From 7c327beaa11b3fc7892b77d1f90ff40557b784d3 Mon Sep 17 00:00:00 2001 From: Sofia Date: Sat, 14 Mar 2026 23:02:28 +0200 Subject: [PATCH] Implement functions --- examples/test.lua | 6 ++++- src/ast.rs | 10 +++++--- src/compile.rs | 37 ++++++++++++++++++++++----- src/main.rs | 22 +++++++++------- src/vm.rs | 65 ++++++++++++++++++++++++++++++++++++++++------- 5 files changed, 111 insertions(+), 29 deletions(-) diff --git a/examples/test.lua b/examples/test.lua index ad6cd60..4556aa4 100644 --- a/examples/test.lua +++ b/examples/test.lua @@ -1 +1,5 @@ -global c = print(5, 7) \ No newline at end of file +function test() + return 5 +end + +global c = print(test()) \ No newline at end of file diff --git a/src/ast.rs b/src/ast.rs index 3a10a93..ec8f866 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -295,10 +295,12 @@ pub struct ExpressionList(pub Vec>); impl Parse for ExpressionList { fn parse(mut stream: TokenStream) -> Result { let mut list = Vec::new(); - list.push(stream.parse()?); - while stream.peek() == Some(Token::Symbol(',')) { - stream.next(); - list.push(stream.parse()?); + if let Ok(value) = stream.parse() { + list.push(value); + while stream.peek() == Some(Token::Symbol(',')) { + stream.next(); + list.push(stream.parse()?); + } } Ok(ExpressionList(list)) diff --git a/src/compile.rs b/src/compile.rs index f3be14a..c230d41 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -7,6 +7,7 @@ use crate::{ pub struct State { pub constants: Vec, + pub prototypes: Vec>, } impl State { @@ -94,9 +95,9 @@ impl Statement { instructions.extend(instr); match access_modifier { AccessModifier::Local => { - let reg = scope.register_counter.next(); - scope.locals.insert(name.kind.clone(), reg); - instructions.push(Instruction::Move(reg, *regs.get(0).unwrap())); + scope + .locals + .insert(name.kind.clone(), *regs.get(0).unwrap()); } AccessModifier::Global => { let global = state.get_constant(&Constant::String(name.kind.clone())); @@ -104,7 +105,14 @@ impl Statement { } } } - Statement::Return(node) => todo!(), + Statement::Return(expr) => { + let (instr, registers) = expr.kind.compile(state, scope, 1); + instructions.extend(instr); + instructions.push(Instruction::Return( + *registers.first().unwrap(), + *registers.last().unwrap(), + )); + } Statement::If(node, block) => todo!(), } @@ -168,7 +176,24 @@ impl Expression { } } Expression::BinOp(binary_operator, node, node1) => todo!(), - Expression::FunctionDefinition(nodes, block) => todo!(), + Expression::FunctionDefinition(params, block) => { + let mut inner_scope = Scope::default(); + for param in params { + inner_scope + .locals + .insert(param.kind.clone(), inner_scope.register_counter.next()); + } + + let instructions = block.compile(state, &mut inner_scope); + state.prototypes.push(instructions); + + let mut instructions = Vec::new(); + instructions.push(Instruction::Close(scope.register_counter.0)); + let local = scope.register_counter.next(); + instructions.push(Instruction::Closure(local, state.prototypes.len() as u32)); + + (instructions, vec![local]) + } Expression::FunctionCall(expr, params) => { let mut instructions = Vec::new(); let (instr, registers) = expr.kind.compile(state, scope, 1); @@ -183,7 +208,7 @@ impl Expression { param_regs.extend(registers); } - let last_param_reg = param_regs.last().unwrap(); + let last_param_reg = param_regs.last().unwrap_or(function_register); let mut return_regs = Vec::new(); for i in 0..expected_values { diff --git a/src/main.rs b/src/main.rs index 308d9ff..7eb499d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,13 +58,12 @@ fn main() { .collect::>(); dbg!(&constants); - let instructions = chunk.compile( - &mut compile::State { - constants: constants.clone(), - }, - &mut Default::default(), - ); - dbg!(&instructions); + let mut state = compile::State { + constants: constants.clone(), + prototypes: Vec::new(), + }; + let mut scope = Default::default(); + let instructions = chunk.compile(&mut state, &mut scope); let mut vm = VirtualMachine { environment: Default::default(), @@ -72,6 +71,11 @@ fn main() { prototypes: Default::default(), }; vm.prototypes.insert(0, instructions); + for (i, prototype) in state.prototypes.into_iter().enumerate() { + vm.prototypes.insert((i + 1) as u32, prototype); + } + dbg!(&vm.prototypes); + vm.environment.borrow_mut().globals.insert( vm::Constant::String("max".to_owned()), vm::Value::RustFunction(Rc::new(RefCell::new(Max))), @@ -85,7 +89,7 @@ fn main() { let mut run = closure.run(); - while run.next() {} + while run.next().is_none() {} - dbg!(vm.environment.borrow()); + // dbg!(&vm.environment.borrow().globals); } diff --git a/src/vm.rs b/src/vm.rs index 02088cf..f311ef4 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -35,16 +35,22 @@ pub enum Instruction { /// [func] [params.len()] [ret_regs.len()] /// R(A), ... R(A+C-2) := R(A)(R(A+1), ... R(A+B-1)) Call(u16, u16, u16), + Return(u16, u16), + Close(u16), + Closure(u16, u32), } impl Debug for Instruction { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Move(arg0, arg1) => write!(f, "MOVE {} {}", arg0, arg1), - Self::LoadK(arg0, arg1) => write!(f, "LOADK {} {}", arg0, arg1), - Self::SetGlobal(arg0, arg1) => write!(f, "SETGLOBAL {} {}", arg0, arg1), - Self::GetGlobal(arg0, arg1) => write!(f, "GETGLOBAL {} {}", arg0, arg1), - Self::Call(arg0, arg1, arg2) => write!(f, "CALL {} {} {}", arg0, arg1, arg2), + Instruction::Move(arg0, arg1) => write!(f, "MOVE {} {}", arg0, arg1), + Instruction::LoadK(arg0, arg1) => write!(f, "LOADK {} {}", arg0, arg1), + Instruction::SetGlobal(arg0, arg1) => write!(f, "SETGLOBAL {} {}", arg0, arg1), + Instruction::GetGlobal(arg0, arg1) => write!(f, "GETGLOBAL {} {}", arg0, arg1), + Instruction::Call(arg0, arg1, arg2) => write!(f, "CALL {} {} {}", arg0, arg1, arg2), + Instruction::Close(arg0) => write!(f, "CLOSE {}", arg0), + Instruction::Closure(arg0, arg1) => write!(f, "CLOSURE {} {}", arg0, arg1), + Instruction::Return(arg0, arg1) => write!(f, "RETURN {} {}", arg0, arg1), } } } @@ -134,6 +140,8 @@ impl Closure { closure: self.clone(), program_counter: 0, stack: HashMap::new(), + inner: None, + return_registers: Vec::new(), } } } @@ -142,10 +150,23 @@ pub struct ClosureRunner { pub closure: Closure, pub program_counter: usize, pub stack: HashMap, + pub inner: Option>, + pub return_registers: Vec, } impl ClosureRunner { - pub fn next(&mut self) -> bool { + pub fn next(&mut self) -> Option> { + if let Some(inner) = &mut self.inner { + if let Some(ret_values) = inner.next() { + self.inner = None; + for (value, reg) in ret_values.iter().zip(&self.return_registers) { + self.stack.insert(*reg, value.clone()); + } + } else { + return None; + } + } + let instructions = self .closure .vm @@ -202,17 +223,43 @@ impl ClosureRunner { ); } } - Value::Function(_) => todo!(), + Value::Function(closure) => { + self.return_registers = Vec::new(); + for i in 0..=(*ret_len - 2) { + self.return_registers.push(*func_reg + i); + } + self.inner = Some(Box::new(closure.run())); + } _ => panic!(), } } + Instruction::Close(_) => {} + Instruction::Closure(reg, protok) => { + self.stack.insert( + *reg, + Value::Function(Closure { + vm: self.closure.vm.clone(), + prototype: *protok, + environment: self.closure.environment.clone(), + upvalues: HashMap::new(), + }), + ); + } + Instruction::Return(reg_start, reg_end) => { + self.program_counter += 1; + let mut ret_values = Vec::new(); + for i in *reg_start..=*reg_end { + ret_values.push(self.stack.get(&i).cloned().unwrap_or(Value::Nil)); + } + return Some(ret_values); + } }; self.program_counter += 1; - true + None } else { - false + Some(Vec::new()) } } }