From 1673ae964ac1bb994d51274e67fc521dfc55ec33 Mon Sep 17 00:00:00 2001 From: Sofia Date: Sun, 15 Mar 2026 18:32:22 +0200 Subject: [PATCH] Implement assignment of multiple values --- src/ast.rs | 21 +++++++++++++-------- src/compile.rs | 50 ++++++++++++++++++++++++++++++++++---------------- src/vm.rs | 10 ++++++++++ 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 89e4670..16eefb3 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -206,7 +206,7 @@ impl Parse for Block { #[derive(Debug, Clone)] pub enum Statement { - Assignment(AccessModifier, Node, Node), + Assignment(AccessModifier, Vec>, ExpressionList), Return(ExpressionList), If(Node, Block), } @@ -219,14 +219,14 @@ impl Parse for Statement { if let Some(name) = function.kind.name { Ok(Self::Assignment( AccessModifier::Global, - name, - Node { + vec![name], + ExpressionList(vec![Node { kind: Expression::FunctionDefinition( function.kind.params, function.kind.block, ), meta: function.meta, - }, + }]), )) } else { todo!() @@ -247,10 +247,15 @@ impl Parse for Statement { Some(Token::Keyword(Keyword::Global)) => AccessModifier::Global, _ => panic!(), }; - let name = stream.parse()?; + let mut names = Vec::new(); + names.push(stream.parse()?); + while stream.peek() == Some(Token::Symbol(',')) { + stream.next(); + names.push(stream.parse()?); + } stream.expect(Token::Symbol('='))?; let expr = stream.parse()?; - Ok(Statement::Assignment(access_modifier, name, expr)) + Ok(Statement::Assignment(access_modifier, names, expr)) } else if let Some(Token::Word(_)) = peeked && stream.peek2() == Some(Token::Symbol('=')) { @@ -258,8 +263,8 @@ impl Parse for Statement { stream.expect(Token::Symbol('='))?; Ok(Self::Assignment( AccessModifier::Global, - name, - stream.parse()?, + vec![name], + ExpressionList(vec![stream.parse()?]), )) } else { Err(stream.expecting_err("statement")) diff --git a/src/compile.rs b/src/compile.rs index 36b144f..6888698 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -25,6 +25,7 @@ impl State { pub struct Scope { pub locals: HashMap, pub register_counter: LocalCounter, + pub highest_upvalue: u16, pub upvalues: HashMap, } @@ -67,14 +68,20 @@ impl Block { impl Statement { pub fn find_constants(&self, scope: &mut Scope) -> HashSet { match self { - Statement::Assignment(access, name, expr) => { + Statement::Assignment(access, names, expr_list) => { let mut constants = HashSet::new(); if *access == AccessModifier::Global { - constants.insert(Constant::String(name.kind.clone())); + for name in names { + constants.insert(Constant::String(name.kind.clone())); + } } else { - scope.locals.insert(name.kind.clone(), 0); + for name in names { + scope.locals.insert(name.kind.clone(), 0); + } + } + for expr in &expr_list.0 { + constants.extend(expr.kind.find_constants(scope)); } - constants.extend(expr.kind.find_constants(scope)); constants } Statement::Return(expr_list) => { @@ -97,18 +104,29 @@ impl Statement { let mut instructions = Vec::new(); match self { - Statement::Assignment(access_modifier, name, expr) => { - let (instr, regs) = expr.kind.compile(state, scope, Some(1)); - instructions.extend(instr); + Statement::Assignment(access_modifier, names, expr_list) => { + instructions.push(Instruction::LoadNil( + scope.register_counter.0 + 1, + scope.register_counter.0 + names.len() as u16, + )); + + let mut expr_regs = Vec::new(); + for expr in &expr_list.0 { + let (instr, regs) = expr.kind.compile(state, scope, Some(1)); + instructions.extend(instr); + expr_regs.extend(regs); + } match access_modifier { AccessModifier::Local => { - scope - .locals - .insert(name.kind.clone(), *regs.get(0).unwrap()); + for (name, reg) in names.iter().zip(expr_regs) { + scope.locals.insert(name.kind.clone(), reg); + } } AccessModifier::Global => { - let global = state.get_constant(&Constant::String(name.kind.clone())); - instructions.push(Instruction::SetGlobal(*regs.get(0).unwrap(), global)); + for (name, reg) in names.iter().zip(expr_regs) { + let global = state.get_constant(&Constant::String(name.kind.clone())); + instructions.push(Instruction::SetGlobal(reg, global)); + } } } } @@ -252,13 +270,13 @@ impl Expression { .insert(param.kind.clone(), inner_scope.register_counter.next()); } - let highest_upvalue = scope.upvalues.iter().map(|(_, v)| *v).max().unwrap_or(0); + inner_scope.highest_upvalue = + scope.highest_upvalue + inner_scope.register_counter.0; inner_scope.upvalues = scope.upvalues.clone(); for (name, reg) in &scope.locals { - inner_scope - .upvalues - .insert(name.clone(), *reg + highest_upvalue + 1); + let new_reg = *reg + inner_scope.highest_upvalue + 1; + inner_scope.upvalues.insert(name.clone(), new_reg); } let instructions = block.compile(state, &mut inner_scope); diff --git a/src/vm.rs b/src/vm.rs index 131b82d..823c200 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -28,6 +28,8 @@ pub enum Instruction { Move(u16, u16), /// R(A) := K(Bx) LoadK(u16, u32), + /// R(A), ..., R(B) := nil + LoadNil(u16, u16), /// G[K(Bx)] := R(A) SetGlobal(u16, u32), /// R(A) := G[K(Bx)] @@ -63,6 +65,7 @@ impl Debug for Instruction { Instruction::Return(arg0, arg1) => write!(f, "RETURN {} {}", arg0, arg1), Instruction::LessThan(arg0, arg1, arg2) => write!(f, "LE {} {} {}", arg0, arg1, arg2), Instruction::Add(arg0, arg1, arg2) => write!(f, "ADD {} {} {}", arg0, arg1, arg2), + Instruction::LoadNil(arg0, arg1) => write!(f, "LOADNIL {} {}", arg0, arg1), } } } @@ -217,6 +220,11 @@ impl ClosureRunner { }, ); } + Instruction::LoadNil(from_reg, to_reg) => { + for i in *from_reg..=*to_reg { + self.stack.insert(i, Value::Nil); + } + } Instruction::SetGlobal(reg, global) => { self.closure.environment.borrow_mut().globals.insert( constants.get(*global as usize).unwrap().clone(), @@ -308,6 +316,8 @@ impl ClosureRunner { ); } + dbg!(&highest_upvalue, &upvalues); + self.stack.insert( *reg, Value::Function(Closure {