✅ another test
parent
eb5a1947a1
commit
8a2807f879
|
@ -1,2 +1,3 @@
|
||||||
|
/luac.out
|
||||||
/target
|
/target
|
||||||
/untracked
|
/untracked
|
||||||
|
|
187
src/main.rs
187
src/main.rs
|
@ -1,7 +1,14 @@
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
#[derive (Debug)]
|
||||||
enum Instruction {
|
enum Instruction {
|
||||||
VarArgPrep (i32),
|
Add (u8, u8, u8),
|
||||||
|
|
||||||
|
Call (u8, u8, u8),
|
||||||
|
Closure (u8, i32),
|
||||||
|
|
||||||
|
// Equals Constant?
|
||||||
|
EqK (u8, u8, u8),
|
||||||
|
|
||||||
// Get Table, Upvalue
|
// Get Table, Upvalue
|
||||||
GetTabUp (u8, u8, u8),
|
GetTabUp (u8, u8, u8),
|
||||||
|
@ -9,9 +16,6 @@ enum Instruction {
|
||||||
// Get Immediate?
|
// Get Immediate?
|
||||||
GetI (u8, u8, u8),
|
GetI (u8, u8, u8),
|
||||||
|
|
||||||
// Equals Constant?
|
|
||||||
EqK (u8, u8, u8),
|
|
||||||
|
|
||||||
// Jump
|
// Jump
|
||||||
Jmp (i32),
|
Jmp (i32),
|
||||||
|
|
||||||
|
@ -21,12 +25,15 @@ enum Instruction {
|
||||||
// Load Constant
|
// Load Constant
|
||||||
LoadK (u8, i32),
|
LoadK (u8, i32),
|
||||||
|
|
||||||
|
// MetaMethod, Binary
|
||||||
|
MmBin (u8, u8, u8),
|
||||||
|
|
||||||
Call (u8, u8, u8),
|
Move (u8, u8),
|
||||||
Closure (u8, i32),
|
|
||||||
|
|
||||||
// (A, B, _C) Return B - 1 registers starting with A
|
// (A, B, _C) Return B - 1 registers starting with A
|
||||||
Return (u8, u8, u8),
|
Return (u8, u8, u8),
|
||||||
|
|
||||||
|
VarArgPrep (i32),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive (Clone, Debug, PartialEq)]
|
#[derive (Clone, Debug, PartialEq)]
|
||||||
|
@ -35,7 +42,6 @@ enum Value {
|
||||||
False,
|
False,
|
||||||
True,
|
True,
|
||||||
Float (f64),
|
Float (f64),
|
||||||
Integer (i64),
|
|
||||||
String (String),
|
String (String),
|
||||||
|
|
||||||
// These are all bogus, I haven't figured out how to implement
|
// These are all bogus, I haven't figured out how to implement
|
||||||
|
@ -66,7 +72,22 @@ impl From <&str> for Value {
|
||||||
|
|
||||||
impl From <i32> for Value {
|
impl From <i32> for Value {
|
||||||
fn from (x: i32) -> Self {
|
fn from (x: i32) -> Self {
|
||||||
Self::Integer (x as i64)
|
Self::Float (f64::try_from (x).unwrap ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From <f64> for Value {
|
||||||
|
fn from (x: f64) -> Self {
|
||||||
|
Self::Float (x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
fn as_float (&self) -> Option <f64> {
|
||||||
|
match self {
|
||||||
|
Self::Float (x) => Some (*x),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +113,20 @@ impl Default for VirtualMachine {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VirtualMachine {
|
impl VirtualMachine {
|
||||||
|
fn upvalues_from_args <I: Iterator <Item = String>> (args: I) -> Vec <Value>
|
||||||
|
{
|
||||||
|
let arg = args.map (|s| s.to_string ()).collect ();
|
||||||
|
|
||||||
|
let env = BTreeMap::from_iter ([
|
||||||
|
("arg", Value::BogusArg (arg)),
|
||||||
|
("print", Value::BogusPrint),
|
||||||
|
].map (|(k, v)| (k.to_string (), v)).into_iter ());
|
||||||
|
|
||||||
|
vec! [
|
||||||
|
Value::BogusEnv (env),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
fn execute_chunk (&mut self, chunk: &Chunk, upvalues: &Vec <Value>)
|
fn execute_chunk (&mut self, chunk: &Chunk, upvalues: &Vec <Value>)
|
||||||
-> Vec <Value> {
|
-> Vec <Value> {
|
||||||
let max_iters = 2000;
|
let max_iters = 2000;
|
||||||
|
@ -103,6 +138,16 @@ impl VirtualMachine {
|
||||||
let k = &chunk.constants;
|
let k = &chunk.constants;
|
||||||
|
|
||||||
match instruction {
|
match instruction {
|
||||||
|
Instruction::Add (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 v_b = r [b].as_float ().unwrap ();
|
||||||
|
let v_c = r [c].as_float ().unwrap ();
|
||||||
|
|
||||||
|
r [a] = (v_b + v_c).into ();
|
||||||
|
},
|
||||||
Instruction::Call (a, b, c) => {
|
Instruction::Call (a, b, c) => {
|
||||||
// Take arguments from registers [a + 1, a + b)
|
// Take arguments from registers [a + 1, a + b)
|
||||||
// Call the function in register [a]
|
// Call the function in register [a]
|
||||||
|
@ -112,14 +157,15 @@ impl VirtualMachine {
|
||||||
//
|
//
|
||||||
// e.g. CALL 0 2 1 mean "Call 0 with 1 argument, return 1 value", like for printing a constant
|
// 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
|
// TODO: Only implement printing values for now
|
||||||
|
|
||||||
let a = usize::try_from (*a).unwrap ();
|
let a = usize::try_from (*a).unwrap ();
|
||||||
|
|
||||||
|
assert_eq! (r.get (a).unwrap (), &Value::BogusPrint);
|
||||||
assert_eq! (*b, 2);
|
assert_eq! (*b, 2);
|
||||||
assert_eq! (*c, 1);
|
assert_eq! (*c, 1);
|
||||||
|
|
||||||
println! ("{:?}", r [a + 1]);
|
println! ("{:?}", r.get (a + 1).unwrap ());
|
||||||
},
|
},
|
||||||
Instruction::EqK (a, b, c_k) => {
|
Instruction::EqK (a, b, c_k) => {
|
||||||
let a = usize::try_from (*a).unwrap ();
|
let a = usize::try_from (*a).unwrap ();
|
||||||
|
@ -178,6 +224,26 @@ impl VirtualMachine {
|
||||||
|
|
||||||
r [a] = k [bx].clone ();
|
r [a] = k [bx].clone ();
|
||||||
},
|
},
|
||||||
|
Instruction::MmBin (a, b, c) => {
|
||||||
|
let a = usize::try_from (*a).unwrap ();
|
||||||
|
let b = usize::try_from (*b).unwrap ();
|
||||||
|
|
||||||
|
let a = &r [a];
|
||||||
|
let b = &r [b];
|
||||||
|
|
||||||
|
if a.as_float().is_some() && b.as_float().is_some () {
|
||||||
|
// No need for metamethods
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
panic! ("Not sure how to implememtn OP_MMBIN for these 2 values {a:?}, {b:?}");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Instruction::Move (a, b) => {
|
||||||
|
let a = usize::try_from (*a).unwrap ();
|
||||||
|
let b = usize::try_from (*b).unwrap ();
|
||||||
|
|
||||||
|
r [a] = r [b].clone ();
|
||||||
|
},
|
||||||
Instruction::Return (a, b, _c) => {
|
Instruction::Return (a, b, _c) => {
|
||||||
let a = usize::try_from (*a).unwrap ();
|
let a = usize::try_from (*a).unwrap ();
|
||||||
let b = usize::try_from (*b).unwrap ();
|
let b = usize::try_from (*b).unwrap ();
|
||||||
|
@ -185,7 +251,7 @@ impl VirtualMachine {
|
||||||
return self.registers [a..(a + b - 1)].to_vec();
|
return self.registers [a..(a + b - 1)].to_vec();
|
||||||
},
|
},
|
||||||
Instruction::VarArgPrep (_) => (),
|
Instruction::VarArgPrep (_) => (),
|
||||||
_ => (),
|
x => panic! ("Unimplemented instruction {x:?}"),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.program_counter += 1;
|
self.program_counter += 1;
|
||||||
|
@ -196,45 +262,26 @@ impl VirtualMachine {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let arg: Vec <_> = std::env::args ().collect ();
|
|
||||||
|
|
||||||
let chunk = Chunk {
|
let chunk = Chunk {
|
||||||
instructions: vec! [
|
instructions: vec! [
|
||||||
Instruction::VarArgPrep (0),
|
Instruction::VarArgPrep (0),
|
||||||
Instruction::GetTabUp (1, 0, 0),
|
Instruction::LoadK (0, 0),
|
||||||
Instruction::GetI (1, 1, 1),
|
Instruction::LoadI (1, 3),
|
||||||
Instruction::EqK (1, 1, 0),
|
Instruction::Add (2, 0, 1),
|
||||||
Instruction::Jmp (6),
|
Instruction::MmBin (0, 1, 6),
|
||||||
Instruction::GetTabUp (1, 0, 2),
|
Instruction::GetTabUp (3, 0, 1),
|
||||||
Instruction::LoadK (2, 3),
|
Instruction::Move (4, 2),
|
||||||
Instruction::Call (1, 2, 1),
|
Instruction::Call (3, 2, 1),
|
||||||
Instruction::LoadI (1, 0),
|
Instruction::Return (2, 2, 1),
|
||||||
Instruction::Return (1, 2, 1),
|
Instruction::Return (3, 1, 1),
|
||||||
Instruction::Jmp (5),
|
|
||||||
Instruction::GetTabUp (1, 0, 2),
|
|
||||||
Instruction::LoadK (2, 4),
|
|
||||||
Instruction::Call (1, 2, 1),
|
|
||||||
Instruction::LoadI (1, 1),
|
|
||||||
Instruction::Return (1, 2, 1),
|
|
||||||
Instruction::Return (1, 1, 1),
|
|
||||||
],
|
],
|
||||||
constants: vec! [
|
constants: vec! [
|
||||||
"arg",
|
0.5.into (),
|
||||||
"93",
|
"print".into (),
|
||||||
"print",
|
],
|
||||||
"it's 93",
|
|
||||||
"it's not 93",
|
|
||||||
].into_iter ().map (|s| Value::from (s)).collect (),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let env = BTreeMap::from_iter ([
|
let upvalues = VirtualMachine::upvalues_from_args (std::env::args ());
|
||||||
("arg", Value::BogusArg (arg.clone ())),
|
|
||||||
("print", Value::BogusPrint),
|
|
||||||
].map (|(k, v)| (k.to_string (), v)).into_iter ());
|
|
||||||
|
|
||||||
let upvalues = vec! [
|
|
||||||
Value::BogusEnv (env),
|
|
||||||
];
|
|
||||||
|
|
||||||
let mut vm = VirtualMachine::default ();
|
let mut vm = VirtualMachine::default ();
|
||||||
println! ("Returned: {:?}", vm.execute_chunk (&chunk, &upvalues));
|
println! ("Returned: {:?}", vm.execute_chunk (&chunk, &upvalues));
|
||||||
|
@ -244,6 +291,48 @@ fn main() {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn floats () {
|
||||||
|
/*
|
||||||
|
local a = 0.5
|
||||||
|
local b = 3
|
||||||
|
|
||||||
|
local x = a + b
|
||||||
|
|
||||||
|
print (x)
|
||||||
|
return x
|
||||||
|
*/
|
||||||
|
|
||||||
|
let chunk = Chunk {
|
||||||
|
instructions: vec! [
|
||||||
|
Instruction::VarArgPrep (0),
|
||||||
|
Instruction::LoadK (0, 0),
|
||||||
|
Instruction::LoadI (1, 3),
|
||||||
|
Instruction::Add (2, 0, 1),
|
||||||
|
Instruction::MmBin (0, 1, 6),
|
||||||
|
Instruction::GetTabUp (3, 0, 1),
|
||||||
|
Instruction::Move (4, 2),
|
||||||
|
Instruction::Call (3, 2, 1),
|
||||||
|
Instruction::Return (2, 2, 1),
|
||||||
|
Instruction::Return (3, 1, 1),
|
||||||
|
],
|
||||||
|
constants: vec! [
|
||||||
|
0.5.into (),
|
||||||
|
"print".into (),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
for (arg, expected) in [
|
||||||
|
(vec! ["_exe_name"], vec! [3.5.into ()]),
|
||||||
|
] {
|
||||||
|
let mut vm = VirtualMachine::default ();
|
||||||
|
let upvalues = VirtualMachine::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ()));
|
||||||
|
let actual = vm.execute_chunk (&chunk, &upvalues);
|
||||||
|
|
||||||
|
assert_eq! (actual, expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn is_93 () {
|
fn is_93 () {
|
||||||
/*
|
/*
|
||||||
|
@ -290,18 +379,8 @@ mod tests {
|
||||||
(vec! ["_exe_name", "93"], vec! [0.into ()]),
|
(vec! ["_exe_name", "93"], vec! [0.into ()]),
|
||||||
(vec! ["_exe_name", "94"], vec! [1.into ()]),
|
(vec! ["_exe_name", "94"], vec! [1.into ()]),
|
||||||
] {
|
] {
|
||||||
let arg = arg.into_iter ().map (|s| s.to_string ()).collect ();
|
|
||||||
|
|
||||||
let env = BTreeMap::from_iter ([
|
|
||||||
("arg", Value::BogusArg (arg)),
|
|
||||||
("print", Value::BogusPrint),
|
|
||||||
].map (|(k, v)| (k.to_string (), v)).into_iter ());
|
|
||||||
|
|
||||||
let upvalues = vec! [
|
|
||||||
Value::BogusEnv (env),
|
|
||||||
];
|
|
||||||
|
|
||||||
let mut vm = VirtualMachine::default ();
|
let mut vm = VirtualMachine::default ();
|
||||||
|
let upvalues = VirtualMachine::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ()));
|
||||||
let actual = vm.execute_chunk (&chunk, &upvalues);
|
let actual = vm.execute_chunk (&chunk, &upvalues);
|
||||||
|
|
||||||
assert_eq! (actual, expected);
|
assert_eq! (actual, expected);
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
local a = 0.5
|
||||||
|
local b = 3
|
||||||
|
|
||||||
|
local x = a + b
|
||||||
|
|
||||||
|
print (x)
|
||||||
|
return x
|
Loading…
Reference in New Issue