⭐ 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
 | 
			
		||||
	Jmp (i32),
 | 
			
		||||
	
 | 
			
		||||
	Len (u8, u8),
 | 
			
		||||
	
 | 
			
		||||
	// Load F (Float?)
 | 
			
		||||
	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
 | 
			
		||||
/// 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
 | 
			
		||||
 | 
			
		||||
pub (crate) fn compile_bytecode (source: Vec <u8>) -> Vec <u8> {
 | 
			
		||||
pub (crate) fn compile_bytecode_from_stdin (source: Vec <u8>) -> Vec <u8> {
 | 
			
		||||
	use std::{
 | 
			
		||||
		io::Write,
 | 
			
		||||
		process::{
 | 
			
		||||
| 
						 | 
				
			
			@ -87,6 +110,7 @@ pub fn parse_inst (buf: [u8; 4]) -> Option <Inst>
 | 
			
		|||
		0x2e => Inst::MmBin (a, b, c),
 | 
			
		||||
		0x30 => Inst::MmBinK (a, b, c, k),
 | 
			
		||||
		0x33 => Inst::Not (a, b),
 | 
			
		||||
		0x34 => Inst::Len (a, b),
 | 
			
		||||
		0x3c => Inst::EqK (a, b, k),
 | 
			
		||||
		0x3d => Inst::EqI (a, i_sb (buf)?, k),
 | 
			
		||||
		0x38 => Inst::Jmp (s_j),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										14
									
								
								src/main.rs
								
								
								
								
							
							
						
						
									
										14
									
								
								src/main.rs
								
								
								
								
							| 
						 | 
				
			
			@ -11,6 +11,7 @@ mod tests;
 | 
			
		|||
fn main () {
 | 
			
		||||
	use state::State;
 | 
			
		||||
	
 | 
			
		||||
	let mut list_bytecode = false;
 | 
			
		||||
	let mut pipe_bytecode = false;
 | 
			
		||||
	let mut script = None;
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			@ -19,6 +20,7 @@ fn main () {
 | 
			
		|||
	
 | 
			
		||||
	while let Some (arg) = args.next () {
 | 
			
		||||
		match arg.as_str () {
 | 
			
		||||
			"--list-bytecode" => list_bytecode = true,
 | 
			
		||||
			"--pipe-bytecode" => pipe_bytecode = true,
 | 
			
		||||
			"--script" => script = Some (args.next ().unwrap ()),
 | 
			
		||||
			"--" => break,
 | 
			
		||||
| 
						 | 
				
			
			@ -26,9 +28,9 @@ fn main () {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	let lua_file = if let Some (script) = script {
 | 
			
		||||
		let source = std::fs::read (script).expect ("couldn't load Lua source code");
 | 
			
		||||
		let bytecode = loader::compile_bytecode(source);
 | 
			
		||||
	let chunk = if let Some (script) = script {
 | 
			
		||||
		let bytecode = loader::compile_bytecode_from_file (&script);
 | 
			
		||||
		dbg! (&bytecode [0..48]);
 | 
			
		||||
		let mut rdr = std::io::Cursor::new (bytecode);
 | 
			
		||||
		loader::parse_chunk (&mut rdr).unwrap ()
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +42,10 @@ fn main () {
 | 
			
		|||
		unimplemented!();
 | 
			
		||||
	};
 | 
			
		||||
	
 | 
			
		||||
	if list_bytecode {
 | 
			
		||||
		dbg! (&chunk);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	let mut vm = State::default ();
 | 
			
		||||
	if std::env::var("LUA_DEBUG").is_ok() {
 | 
			
		||||
		vm.debug_print = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -52,5 +58,5 @@ fn main () {
 | 
			
		|||
		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 instructions: Vec <Instruction>,
 | 
			
		||||
	pub constants: Vec <Value>,
 | 
			
		||||
	pub upvalue_count: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive (Debug)]
 | 
			
		||||
pub struct Chunk {
 | 
			
		||||
	pub blocks: Vec <Block>,
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -338,6 +340,14 @@ impl State {
 | 
			
		|||
					*self.reg_mut (*a) = upvalues [b].clone ();
 | 
			
		||||
				},
 | 
			
		||||
				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) => {
 | 
			
		||||
					*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
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -289,7 +289,7 @@ fn is_93 () {
 | 
			
		|||
	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 ();
 | 
			
		||||
	
 | 
			
		||||
	assert_eq! (chunk.blocks [0].instructions [3], Inst::EqK (0, 1, false));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue