♻️ refactor: match the Lua CLI API more closely

main
_ 2023-10-01 21:26:47 -05:00
parent db84365c27
commit b8dd59cd7c
6 changed files with 68 additions and 38 deletions

View File

@ -1,20 +1,28 @@
// cargo run -- --script lunar_wave_vm/test_vectors/fizz_buzz.lua // cargo run -- --script lunar_wave_vm/test_vectors/fizz_buzz.lua
use std::io::Read;
use lunar_wave_vm as lwvm; use lunar_wave_vm as lwvm;
fn main () -> Result <(), lwvm::StepError> { fn main () -> Result <(), lwvm::StepError> {
let args: Vec <_> = std::env::args ().collect ();
lunar_wave (args)?;
Ok (())
}
fn lunar_wave (args: Vec <String>) -> Result <Vec <lwvm::Value>, lwvm::StepError> {
let mut list_bytecode = false; let mut list_bytecode = false;
let mut pipe_bytecode = false;
let mut script = None;
let mut breakpoints = vec![]; let mut breakpoints = vec![];
let mut chunk = None;
let mut lua_args = vec! [];
let mut args = std::env::args (); let mut arg_iter = args.iter ();
let exe_name = args.next ().unwrap (); let _exe_name = arg_iter.next ().unwrap ();
while let Some (arg) = args.next () { while let Some (arg) = arg_iter.next () {
match arg.as_str () { match arg.as_str () {
"--break" => { "--break" => {
let s = args.next ().unwrap (); let s = arg_iter.next ().unwrap ();
let (block_idx, program_counter) = s.split_once (":").unwrap (); let (block_idx, program_counter) = s.split_once (":").unwrap ();
let block_idx = str::parse (block_idx).unwrap (); let block_idx = str::parse (block_idx).unwrap ();
let program_counter = str::parse (program_counter).unwrap (); let program_counter = str::parse (program_counter).unwrap ();
@ -25,31 +33,41 @@ fn main () -> Result <(), lwvm::StepError> {
}); });
}, },
"--list-bytecode" => list_bytecode = true, "--list-bytecode" => list_bytecode = true,
"--pipe-bytecode" => pipe_bytecode = true, "-" => {
"--script" => script = Some (args.next ().unwrap ()), let mut buf = vec! [];
std::io::stdin ().read_to_end (&mut buf).unwrap ();
let bc = lwvm::ensure_bytecode (buf);
let mut rdr = std::io::Cursor::new (bc);
chunk = Some (lwvm::parse_chunk (&mut rdr).unwrap ());
lua_args = vec! ["-".to_string ()];
},
"--" => break, "--" => break,
_ => panic! ("can't parse args"), x => {
if x.starts_with ('-') {
panic! ("Unknown flag `{x}`");
}
else if chunk.is_none () {
let bc = lwvm::compile_bytecode_from_file (x);
let mut rdr = std::io::Cursor::new (bc);
chunk = Some (lwvm::parse_chunk (&mut rdr).unwrap ());
lua_args = vec! [x.to_string ()];
}
else {
lua_args.push (x.into ());
}
},
} }
} }
let chunk = if let Some (script) = script { let chunk = chunk.unwrap ();
let bytecode = lwvm::compile_bytecode_from_file (&script);
let mut rdr = std::io::Cursor::new (bytecode);
lwvm::parse_chunk (&mut rdr).unwrap ()
}
else if pipe_bytecode {
let mut stdin = std::io::stdin ().lock ();
lwvm::parse_chunk (&mut stdin).unwrap ()
}
else {
unimplemented!();
};
if list_bytecode { if list_bytecode {
dbg! (&chunk); dbg! (&chunk);
} }
let upvalues = lwvm::State::upvalues_from_args ([exe_name].into_iter ().chain (args)); let upvalues = lwvm::State::upvalues_from_args (lua_args.into_iter ());
let mut vm = lwvm::State::new (chunk, upvalues); let mut vm = lwvm::State::new (chunk, upvalues);
if std::env::var("LWVM_DEBUG").is_ok() { if std::env::var("LWVM_DEBUG").is_ok() {
@ -77,7 +95,7 @@ fn main () -> Result <(), lwvm::StepError> {
match input.as_str ().trim_end () { match input.as_str ().trim_end () {
"c" => in_break = false, "c" => in_break = false,
"q" => return Ok (()), "q" => return Ok (vec! []),
"registers" => { "registers" => {
dbg! (&vm.registers); dbg! (&vm.registers);
continue; continue;
@ -86,8 +104,7 @@ fn main () -> Result <(), lwvm::StepError> {
match vm.step ()? { match vm.step ()? {
None => (), None => (),
Some (lwvm::StepOutput::ChunkReturned (x)) => { Some (lwvm::StepOutput::ChunkReturned (x)) => {
dbg! (x); return Ok (x);
return Ok (());
}, },
} }
continue; continue;
@ -99,12 +116,9 @@ fn main () -> Result <(), lwvm::StepError> {
match vm.step ()? { match vm.step ()? {
None => (), None => (),
Some (lwvm::StepOutput::ChunkReturned (x)) => { Some (lwvm::StepOutput::ChunkReturned (x)) => {
dbg! (x); return Ok (x);
return Ok (());
}, },
} }
} }
dbg! (vm);
panic! ("Hit max iterations before block returned");
} }

View File

@ -4,7 +4,8 @@ mod state;
mod value; mod value;
pub use loader::compile_bytecode_from_file as compile_bytecode_from_file; pub use loader::compile_bytecode_from_file as compile_bytecode_from_file;
pub use loader::compile_bytecode_from_stdin as compile_bytecode_from_stdin; pub use loader::compile_bytecode as compile_bytecode;
pub use loader::ensure_bytecode as ensure_bytecode;
pub use loader::parse_chunk as parse_chunk; pub use loader::parse_chunk as parse_chunk;
pub use state::Breakpoint as Breakpoint; pub use state::Breakpoint as Breakpoint;
pub use state::State as State; pub use state::State as State;

View File

@ -34,7 +34,7 @@ pub fn compile_bytecode_from_file (path: &str) -> Vec <u8> {
/// ///
/// `source` is a Vec because we move it to a worker thread /// `source` is a Vec because we move it to a worker thread
pub fn compile_bytecode_from_stdin (source: Vec <u8>) -> Vec <u8> { pub fn compile_bytecode (source: Vec <u8>) -> Vec <u8> {
use std::{ use std::{
io::Write, io::Write,
process::{ process::{
@ -64,6 +64,19 @@ pub fn compile_bytecode_from_stdin (source: Vec <u8>) -> Vec <u8> {
output.stdout.as_slice ().to_vec () output.stdout.as_slice ().to_vec ()
} }
/// Checks whether the input is already bytecode, or is possibly
/// Lua source code. If it's source code, compiles and returns bytecode.
/// If it's bytecode, just returns the input.
pub fn ensure_bytecode (buffer: Vec <u8>) -> Vec <u8> {
let bytecode_header = &[0x1b, 0x4c, 0x75, 0x61, 0x54, 0x00, 0x19, 0x93];
if buffer.starts_with (bytecode_header) {
return buffer;
}
compile_bytecode (buffer)
}
fn i_sb (buf: [u8; 4]) -> Option <i8> { fn i_sb (buf: [u8; 4]) -> Option <i8> {
let b = buf [2]; let b = buf [2];
i8::try_from (i32::try_from (b).ok ()? - 127).ok () i8::try_from (i32::try_from (b).ok ()? - 127).ok ()

View File

@ -42,7 +42,7 @@ fn run_bytecode (args: &[&str], bc: &[u8]) -> Vec <Value> {
/// and returns the output /// and returns the output
fn run_source (args: &[&str], s: &str) -> Vec <Value> { fn run_source (args: &[&str], s: &str) -> Vec <Value> {
let bc = loader::compile_bytecode_from_stdin (s.as_bytes ().to_vec ()); let bc = loader::compile_bytecode (s.as_bytes ().to_vec ());
run_bytecode (args, &bc) run_bytecode (args, &bc)
} }
@ -128,7 +128,7 @@ fn bools () {
#[test] #[test]
fn closure () { fn closure () {
let source = include_bytes! ("../test_vectors/closure.lua"); let source = include_bytes! ("../test_vectors/closure.lua");
let bytecode = &crate::loader::compile_bytecode_from_stdin (source.to_vec ()); let bytecode = &crate::loader::compile_bytecode (source.to_vec ());
let chunk = crate::loader::parse_chunk_from_bytes (bytecode).unwrap (); let chunk = crate::loader::parse_chunk_from_bytes (bytecode).unwrap ();
assert_eq! (run_chunk (&["_exe_name"], chunk), vec! [Value::from (23i64)]); assert_eq! (run_chunk (&["_exe_name"], chunk), vec! [Value::from (23i64)]);
@ -185,7 +185,7 @@ fn floats () {
#[test] #[test]
fn fma () { fn fma () {
let source = include_bytes! ("../test_vectors/fma.lua"); let source = include_bytes! ("../test_vectors/fma.lua");
let bytecode = &crate::loader::compile_bytecode_from_stdin (source.to_vec ()); let bytecode = &crate::loader::compile_bytecode (source.to_vec ());
let chunk = crate::loader::parse_chunk_from_bytes (bytecode).unwrap (); let chunk = crate::loader::parse_chunk_from_bytes (bytecode).unwrap ();
assert_eq! (chunk.blocks.len (), 5); assert_eq! (chunk.blocks.len (), 5);
@ -275,7 +275,7 @@ fn is_93 () {
end end
"#; "#;
let bc = loader::compile_bytecode_from_stdin (src.as_bytes ().to_vec ()); let bc = loader::compile_bytecode (src.as_bytes ().to_vec ());
let chunk = loader::parse_chunk_from_bytes (&bc).unwrap (); let chunk = loader::parse_chunk_from_bytes (&bc).unwrap ();
assert_eq! (chunk.blocks [0].instructions [3], Inst::EqK (0, 1, false)); assert_eq! (chunk.blocks [0].instructions [3], Inst::EqK (0, 1, false));
@ -363,7 +363,7 @@ fn tailcall () {
return tonumber ("5") return tonumber ("5")
"#; "#;
let bc = loader::compile_bytecode_from_stdin (src.as_bytes ().to_vec ()); let bc = loader::compile_bytecode (src.as_bytes ().to_vec ());
let chunk = loader::parse_chunk_from_bytes (&bc).unwrap (); let chunk = loader::parse_chunk_from_bytes (&bc).unwrap ();
assert_eq! (chunk.blocks [0].instructions [3], Instruction::TailCall (0, 2, 1, false)); assert_eq! (chunk.blocks [0].instructions [3], Instruction::TailCall (0, 2, 1, false));

View File

@ -0,0 +1,2 @@
print (arg [0])
print (arg [1])

View File

@ -19,7 +19,7 @@ fn embedding () {
1 1
} }
let bytecode = lwvm::compile_bytecode_from_stdin (src.to_vec ()); let bytecode = lwvm::compile_bytecode (src.to_vec ());
let mut rdr = std::io::Cursor::new (bytecode); let mut rdr = std::io::Cursor::new (bytecode);
let chunk = lwvm::parse_chunk (&mut rdr).unwrap (); let chunk = lwvm::parse_chunk (&mut rdr).unwrap ();