diff options
Diffstat (limited to 'bytecode/src')
| -rw-r--r-- | bytecode/src/bytecode.rs | 26 | ||||
| -rw-r--r-- | bytecode/src/data.rs | 7 | ||||
| -rw-r--r-- | bytecode/src/encoding.rs | 3 |
3 files changed, 33 insertions, 3 deletions
diff --git a/bytecode/src/bytecode.rs b/bytecode/src/bytecode.rs index 8c9324b..73c8f53 100644 --- a/bytecode/src/bytecode.rs +++ b/bytecode/src/bytecode.rs @@ -58,6 +58,8 @@ pub enum Op { Cons(Local, Arg, Arg), // Length of a list. Len(Local, Arg), + // Checks that a list has length 1, and gets its first element. + AssertSingleton(Local, Arg), // Locals // ====== @@ -261,6 +263,29 @@ impl Interpreter { Ok(()) } + fn assert_singleton(&mut self, dest: Local, arg: Arg) -> Result<(), String> { + let a = self.read_arg(arg); + if a == Value::NIL { + return Err(String::from( + "wrong number of arguments passed to continuation (0)", + )); + } + let l = self.read_arg(arg).to_pointer()?; + let typecode = self.heap.peek(l, 0)?; + if typecode != Value::from_int(2) { + return Err(String::from("not a list")); + } + let cdr = self.heap.peek(l, 2)?; + if cdr != Value::NIL { + return Err(String::from( + "wrong number of arguments passed to continuation", + )); + } + let car = self.heap.peek(l, 1)?; + self.set_arg(dest, car); + Ok(()) + } + fn mov(&mut self, dest: Local, src: Arg) { self.set_arg(dest, self.read_arg(src)); } @@ -334,6 +359,7 @@ impl Interpreter { 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::AssertSingleton(dest, l) => self.assert_singleton(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/data.rs b/bytecode/src/data.rs index e14eaa9..4774f2a 100644 --- a/bytecode/src/data.rs +++ b/bytecode/src/data.rs @@ -52,7 +52,10 @@ impl Value { pub fn to_pointer(self) -> Result<Pointer, String> { let Value(stack_representation) = self; if !self.is_pointer() { - return Err(format!("value {:x} is not a pointer", stack_representation)); + return Err(format!( + "value 0x{:x} is not a pointer", + stack_representation + )); } return Ok(Pointer(usize::try_from(stack_representation).unwrap())); } @@ -69,7 +72,7 @@ impl Value { pub fn to_int(self) -> Result<i64, String> { let Value(stack_representation) = self; if !self.is_int() { - return Err(format!("value {:x} is not an int", stack_representation)); + return Err(format!("value 0x{:x} is not an int", stack_representation)); } return Ok(stack_representation as i64 >> 1); } diff --git a/bytecode/src/encoding.rs b/bytecode/src/encoding.rs index 44fff51..a4e159f 100644 --- a/bytecode/src/encoding.rs +++ b/bytecode/src/encoding.rs @@ -119,8 +119,9 @@ fn op_decoding<T: Read>(prog: &mut T) -> Result<Option<Op>, String> { read_arg(prog, arg2_const)?, ), 19 => Op::Len(read_local(prog)?, read_arg(prog, arg1_const)?), + 20 => Op::AssertSingleton(read_local(prog)?, read_arg(prog, arg1_const)?), _ => { - return Err(String::from("invalid opcode")); + return Err(format!("invalid opcode {tag}")); } }; Ok(Some(op)) |
