⭐ add OP_LEN and allow telling luac a file name
This make debugging easier, since the bytecodes will match between a terminal and lunar_wavemain
parent
565fd19e66
commit
5649f38698
|
@ -31,6 +31,8 @@ pub enum Instruction {
|
||||||
// Jump
|
// Jump
|
||||||
Jmp (i32),
|
Jmp (i32),
|
||||||
|
|
||||||
|
Len (u8, u8),
|
||||||
|
|
||||||
// Load F (Float?)
|
// Load F (Float?)
|
||||||
LoadF (u8, i32),
|
LoadF (u8, i32),
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,35 @@ use crate::{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub (crate) fn compile_bytecode_from_file (path: &str) -> Vec <u8> {
|
||||||
|
use std::{
|
||||||
|
process::{
|
||||||
|
Command,
|
||||||
|
Stdio,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let child = Command::new ("luac5.4")
|
||||||
|
.arg ("-o") // Output to...
|
||||||
|
.arg ("-") // Standard output
|
||||||
|
.arg (path)
|
||||||
|
.stdout (Stdio::piped ())
|
||||||
|
.spawn ()
|
||||||
|
.expect ("failed to execute `luac5.4`. Is Lua installed?");
|
||||||
|
|
||||||
|
let output = child
|
||||||
|
.wait_with_output ()
|
||||||
|
.expect ("failed to wait on child");
|
||||||
|
|
||||||
|
output.stdout.as_slice ().to_vec ()
|
||||||
|
}
|
||||||
|
|
||||||
/// Invoke `luac` as a subprocess
|
/// Invoke `luac` as a subprocess
|
||||||
/// Luckily luac is single-pass, so we can just pipe in and out
|
/// Luckily luac is single-pass, so we can just pipe in and out
|
||||||
///
|
///
|
||||||
/// `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 (crate) fn compile_bytecode (source: Vec <u8>) -> Vec <u8> {
|
pub (crate) fn compile_bytecode_from_stdin (source: Vec <u8>) -> Vec <u8> {
|
||||||
use std::{
|
use std::{
|
||||||
io::Write,
|
io::Write,
|
||||||
process::{
|
process::{
|
||||||
|
@ -87,6 +110,7 @@ pub fn parse_inst (buf: [u8; 4]) -> Option <Inst>
|
||||||
0x2e => Inst::MmBin (a, b, c),
|
0x2e => Inst::MmBin (a, b, c),
|
||||||
0x30 => Inst::MmBinK (a, b, c, k),
|
0x30 => Inst::MmBinK (a, b, c, k),
|
||||||
0x33 => Inst::Not (a, b),
|
0x33 => Inst::Not (a, b),
|
||||||
|
0x34 => Inst::Len (a, b),
|
||||||
0x3c => Inst::EqK (a, b, k),
|
0x3c => Inst::EqK (a, b, k),
|
||||||
0x3d => Inst::EqI (a, i_sb (buf)?, k),
|
0x3d => Inst::EqI (a, i_sb (buf)?, k),
|
||||||
0x38 => Inst::Jmp (s_j),
|
0x38 => Inst::Jmp (s_j),
|
||||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -11,6 +11,7 @@ mod tests;
|
||||||
fn main () {
|
fn main () {
|
||||||
use state::State;
|
use state::State;
|
||||||
|
|
||||||
|
let mut list_bytecode = false;
|
||||||
let mut pipe_bytecode = false;
|
let mut pipe_bytecode = false;
|
||||||
let mut script = None;
|
let mut script = None;
|
||||||
|
|
||||||
|
@ -19,6 +20,7 @@ fn main () {
|
||||||
|
|
||||||
while let Some (arg) = args.next () {
|
while let Some (arg) = args.next () {
|
||||||
match arg.as_str () {
|
match arg.as_str () {
|
||||||
|
"--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 ()),
|
||||||
"--" => break,
|
"--" => break,
|
||||||
|
@ -26,9 +28,9 @@ fn main () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let lua_file = if let Some (script) = script {
|
let chunk = if let Some (script) = script {
|
||||||
let source = std::fs::read (script).expect ("couldn't load Lua source code");
|
let bytecode = loader::compile_bytecode_from_file (&script);
|
||||||
let bytecode = loader::compile_bytecode(source);
|
dbg! (&bytecode [0..48]);
|
||||||
let mut rdr = std::io::Cursor::new (bytecode);
|
let mut rdr = std::io::Cursor::new (bytecode);
|
||||||
loader::parse_chunk (&mut rdr).unwrap ()
|
loader::parse_chunk (&mut rdr).unwrap ()
|
||||||
}
|
}
|
||||||
|
@ -40,6 +42,10 @@ fn main () {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if list_bytecode {
|
||||||
|
dbg! (&chunk);
|
||||||
|
}
|
||||||
|
|
||||||
let mut vm = State::default ();
|
let mut vm = State::default ();
|
||||||
if std::env::var("LUA_DEBUG").is_ok() {
|
if std::env::var("LUA_DEBUG").is_ok() {
|
||||||
vm.debug_print = true;
|
vm.debug_print = true;
|
||||||
|
@ -52,5 +58,5 @@ fn main () {
|
||||||
program_counter: 0,
|
program_counter: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
vm.execute_chunk (&lua_file, &upvalues);
|
vm.execute_chunk (&chunk, &upvalues);
|
||||||
}
|
}
|
||||||
|
|
10
src/state.rs
10
src/state.rs
|
@ -8,12 +8,14 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive (Debug)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
pub instructions: Vec <Instruction>,
|
pub instructions: Vec <Instruction>,
|
||||||
pub constants: Vec <Value>,
|
pub constants: Vec <Value>,
|
||||||
pub upvalue_count: usize,
|
pub upvalue_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive (Debug)]
|
||||||
pub struct Chunk {
|
pub struct Chunk {
|
||||||
pub blocks: Vec <Block>,
|
pub blocks: Vec <Block>,
|
||||||
}
|
}
|
||||||
|
@ -338,6 +340,14 @@ impl State {
|
||||||
*self.reg_mut (*a) = upvalues [b].clone ();
|
*self.reg_mut (*a) = upvalues [b].clone ();
|
||||||
},
|
},
|
||||||
Instruction::Jmp (s_j) => next_pc += s_j,
|
Instruction::Jmp (s_j) => next_pc += s_j,
|
||||||
|
Instruction::Len (a, b) => {
|
||||||
|
let len = match self.reg (*b) {
|
||||||
|
Value::String (s) => s.len (),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
*self.reg_mut (*a) = len.into ();
|
||||||
|
}
|
||||||
Instruction::LoadF (a, sbx) => {
|
Instruction::LoadF (a, sbx) => {
|
||||||
*self.reg_mut (*a) = Value::Float (*sbx as f64);
|
*self.reg_mut (*a) = Value::Float (*sbx as f64);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 (s.as_bytes ().to_vec ());
|
let bc = loader::compile_bytecode_from_stdin (s.as_bytes ().to_vec ());
|
||||||
run_bytecode (args, &bc)
|
run_bytecode (args, &bc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +289,7 @@ fn is_93 () {
|
||||||
end
|
end
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let bc = loader::compile_bytecode (src.as_bytes ().to_vec ());
|
let bc = loader::compile_bytecode_from_stdin (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));
|
||||||
|
|
Loading…
Reference in New Issue