aboutsummaryrefslogtreecommitdiffstats
path: root/bytecode/src
diff options
context:
space:
mode:
Diffstat (limited to 'bytecode/src')
-rw-r--r--bytecode/src/bytecode.rs89
-rw-r--r--bytecode/src/data.rs2
2 files changed, 91 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)))
+ ])
+ );
+ }
}
diff --git a/bytecode/src/data.rs b/bytecode/src/data.rs
index d6f9bd2..e14eaa9 100644
--- a/bytecode/src/data.rs
+++ b/bytecode/src/data.rs
@@ -80,6 +80,8 @@ impl Value {
}
return Value(0x2);
}
+
+ pub const NIL: Self = Value(0x12);
}
#[cfg(test)]