Compare commits

..

10 Commits

Author SHA1 Message Date
_ 57486f7a65 🐛 bug: fma test passes with a hack
So closures are kinda working, but I'm probably missing some edge cases.
2023-09-29 17:44:54 -05:00
_ 2a0e02aec4 test: closure passing again, fma still not 2023-09-29 17:25:54 -05:00
_ 24d576879b make Debug print easier to read 2023-09-29 17:17:53 -05:00
_ 35e62027e6 🐛 bug 2023-09-29 16:58:40 -05:00
_ e499d27dfc 🚧 wip: improving debugging 2023-09-29 16:55:02 -05:00
_ a460b5a932 ♻️ refactor: hoist breakpoints out of State 2023-09-29 16:32:29 -05:00
_ a9e14d0f47 ♻️ refactor: extract a single step method for State 2023-09-29 16:27:50 -05:00
_ f0d4f25cec implement a couple more opcodes fighting the closure issue 2023-09-29 16:15:00 -05:00
_ 4da634a2aa 🚧 wip: working on closures / upvalues 2023-09-28 01:31:23 -05:00
_ 05b1d6e1f7 loading upvalue metadata 2023-09-28 00:55:16 -05:00
7 changed files with 712 additions and 483 deletions

View File

@ -251,19 +251,25 @@ pub fn parse_block <R: Read> (rdr: &mut R, blocks: &mut Vec <Block>)
} }
let upvalue_count = parse_int (rdr).unwrap () as usize; let upvalue_count = parse_int (rdr).unwrap () as usize;
let mut upvalues = Vec::with_capacity (upvalue_count);
for _ in 0..upvalue_count { for _ in 0..upvalue_count {
// Just ignore these let in_stack = parse_byte (rdr).unwrap () == 1;
let idx = parse_byte (rdr).unwrap ();
let kind = parse_byte (rdr).unwrap ();
for _ in 0..3 { let upvalue = crate::state::Upvalue {
parse_byte (rdr).unwrap (); in_stack,
} idx,
kind,
};
upvalues.push (upvalue);
} }
blocks.push (Block { blocks.push (Block {
constants, constants,
instructions, instructions,
upvalue_count, upvalues,
}); });
// Recursion // Recursion

View File

