Compare commits
10 Commits
b639d02027
...
57486f7a65
Author | SHA1 | Date |
---|---|---|
_ | 57486f7a65 | |
_ | 2a0e02aec4 | |
_ | 24d576879b | |
_ | 35e62027e6 | |
_ | e499d27dfc | |
_ | a460b5a932 | |
_ | a9e14d0f47 | |
_ | f0d4f25cec | |
_ | 4da634a2aa | |
_ | 05b1d6e1f7 |
|
@ -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 mut upvalues = Vec::with_capacity (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 {
|
||||
parse_byte (rdr).unwrap ();
|
||||
}
|
||||
let upvalue = crate::state::Upvalue {
|
||||
in_stack,
|
||||
idx,
|
||||
kind,
|
||||
};
|
||||
|
||||
upvalues.push (upvalue);
|
||||
}
|
||||
|
||||
blocks.push (Block {
|
||||
constants,
|
||||
instructions,
|
||||
upvalue_count,
|
||||
upvalues,
|
||||
});
|
||||
|
||||
// Recursion
|
||||
|
|
74
src/main.rs
74
src/main.rs
|
@ -14,12 +14,24 @@ fn main () {
|
|||
let mut list_bytecode = false;
|
||||
let mut pipe_bytecode = false;
|
||||
let mut script = None;
|
||||
let mut breakpoints = vec![];
|
||||
|
||||
let mut args = std::env::args ();
|
||||
let exe_name = args.next ().unwrap ();
|
||||
|
||||
while let Some (arg) = args.next () {
|
||||
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,
|
||||
"--pipe-bytecode" => pipe_bytecode = true,
|
||||
"--script" => script = Some (args.next ().unwrap ()),
|
||||
|
@ -45,17 +57,63 @@ fn main () {
|
|||
dbg! (&chunk);
|
||||
}
|
||||
|
||||
let mut vm = State::default ();
|
||||
if std::env::var("LUA_DEBUG").is_ok() {
|
||||
let upvalues = State::upvalues_from_args ([exe_name].into_iter ().chain (args));
|
||||
|
||||
let mut vm = State::new (&chunk, &upvalues);
|
||||
if std::env::var("LWVM_DEBUG").is_ok() {
|
||||
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 {
|
||||
block_idx: 3,
|
||||
program_counter: 0,
|
||||
});
|
||||
for _ in 0..max_iters {
|
||||
if in_break || breakpoints.iter ().any (|bp| vm.at_breakpoint (bp)) {
|
||||
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");
|
||||
}
|
||||
|
|
1002
src/state.rs
1002
src/state.rs
File diff suppressed because it is too large
Load Diff
33
src/tests.rs
33
src/tests.rs
|
@ -23,9 +23,9 @@ fn calculate_hash<T: Hash>(t: &T) -> u64 {
|
|||
/// and returns the output
|
||||
|
||||
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 ()));
|
||||
vm.execute_chunk (chunk, &upvalues)
|
||||
let mut vm = State::new (chunk, &upvalues);
|
||||
vm.execute_chunk (&[])
|
||||
}
|
||||
|
||||
/// Takes arguments and Lua bytecode, loads it, runs it,
|
||||
|
@ -93,7 +93,7 @@ fn bools () {
|
|||
"arg".into (),
|
||||
"print".into (),
|
||||
],
|
||||
upvalue_count: 1,
|
||||
upvalues: vec! [],
|
||||
},
|
||||
Block {
|
||||
instructions: vec! [
|
||||
|
@ -107,7 +107,7 @@ fn bools () {
|
|||
Inst::Return0,
|
||||
],
|
||||
constants: vec! [],
|
||||
upvalue_count: 0,
|
||||
upvalues: vec! [],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
@ -118,10 +118,9 @@ fn bools () {
|
|||
] {
|
||||
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 actual = vm.execute_chunk (&chunk, &upvalues);
|
||||
let mut vm = State::new (&chunk, &upvalues);
|
||||
let actual = vm.execute_chunk (&[]);
|
||||
assert_eq! (actual, expected);
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +163,7 @@ fn floats () {
|
|||
0.5.into (),
|
||||
"print".into (),
|
||||
],
|
||||
upvalue_count: 1,
|
||||
upvalues: vec! [],
|
||||
};
|
||||
let chunk = Chunk {
|
||||
blocks: vec! [block],
|
||||
|
@ -175,9 +174,9 @@ fn floats () {
|
|||
(vec! ["_exe_name", " "], vec! [3.5.into ()]),
|
||||
] {
|
||||
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 actual = vm.execute_chunk (&chunk, &upvalues);
|
||||
let mut vm = State::new (&chunk, &upvalues);
|
||||
let actual = vm.execute_chunk (&[]);
|
||||
|
||||
assert_eq! (actual, expected);
|
||||
}
|
||||
|
@ -185,19 +184,21 @@ fn floats () {
|
|||
|
||||
#[test]
|
||||
fn fma () {
|
||||
let bytecode = include_bytes! ("../test_vectors/fma.luac");
|
||||
let mut rdr = std::io::Cursor::new (bytecode);
|
||||
let file = crate::loader::parse_chunk (&mut rdr).unwrap ();
|
||||
assert_eq! (file.blocks.len (), 4);
|
||||
let source = include_bytes! ("../test_vectors/fma.lua");
|
||||
let bytecode = &crate::loader::compile_bytecode_from_stdin (source.to_vec ());
|
||||
let chunk = crate::loader::parse_chunk_from_bytes (bytecode).unwrap ();
|
||||
assert_eq! (chunk.blocks.len (), 5);
|
||||
|
||||
assert_eq! (chunk.blocks [3].upvalues.len (), 2);
|
||||
|
||||
for (arg, expected) in [
|
||||
(vec! ["_exe_name"], vec! [122.into ()]),
|
||||
(vec! ["_exe_name"], vec! [122.into ()]),
|
||||
] {
|
||||
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 actual = vm.execute_chunk (&file, &upvalues);
|
||||
let mut vm = State::new (&chunk, &upvalues);
|
||||
let actual = vm.execute_chunk (&[]);
|
||||
|
||||
assert_eq! (actual, expected);
|
||||
}
|
||||
|
|
47
src/value.rs
47
src/value.rs
|
@ -11,11 +11,12 @@ use std::{
|
|||
|
||||
#[derive (Debug, Eq, PartialEq)]
|
||||
pub struct BogusClosure {
|
||||
// I'm pretty sure this should be absolute?
|
||||
pub idx: usize,
|
||||
pub upvalues: Vec <Value>,
|
||||
}
|
||||
|
||||
#[derive (Clone, Debug, PartialEq)]
|
||||
#[derive (Clone, PartialEq)]
|
||||
pub enum Value {
|
||||
Nil,
|
||||
Boolean (bool),
|
||||
|
@ -32,7 +33,24 @@ pub enum Value {
|
|||
// These are all bogus, I haven't figured out how to implement
|
||||
// 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 {
|
||||
|
@ -53,11 +71,17 @@ impl fmt::Display for Value {
|
|||
Value::String (s) => write! (f, "{}", s),
|
||||
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 {
|
||||
fn from (x: bool) -> Self {
|
||||
Self::Boolean (x)
|
||||
|
@ -156,6 +180,13 @@ impl PartialEq <i64> for Value {
|
|||
}
|
||||
|
||||
impl Value {
|
||||
pub fn as_closure (&self) -> Option <&Rc <RefCell <BogusClosure>>> {
|
||||
match self {
|
||||
Self::BogusClosure (x) => Some (x),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Coerces ints to float
|
||||
|
||||
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 {
|
||||
array: Vec <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 {
|
||||
fn get_inner (&self, key: &Value) -> Value {
|
||||
self.hash.get (key).cloned ().unwrap_or_default ()
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
local function make_closure (x)
|
||||
print (x)
|
||||
local function make_closure (t)
|
||||
return function (y)
|
||||
return x + y
|
||||
return t.x + y
|
||||
end
|
||||
end
|
||||
|
||||
local f = make_closure (11)
|
||||
local f = make_closure ({ x = 11 })
|
||||
local t = {}
|
||||
local x = f (12)
|
||||
print (x)
|
||||
return x
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
-- This one fails :( I haven't implemented closures properly yet.
|
||||
|
||||
local ii = "bogus"
|
||||
|
||||
local function add (aa, bb)
|
||||
return aa + bb
|
||||
end
|
||||
|
@ -12,6 +14,13 @@ local function fma (ee, ff, gg)
|
|||
return add (mul (ee, ff), gg)
|
||||
end
|
||||
|
||||
local hh = fma (10, 11, 12)
|
||||
print (hh)
|
||||
local function run ()
|
||||
local hh = fma (10, 11, 12)
|
||||
print (hh)
|
||||
return hh
|
||||
end
|
||||
|
||||
local hh = run ()
|
||||
print (ii)
|
||||
|
||||
return hh
|
||||
|
|
Loading…
Reference in New Issue