lunar_wave/src/main.rs

172 lines
3.8 KiB
Rust
Raw Normal View History

enum Instruction {
VarArgPrep (i32),
GetTabUp (u8, u8, u8),
GetI (u8, u8, u8),
EqK (u8, u8, u8),
Jmp (i32),
LoadK (u8, i32),
Call (u8, u8, u8),
Closure (u8, i32),
Return (u8, u8, u8),
}
#[derive (Clone, Debug, PartialEq)]
enum Value {
Nil,
False,
True,
Float (f64),
String (String),
// These are all bogus, I haven't figured out how to implement
// tables and function pointers yet
BogusArg,
BogusPrint,
}
impl Default for Value {
fn default () -> Self {
Self::Nil
}
}
impl From <String> for Value {
fn from (x: String) -> Self {
Self::String (x)
}
}
impl From <&str> for Value {
fn from (x: &str) -> Self {
Self::from (String::from (x))
}
}
struct Chunk {
instructions: Vec <Instruction>,
constants: Vec <Value>,
}
fn main() {
let arg: Vec <_> = std::env::args ().collect ();
let chunk = Chunk {
instructions: vec! [
Instruction::VarArgPrep (0),
Instruction::GetTabUp (0, 0, 0),
Instruction::GetI (0, 0, 1),
Instruction::EqK (0, 1, 0),
Instruction::Jmp (4),
Instruction::GetTabUp (0, 0, 2),
Instruction::LoadK (1, 3),
Instruction::Call (0, 2, 1),
Instruction::Jmp (3),
Instruction::GetTabUp (0, 0, 2),
Instruction::LoadK (1, 4),
Instruction::Call (0, 2, 1),
Instruction::Return (1, 1, 1),
],
constants: vec! [
"arg",
"93",
"print",
"it's 93",
"it's not 93",
].into_iter ().map (|s| Value::from (s)).collect (),
};
let mut registers = vec! [Value::default (); 256];
let mut program_counter = 0i32;
let max_iters = 2000;
for _ in 0..max_iters {
let instruction = chunk.instructions.get (usize::try_from (program_counter).unwrap ()).unwrap ();
let r = &mut registers;
let k = &chunk.constants;
match instruction {
Instruction::Call (a, b, c) => {
// Take arguments from registers [a + 1, a + b)
// Call the function in register [a]
// Return values in registers [a, a + c - 1)
//
// That is, call a with b - 1 arguments and expect c returns
//
// e.g. CALL 0 2 1 mean "Call 0 with 1 argument, return 1 value", like for printing a constant
// TODO: Only implement printing constants for now
let a = usize::try_from (*a).unwrap ();
assert_eq! (*b, 2);
assert_eq! (*c, 1);
println! ("{:?}", r [a + 1]);
},
Instruction::EqK (a, b, c_k) => {
let a = usize::try_from (*a).unwrap ();
let b = usize::try_from (*b).unwrap ();
let equal = r [a] == k [b];
match (equal, c_k) {
(true, 0) => program_counter += 1,
(false, 1) => program_counter += 1,
_ => (),
}
},
Instruction::GetTabUp (a, b, c) => {
let a = usize::try_from (*a).unwrap ();
let b = usize::try_from (*b).unwrap ();
let c = usize::try_from (*c).unwrap ();
// Only supported upvalue is `_ENV`
assert_eq! (b, 0);
let key = k.get (c).unwrap ();
let value = match key {
Value::String (s) => match s.as_str() {
"arg" => Value::BogusArg,
"print" => Value::BogusPrint,
_ => panic! ("key not in _ENV upvalue"),
},
_ => unimplemented!(),
};
r [a] = value;
},
Instruction::GetI (a, b, c) => {
let a = usize::try_from (*a).unwrap ();
let b = usize::try_from (*b).unwrap ();
let c = usize::try_from (*c).unwrap ();
let table = r.get (b).unwrap ();
let value = match table {
Value::BogusArg => arg.get (c).unwrap ().as_str().into (),
_ => unimplemented!(),
};
r [a] = value;
},
Instruction::Jmp (sJ) => program_counter += sJ,
Instruction::LoadK (a, bx) => {
let a = usize::try_from (*a).unwrap ();
let bx = usize::try_from (*bx).unwrap ();
r [a] = k [bx].clone ();
},
Instruction::Return (_a, _b, _c) => {
break;
},
Instruction::VarArgPrep (_) => (),
_ => (),
}
program_counter += 1;
}
}