@ -14,12 +14,24 @@ fn main () {
let mut list_bytecode = false; let mut list_bytecode = false;
let mut pipe_bytecode = false; let mut pipe_bytecode = false;
let mut script = None; let mut script = None;
let mut breakpoints = vec![];
let mut args = std::env::args (); let mut args = std::env::args ();
let exe_name = args.next ().unwrap (); let exe_name = args.next ().unwrap ();
while let Some (arg) = args.next () { while let Some (arg) = args.next () {
match arg.as_str () { match arg.as_str () {
"--break" => {
let s = args.next ().unwrap ();
let (block_idx, program_counter) = s.split_once (":").unwrap ();
let block_idx = str::parse (block_idx).unwrap ();
let program_counter = str::parse (program_counter).unwrap ();
breakpoints.push (state::Breakpoint {
block_idx,
program_counter,
});
},
"--list-bytecode" => list_bytecode = true, "--list-bytecode" => list_bytecode = true,
"--pipe-bytecode" => pipe_bytecode = true, "--pipe-bytecode" => pipe_bytecode = true,
"--script" => script = Some (args.next ().unwrap ()), "--script" => script = Some (args.next ().unwrap ()),
@ -45,17 +57,63 @@ fn main () {
dbg! (&chunk); dbg! (&chunk);
} }
let mut vm = State::default (); let upvalues = State::upvalues_from_args ([exe_name].into_iter ().chain (args));
if std::env::var("LUA_DEBUG").is_ok() {
let mut vm = State::new (&chunk, &upvalues);
if std::env::var("LWVM_DEBUG").is_ok() {
vm.debug_print = true; vm.debug_print = true;
} }
let upvalues = State::upvalues_from_args ([exe_name].into_iter ().chain (args)); let max_iters = 2000;
let mut in_break = false;
let mut last_input = String::new ();
vm.breakpoints.push (state::Breakpoint { for _ in 0..max_iters {
block_idx: 3, if in_break || breakpoints.iter ().any (|bp| vm.at_breakpoint (bp)) {
program_counter: 0, in_break = true;
}); dbg! (&vm.stack);
let mut input = Default::default ();
std::io::stdin ().read_line (&mut input).unwrap ();
let input = if input == "" {
&last_input
}
else {
last_input = input;
&last_input
};
match input.as_str ().trim_end () {
"c" => in_break = false,
"q" => return,
"registers" => {
dbg! (&vm.registers);
continue;
}
"s" => {
match vm.step () {
None => (),
Some (state::StepOutput::ChunkReturned (x)) => {
dbg! (x);
return;
},
}
continue;
},
x => { dbg! (x); },
}
}
match vm.step () {
None => (),
Some (state::StepOutput::ChunkReturned (x)) => {
dbg! (x);
return;
},
}
}
vm.execute_chunk (&chunk, &upvalues); dbg! (vm);
panic! ("Hit max iterations before block returned");
} }

File diff suppressed because it is too large Load Diff

View File

@ -23,9 +23,9 @@ fn calculate_hash<T: Hash>(t: &T) -> u64 {
/// and returns the output /// and returns the output
fn run_chunk (args: &[&str], chunk: &Chunk) -> Vec <Value> { fn run_chunk (args: &[&str], chunk: &Chunk) -> Vec <Value> {
let mut vm = State::default ();
let upvalues = State::upvalues_from_args (args.into_iter ().map (|s| s.to_string ())); let upvalues = State::upvalues_from_args (args.into_iter ().map (|s| s.to_string ()));
vm.execute_chunk (chunk, &upvalues) let mut vm = State::new (chunk, &upvalues);
vm.execute_chunk (&[])
} }
/// Takes arguments and Lua bytecode, loads it, runs it, /// Takes arguments and Lua bytecode, loads it, runs it,
@ -93,7 +93,7 @@ fn bools () {
"arg".into (), "arg".into (),
"print".into (), "print".into (),
], ],
upvalue_count: 1, upvalues: vec! [],
}, },
Block { Block {
instructions: vec! [ instructions: vec! [
@ -107,7 +107,7 @@ fn bools () {
Inst::Return0, Inst::Return0,
], ],
constants: vec! [], constants: vec! [],
upvalue_count: 0, upvalues: vec! [],
}, },
], ],
}; };
@ -118,10 +118,9 @@ fn bools () {
] { ] {
let expected: Vec <Value> = expected; let expected: Vec <Value> = expected;
let mut vm = State::default ();
let upvalues = State::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ())); let upvalues = State::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ()));
let mut vm = State::new (&chunk, &upvalues);
let actual = vm.execute_chunk (&chunk, &upvalues); let actual = vm.execute_chunk (&[]);
assert_eq! (actual, expected); assert_eq! (actual, expected);
} }
} }
@ -164,7 +163,7 @@ fn floats () {
0.5.into (), 0.5.into (),
"print".into (), "print".into (),
], ],
upvalue_count: 1, upvalues: vec! [],
}; };
let chunk = Chunk { let chunk = Chunk {
blocks: vec! [block], blocks: vec! [block],
@ -175,9 +174,9 @@ fn floats () {
(vec! ["_exe_name", " "], vec! [3.5.into ()]), (vec! ["_exe_name", " "], vec! [3.5.into ()]),
] { ] {
let expected: Vec <Value> = expected; let expected: Vec <Value> = expected;
let mut vm = State::default ();
let upvalues = State::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ())); let upvalues = State::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ()));
let actual = vm.execute_chunk (&chunk, &upvalues); let mut vm = State::new (&chunk, &upvalues);
let actual = vm.execute_chunk (&[]);
assert_eq! (actual, expected); assert_eq! (actual, expected);
} }
@ -185,19 +184,21 @@ fn floats () {
#[test] #[test]
fn fma () { fn fma () {
let bytecode = include_bytes! ("../test_vectors/fma.luac"); let source = include_bytes! ("../test_vectors/fma.lua");
let mut rdr = std::io::Cursor::new (bytecode); let bytecode = &crate::loader::compile_bytecode_from_stdin (source.to_vec ());
let file = crate::loader::parse_chunk (&mut rdr).unwrap (); let chunk = crate::loader::parse_chunk_from_bytes (bytecode).unwrap ();
assert_eq! (file.blocks.len (), 4); assert_eq! (chunk.blocks.len (), 5);
assert_eq! (chunk.blocks [3].upvalues.len (), 2);
for (arg, expected) in [ for (arg, expected) in [
(vec! ["_exe_name"], vec! [122.into ()]), (vec! ["_exe_name"], vec! [122.into ()]),
(vec! ["_exe_name"], vec! [122.into ()]), (vec! ["_exe_name"], vec! [122.into ()]),
] { ] {
let expected: Vec <Value> = expected; let expected: Vec <Value> = expected;
let mut vm = State::default ();
let upvalues = State::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ())); let upvalues = State::upvalues_from_args (arg.into_iter ().map (|s| s.to_string ()));
let actual = vm.execute_chunk (&file, &upvalues); let mut vm = State::new (&chunk, &upvalues);
let actual = vm.execute_chunk (&[]);
assert_eq! (actual, expected); assert_eq! (actual, expected);
} }

View File

@ -11,11 +11,12 @@ use std::{
#[derive (Debug, Eq, PartialEq)] #[derive (Debug, Eq, PartialEq)]
pub struct BogusClosure { pub struct BogusClosure {
// I'm pretty sure this should be absolute?
pub idx: usize, pub idx: usize,
pub upvalues: Vec <Value>, pub upvalues: Vec <Value>,
} }
#[derive (Clone, Debug, PartialEq)] #[derive (Clone, PartialEq)]
pub enum Value { pub enum Value {
Nil, Nil,
Boolean (bool), Boolean (bool),
@ -32,7 +33,24 @@ pub enum Value {
// These are all bogus, I haven't figured out how to implement // These are all bogus, I haven't figured out how to implement
// closures yet // closures yet
BogusClosure (Rc <BogusClosure>), BogusClosure (Rc <RefCell <BogusClosure>>),
}
impl fmt::Debug for Value {
fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Value::Nil => write! (f, "nil"),
Value::Boolean (false) => write! (f, "false"),
Value::Boolean (true) => write! (f, "true"),
Value::Float (x) => write! (f, "{:?}", x),
Value::Integer (x) => write! (f, "{}", x),
Value::RsFunc (x) => write! (f, "function: {:?}", x),
Value::String (s) => write! (f, "\"{}\"", s),
Value::Table (t) => write! (f, "{:?}", t.borrow ()),
Value::BogusClosure (x) => write! (f, "{:?}", x.borrow ()),
}
}
} }
impl Default for Value { impl Default for Value {
@ -53,11 +71,17 @@ impl fmt::Display for Value {
Value::String (s) => write! (f, "{}", s), Value::String (s) => write! (f, "{}", s),
Value::Table (t) => write! (f, "table: {:?}", std::rc::Rc::as_ptr (t)), Value::Table (t) => write! (f, "table: {:?}", std::rc::Rc::as_ptr (t)),
Value::BogusClosure (_) => write! (f, "BogusClosure"), Value::BogusClosure (x) => write! (f, "BogusClosure: {:?}", std::rc::Rc::as_ptr (x)),
} }
} }
} }
impl From <BogusClosure> for Value {
fn from (x: BogusClosure) -> Self {
Self::BogusClosure (Rc::new (RefCell::new (x)))
}
}
impl From <bool> for Value { impl From <bool> for Value {
fn from (x: bool) -> Self { fn from (x: bool) -> Self {
Self::Boolean (x) Self::Boolean (x)
@ -156,6 +180,13 @@ impl PartialEq <i64> for Value {
} }
impl Value { impl Value {
pub fn as_closure (&self) -> Option <&Rc <RefCell <BogusClosure>>> {
match self {
Self::BogusClosure (x) => Some (x),
_ => None,
}
}
/// Coerces ints to float /// Coerces ints to float
pub fn as_float (&self) -> Option <f64> { pub fn as_float (&self) -> Option <f64> {
@ -200,12 +231,20 @@ impl Value {
} }
} }
#[derive (Debug, Default, Eq, PartialEq)] #[derive (Default, Eq, PartialEq)]
pub struct Table { pub struct Table {
array: Vec <Value>, array: Vec <Value>,
hash: HashMap <Value, Value>, hash: HashMap <Value, Value>,
} }
impl fmt::Debug for Table {
fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result {
write! (f, "Table {:#?}", self.hash)?;
Ok (())
}
}
impl Table { impl Table {
fn get_inner (&self, key: &Value) -> Value { fn get_inner (&self, key: &Value) -> Value {
self.hash.get (key).cloned ().unwrap_or_default () self.hash.get (key).cloned ().unwrap_or_default ()

View File

@ -1,11 +1,11 @@
local function make_closure (x) local function make_closure (t)
print (x)
return function (y) return function (y)
return x + y return t.x + y
end end
end end
local f = make_closure (11) local f = make_closure ({ x = 11 })
local t = {}
local x = f (12) local x = f (12)
print (x) print (x)
return x return x

View File

@ -1,5 +1,7 @@
-- This one fails :( I haven't implemented closures properly yet. -- This one fails :( I haven't implemented closures properly yet.
local ii = "bogus"
local function add (aa, bb) local function add (aa, bb)
return aa + bb return aa + bb
end end
@ -12,6 +14,13 @@ local function fma (ee, ff, gg)
return add (mul (ee, ff), gg) return add (mul (ee, ff), gg)
end end
local hh = fma (10, 11, 12) local function run ()
print (hh) local hh = fma (10, 11, 12)
print (hh)
return hh
end
local hh = run ()
print (ii)
return hh return hh