diff options
| author | Rose Hogenson <rhogenson@posteo.net> | 2022-07-30 13:30:34 -0700 |
|---|---|---|
| committer | Rose Hogenson <rhogenson@posteo.net> | 2022-07-30 13:30:34 -0700 |
| commit | 0632650d0e4250e08a76982ab2713a34e3531b33 (patch) | |
| tree | 1017fad6236661e2ec4b84ed2f005fa66e0ea554 /bytecode/src/bytecode.rs | |
| parent | 3f79dd1c6a34b7f6746ace3b4a9592ebb83eb15f (diff) | |
| download | chromatopelma-0632650d0e4250e08a76982ab2713a34e3531b33.tar.zst | |
Add the typeof opcode.
Diffstat (limited to 'bytecode/src/bytecode.rs')
| -rw-r--r-- | bytecode/src/bytecode.rs | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/bytecode/src/bytecode.rs b/bytecode/src/bytecode.rs index df07485..6ba23cf 100644 --- a/bytecode/src/bytecode.rs +++ b/bytecode/src/bytecode.rs @@ -64,6 +64,17 @@ pub enum Op { JmpIf(Arg, Arg), // Terminates the interpreter with the given status code. Exit(Arg), + + // Introspection + // ============= + + // Returns the type code for the specified value. Type codes are listed below: + // - pointer: 0 + // - integer: 1 + // - boolean: 2 + // - nil: 3 + // - symbol: 4 + TypeOf(Local, Arg), } struct Interpreter { @@ -218,6 +229,27 @@ impl Interpreter { Ok(()) } + fn type_of(&mut self, dest: Local, arg: Arg) -> Result<(), String> { + let Value(u) = self.read_arg(arg); + let code = match u & 0x7 { + 0 => 0, + 0x1 | 0x3 | 0x5 | 0x7 => 1, + 2 => match u { + 0x2 | 0xa => 2, + 0x12 => 3, + _ => { + return Err(format!("invalid value {u:x}")); + } + }, + 0x4 => 4, + _ => { + return Err(format!("invalid value {u:x}")); + } + }; + self.set_arg(dest, Value::from_int(code)); + Ok(()) + } + fn eval(&mut self, prog: &[Op]) -> Result<u8, String> { let mut ip = 0; loop { @@ -245,6 +277,7 @@ impl Interpreter { let n = self.read_arg(code).to_int()?; return Ok((n & 0xff) as u8); } + Op::TypeOf(dest, arg) => self.type_of(dest, arg)?, } } } @@ -426,4 +459,60 @@ mod tests { ]) ); } + + #[test] + fn eval_type_of_pointer() { + assert_eq!( + Ok(0), + eval(&vec![ + Alloc(Local(0), Const(Value::from_int(1))), + TypeOf(Local(1), L(Local(0))), + Exit(L(Local(1))) + ]) + ); + } + + #[test] + fn eval_type_of_int() { + assert_eq!( + Ok(1), + eval(&vec![ + TypeOf(Local(0), Const(Value::from_int(0))), + Exit(L(Local(0))) + ]) + ); + } + + #[test] + fn eval_type_of_true() { + assert_eq!( + Ok(2), + eval(&vec![ + TypeOf(Local(0), Const(Value::from_bool(true))), + Exit(L(Local(0))) + ]) + ); + } + + #[test] + fn eval_type_of_false() { + assert_eq!( + Ok(2), + eval(&vec![ + TypeOf(Local(0), Const(Value::from_bool(false))), + Exit(L(Local(0))) + ]) + ); + } + + #[test] + fn eval_type_of_nil() { + assert_eq!( + Ok(3), + eval(&vec![ + TypeOf(Local(0), Const(Value::NIL)), + Exit(L(Local(0))) + ]) + ); + } } |
