Skip to content

Commit 47248a5

Browse files
committed
bytecode.rs: added CAR/CDR opcode constants and constructors
vm.rs: added VM handlers for Car/Cdr with optimized unsafe access compiler.rs: detect car/cdr calls and emit specialized opcodes
1 parent af1032d commit 47248a5

File tree

3 files changed

+82
-0
lines changed

3 files changed

+82
-0
lines changed

src/bytecode.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ impl std::fmt::Debug for Op {
5454
Self::NEW_LIST => write!(f, "NewList({}, {})", self.a(), self.b()),
5555
Self::GET_LIST => write!(f, "GetList({}, {}, {})", self.a(), self.b(), self.c()),
5656
Self::SET_LIST => write!(f, "SetList({}, {}, {})", self.a(), self.b(), self.c()),
57+
Self::CAR => write!(f, "Car({}, {})", self.a(), self.b()),
58+
Self::CDR => write!(f, "Cdr({}, {})", self.a(), self.b()),
5759
_ => write!(f, "Unknown(0x{:08x})", self.0),
5860
}
5961
}
@@ -95,6 +97,8 @@ impl Op {
9597
pub const NEW_LIST: u8 = 31; // AB: dest, nargs
9698
pub const GET_LIST: u8 = 32; // ABC: dest, list, index
9799
pub const SET_LIST: u8 = 33; // ABC: list, index, value
100+
pub const CAR: u8 = 34; // AB: dest, src - get head of cons/list
101+
pub const CDR: u8 = 35; // AB: dest, src - get tail of cons/list
98102

99103
// ========== Constructors ==========
100104

@@ -328,6 +332,16 @@ impl Op {
328332
Self::abc(Self::SET_LIST, list, index, value)
329333
}
330334

335+
#[inline(always)]
336+
pub const fn car(dest: Reg, src: Reg) -> Self {
337+
Self::abc(Self::CAR, dest, src, 0)
338+
}
339+
340+
#[inline(always)]
341+
pub const fn cdr(dest: Reg, src: Reg) -> Self {
342+
Self::abc(Self::CDR, dest, src, 0)
343+
}
344+
331345
// ========== Jump patching helpers ==========
332346

333347
/// Check if this is a jump instruction (for patching)

src/compiler.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,26 @@ impl Compiler {
800800
return Ok(());
801801
}
802802
}
803+
804+
// Try specialized car/cdr opcodes (single argument)
805+
let args = &items[1..];
806+
if args.len() == 1 {
807+
match op {
808+
"car" => {
809+
// Compile arg into dest, then emit Car
810+
self.compile_expr(&args[0], dest, false)?;
811+
self.emit(Op::car(dest, dest));
812+
return Ok(());
813+
}
814+
"cdr" => {
815+
// Compile arg into dest, then emit Cdr
816+
self.compile_expr(&args[0], dest, false)?;
817+
self.emit(Op::cdr(dest, dest));
818+
return Ok(());
819+
}
820+
_ => {}
821+
}
822+
}
803823
}
804824

805825
// Check if calling a global symbol (optimization: use CallGlobal/TailCallGlobal)

src/vm.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,41 @@ impl VM {
680680
return Err("SetList not implemented (immutable lists)".to_string());
681681
}
682682

683+
Op::CAR => {
684+
let dest = instr.a();
685+
let src = instr.b();
686+
let v = unsafe { self.registers.get_unchecked(base + src as usize) };
687+
// Fast path: cons cell (most common in list processing)
688+
let result = if let Some(cons) = v.as_cons() {
689+
cons.car.clone()
690+
} else if let Some(list) = v.as_list() {
691+
// Array list
692+
list.first().cloned().ok_or_else(|| "car on empty list".to_string())?
693+
} else {
694+
return Err("car expects a list or cons cell".to_string());
695+
};
696+
unsafe { *self.registers.get_unchecked_mut(base + dest as usize) = result };
697+
}
698+
699+
Op::CDR => {
700+
let dest = instr.a();
701+
let src = instr.b();
702+
let v = unsafe { self.registers.get_unchecked(base + src as usize) };
703+
// Fast path: cons cell (most common in list processing)
704+
let result = if let Some(cons) = v.as_cons() {
705+
cons.cdr.clone()
706+
} else if let Some(list) = v.as_list() {
707+
// Array list - O(n) but rare with cons cells
708+
if list.is_empty() {
709+
return Err("cdr on empty list".to_string());
710+
}
711+
Value::list(list[1..].to_vec())
712+
} else {
713+
return Err("cdr expects a list or cons cell".to_string());
714+
};
715+
unsafe { *self.registers.get_unchecked_mut(base + dest as usize) = result };
716+
}
717+
683718
_ => {
684719
return Err(format!("Unknown opcode: {}", instr.opcode()));
685720
}
@@ -1215,4 +1250,17 @@ mod tests {
12151250
let result = vm_eval("(do (def sum (fn (n acc) (if (<= n 0) acc (sum (- n 1) (+ acc n))))) (sum 10000 0))").unwrap();
12161251
assert_eq!(result, Value::Int(50005000));
12171252
}
1253+
1254+
#[test]
1255+
fn test_specialized_car_cdr() {
1256+
// Test specialized car/cdr opcodes with cons cells
1257+
assert_eq!(vm_eval("(car (cons 1 (cons 2 nil)))").unwrap(), Value::Int(1));
1258+
assert_eq!(vm_eval("(car (cdr (cons 1 (cons 2 nil))))").unwrap(), Value::Int(2));
1259+
1260+
// Test with nested list operations
1261+
let result = vm_eval("(do (def reverse-acc (fn (lst acc) (if (empty? lst) acc (reverse-acc (cdr lst) (cons (car lst) acc))))) (reverse-acc (cons 1 (cons 2 (cons 3 nil))) nil))").unwrap();
1262+
// reversed (1 2 3) -> (3 2 1)
1263+
let cons = result.as_cons().expect("expected cons cell");
1264+
assert_eq!(cons.car.as_int(), Some(3));
1265+
}
12181266
}

0 commit comments

Comments
 (0)