aboutsummaryrefslogtreecommitdiffstats
path: root/bytecode/src
diff options
context:
space:
mode:
Diffstat (limited to 'bytecode/src')
-rw-r--r--bytecode/src/bytecode.rs26
-rw-r--r--bytecode/src/data.rs7
-rw-r--r--bytecode/src/encoding.rs3
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))