From dc8a480c65fabf35b99398120aeccca8f2874c6d Mon Sep 17 00:00:00 2001 From: Rose Hogenson Date: Mon, 22 Aug 2022 20:07:06 -0700 Subject: Add a few primitive list operations. --- bytecode/src/bytecode.rs | 36 ++++++++++++++++++++++++++++++++++++ bytecode/src/encoding.rs | 6 ++++++ lib/csc/encoding.csc | 18 ++++++++++++++---- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/bytecode/src/bytecode.rs b/bytecode/src/bytecode.rs index 41302ad..8c9324b 100644 --- a/bytecode/src/bytecode.rs +++ b/bytecode/src/bytecode.rs @@ -51,6 +51,14 @@ pub enum Op { // Stores a byte at the specified address plus the given offset. PokeByte(Arg, Arg, Arg), + // Lists + // ===== + + // Special case of Alloc for allocating a pair. + Cons(Local, Arg, Arg), + // Length of a list. + Len(Local, Arg), + // Locals // ====== @@ -227,6 +235,32 @@ impl Interpreter { Ok(()) } + fn cons(&mut self, dest: Local, car: Arg, cdr: Arg) -> Result<(), String> { + let p = self.heap.alloc(3, &mut self.locals)?; + self.heap.poke(Value::from_int(2), p, 0)?; + self.heap.poke(self.read_arg(car), p, 1)?; + self.heap.poke(self.read_arg(cdr), p, 2)?; + self.set_arg(dest, Value::from_pointer(p)); + Ok(()) + } + + fn len(&mut self, dest: Local, arg: Arg) -> Result<(), String> { + let mut len = 0; + let mut l = self.read_arg(arg); + while l != Value::NIL { + let p = l.to_pointer()?; + let typecode = self.heap.peek(p, 0)?; + if typecode != Value::from_int(2) { + return Err(String::from("not a list")); + } + + len += 1; + l = self.heap.peek(p, 2)?; + } + self.set_arg(dest, Value::from_int(len)); + Ok(()) + } + fn mov(&mut self, dest: Local, src: Arg) { self.set_arg(dest, self.read_arg(src)); } @@ -298,6 +332,8 @@ impl Interpreter { Op::Poke(word, ptr, offset) => self.poke(word, ptr, offset)?, Op::PeekByte(dest, ptr, offset) => self.peek_byte(dest, ptr, offset)?, Op::PokeByte(word, ptr, offset) => self.poke_byte(word, ptr, offset)?, + Op::Cons(dest, x, y) => self.cons(dest, x, y)?, + Op::Len(dest, l) => self.len(dest, l)?, Op::Mov(dest, src) => self.mov(dest, src), Op::Jmp(addr) => self.jmp(&mut ip, addr)?, Op::JmpIf(cond, addr) => self.jmp_if(&mut ip, cond, addr)?, diff --git a/bytecode/src/encoding.rs b/bytecode/src/encoding.rs index 8fccc1a..44fff51 100644 --- a/bytecode/src/encoding.rs +++ b/bytecode/src/encoding.rs @@ -113,6 +113,12 @@ fn op_decoding(prog: &mut T) -> Result, String> { read_arg(prog, arg1_const)?, read_arg(prog, arg2_const)?, ), + 18 => Op::Cons( + read_local(prog)?, + read_arg(prog, arg1_const)?, + read_arg(prog, arg2_const)?, + ), + 19 => Op::Len(read_local(prog)?, read_arg(prog, arg1_const)?), _ => { return Err(String::from("invalid opcode")); } diff --git a/lib/csc/encoding.csc b/lib/csc/encoding.csc index aceedc8..099beaf 100644 --- a/lib/csc/encoding.csc +++ b/lib/csc/encoding.csc @@ -1,6 +1,7 @@ (define-library (csc encoding) (export encode) (import (scheme base) + (csc format) (only (csc loop) loop return) @@ -10,10 +11,10 @@ ; The format of unboxed constants is described in bytecocde/src/data.rs. ; Boxed values are represented by a pointer to an array on the heap. The ; first position in the array is an integer code indicating what type the - ; object is. Vectors have code 0, codes for other types are not stable. - ; Vectors are represented as an array, the first element of which is the - ; integer 0 (the type code), the second element is the vector length, and - ; the remaining slots hold the array values. + ; object is. Vectors have code 0, pairs have code 2, and codes for other + ; types are not stable. Vectors are represented as an array, the first + ; element of which is the integer 0 (the type code), the second element is + ; the vector length, and the remaining slots hold the array values. (define (low-byte w n) @@ -185,6 +186,15 @@ (arg->le-bytes w dest) (arg->le-bytes w x) (arg->le-bytes w y)) + (('cons dest x y) + (make-opcode w 18 (is-const? x) (is-const? y)) + (arg->le-bytes w dest) + (arg->le-bytes w x) + (arg->le-bytes w y)) + (('len dest l) + (make-opcode w 19 (is-const? l) #f) + (arg->le-bytes w dest) + (arg->le-bytes w l)) (_ (error "invalid opcode" opcode)))) -- cgit v1.3.1