diff --git a/examples/test.lua b/examples/test.lua index cf6e804..8063bbf 100644 --- a/examples/test.lua +++ b/examples/test.lua @@ -1,4 +1,4 @@ -local b = 5 +global b = 5 function add(x) return function (y) diff --git a/src/compile.rs b/src/compile.rs index 0b356d9..05982c7 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -73,8 +73,8 @@ impl LocalCounter { } impl Block { - pub fn find_constants(&self, scope: &mut Scope) -> HashSet { - let mut constants = HashSet::new(); + pub fn find_constants(&self, scope: &mut Scope, constants: Vec) -> HashSet { + let mut constants = constants.iter().cloned().collect::>(); let mut inner_scope = scope.clone(); @@ -132,7 +132,7 @@ impl Statement { Statement::If(cond, then) => { let mut constants = HashSet::new(); constants.extend(cond.kind.find_constants(scope)); - constants.extend(then.find_constants(scope)); + constants.extend(then.find_constants(scope, Vec::new())); constants } Statement::Expression(expr) => expr.kind.find_constants(scope), @@ -303,7 +303,7 @@ impl Expression { constants } Expression::UnOp(_, expr) => expr.kind.find_constants(scope), - Expression::FunctionDefinition(_, block) => block.find_constants(scope), + Expression::FunctionDefinition(_, block) => block.find_constants(scope, Vec::new()), Expression::FunctionCall(expr, params) => { let mut constants = HashSet::new(); constants.extend(expr.kind.find_constants(scope)); diff --git a/src/main.rs b/src/main.rs index c2b84f1..d996176 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,40 +40,53 @@ impl RustFunction for Print { } } -fn main() { +fn compile( + text: &str, + constants: Vec, + prototypes: Vec>, +) -> (Vec, compile::State, Vec) { let file_path = PathBuf::from("../examples/test.lua"); - let tokens = tokenize(TEST).unwrap(); + let tokens = tokenize(text).unwrap(); let mut stream = TokenStream::from(&file_path, &tokens); - dbg!(&tokens); + // dbg!(&tokens); let chunk = stream.parse::().unwrap(); stream.expect(Token::Eof).unwrap(); - dbg!(&chunk); + // dbg!(&chunk); let constants = chunk - .find_constants(&mut Default::default()) + .find_constants(&mut Default::default(), constants) .into_iter() .collect::>(); - dbg!(&constants); let mut state = compile::State { constants: constants.clone(), - prototypes: Vec::new(), + prototypes, }; let mut scope = Default::default(); let instructions = chunk.compile(&mut state, &mut scope); + (instructions, state, constants) +} + +fn main() { + let (instructions, state, constants) = compile(TEST, Vec::new(), Vec::new()); + + dbg!(&instructions); + + dbg!(&constants); + let mut vm = VirtualMachine { environment: Default::default(), - constants, + constants: constants.clone(), prototypes: Default::default(), proto_counter: 0, }; let chunk_id = vm.new_prototype(instructions); - for prototype in state.prototypes { - vm.new_prototype(prototype); + for prototype in &state.prototypes { + vm.new_prototype(prototype.clone()); } dbg!(&vm.prototypes); @@ -90,7 +103,24 @@ fn main() { let mut run = closure.run(Vec::new()); - while run.next().unwrap().is_none() {} + while run.next().unwrap().is_none() { + let (instructions, state, constants) = + compile("print(b)", constants.clone(), state.prototypes.clone()); + + // dbg!(&instructions); + + let mut new_run = run.execute(instructions, state, constants); + while { + match new_run.next() { + Ok(Some(_)) => false, + Ok(None) => true, + Err(e) => { + print!("Error: {}", e); + false + } + } + } {} + } dbg!(&vm.environment.borrow().globals); } diff --git a/src/vm.rs b/src/vm.rs index f464393..29bb318 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -2,7 +2,10 @@ use thiserror::Error; use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc}; -use crate::ast::{BinaryOperator, LuaNumber, UnaryOperator}; +use crate::{ + ast::{BinaryOperator, LuaNumber, UnaryOperator}, + compile, +}; pub type VMNumber = u64; @@ -106,6 +109,8 @@ pub enum RuntimeError { InvalidOperand(UnaryOperator, Value), #[error("Tried calling a non-function: {0:?}")] TriedCallingNonFunction(Value), + #[error("Global not found: {0:?}")] + GlobalNotFound(Option), #[error("{0}")] Custom(String), } @@ -321,6 +326,44 @@ impl ClosureRunner { } } + fn close_upvalues(&self) -> HashMap>> { + let highest_upvalue = self + .closure + .upvalues + .iter() + .map(|(v, _)| *v) + .max() + .unwrap_or(0); + + let mut upvalues = self.closure.upvalues.clone(); + for (reg, value) in &self.stack { + upvalues.insert(reg + highest_upvalue + 1, value.clone()); + } + upvalues + } + + pub fn execute( + &mut self, + instructions: Vec, + state: compile::State, + constants: Vec, + ) -> ClosureRunner { + let mut vm = self.closure.vm.clone(); + vm.constants = constants; + let proto_id = vm.new_prototype(instructions); + for prototype in state.prototypes { + vm.new_prototype(prototype); + } + + let closure = Closure { + vm, + prototype: proto_id, + environment: self.closure.environment.clone(), + upvalues: self.close_upvalues(), + }; + closure.run(Vec::new()) + } + pub fn next(&mut self) -> Result>, RuntimeError> { if let Some(inner) = &mut self.inner { match inner.next() { @@ -408,7 +451,9 @@ impl ClosureRunner { if let Some(global) = glob { self.set_stack(*reg, global.clone()); } else { - todo!("Global not found: {:?}", constants.get(*global as usize)) + return Err(RuntimeError::GlobalNotFound( + constants.get(*global as usize).cloned(), + )); } } Instruction::GetUpVal(reg, upvalreg) => { @@ -514,26 +559,13 @@ impl ClosureRunner { } Instruction::Close(_) => {} Instruction::Closure(reg, protok) => { - let highest_upvalue = self - .closure - .upvalues - .iter() - .map(|(v, _)| *v) - .max() - .unwrap_or(0); - - let mut upvalues = self.closure.upvalues.clone(); - for (reg, value) in &self.stack { - upvalues.insert(reg + highest_upvalue + 1, value.clone()); - } - self.set_stack( *reg, Value::Function(Closure { vm: self.closure.vm.clone(), prototype: *protok, environment: self.closure.environment.clone(), - upvalues, + upvalues: self.close_upvalues(), }), ); }