Implement assignment of multiple values

This commit is contained in:
Sofia 2026-03-15 18:32:22 +02:00
parent 167649d9e4
commit 1673ae964a
3 changed files with 57 additions and 24 deletions

View File

@ -206,7 +206,7 @@ impl Parse for Block {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Statement { pub enum Statement {
Assignment(AccessModifier, Node<String>, Node<Expression>), Assignment(AccessModifier, Vec<Node<String>>, ExpressionList),
Return(ExpressionList), Return(ExpressionList),
If(Node<Expression>, Block), If(Node<Expression>, Block),
} }
@ -219,14 +219,14 @@ impl Parse for Statement {
if let Some(name) = function.kind.name { if let Some(name) = function.kind.name {
Ok(Self::Assignment( Ok(Self::Assignment(
AccessModifier::Global, AccessModifier::Global,
name, vec![name],
Node { ExpressionList(vec![Node {
kind: Expression::FunctionDefinition( kind: Expression::FunctionDefinition(
function.kind.params, function.kind.params,
function.kind.block, function.kind.block,
), ),
meta: function.meta, meta: function.meta,
}, }]),
)) ))
} else { } else {
todo!() todo!()
@ -247,10 +247,15 @@ impl Parse for Statement {
Some(Token::Keyword(Keyword::Global)) => AccessModifier::Global, Some(Token::Keyword(Keyword::Global)) => AccessModifier::Global,
_ => panic!(), _ => 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('='))?; stream.expect(Token::Symbol('='))?;
let expr = stream.parse()?; 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 } else if let Some(Token::Word(_)) = peeked
&& stream.peek2() == Some(Token::Symbol('=')) && stream.peek2() == Some(Token::Symbol('='))
{ {
@ -258,8 +263,8 @@ impl Parse for Statement {
stream.expect(Token::Symbol('='))?; stream.expect(Token::Symbol('='))?;
Ok(Self::Assignment( Ok(Self::Assignment(
AccessModifier::Global, AccessModifier::Global,
name, vec![name],
stream.parse()?, ExpressionList(vec![stream.parse()?]),
)) ))
} else { } else {
Err(stream.expecting_err("statement")) Err(stream.expecting_err("statement"))

View File

@ -25,6 +25,7 @@ impl State {
pub struct Scope { pub struct Scope {
pub locals: HashMap<String, u16>, pub locals: HashMap<String, u16>,
pub register_counter: LocalCounter, pub register_counter: LocalCounter,
pub highest_upvalue: u16,
pub upvalues: HashMap<String, u16>, pub upvalues: HashMap<String, u16>,
} }
@ -67,14 +68,20 @@ impl Block {
impl Statement { impl Statement {
pub fn find_constants(&self, scope: &mut Scope) -> HashSet<Constant> { pub fn find_constants(&self, scope: &mut Scope) -> HashSet<Constant> {
match self { match self {
Statement::Assignment(access, name, expr) => { Statement::Assignment(access, names, expr_list) => {
let mut constants = HashSet::new(); let mut constants = HashSet::new();
if *access == AccessModifier::Global { if *access == AccessModifier::Global {
constants.insert(Constant::String(name.kind.clone())); for name in names {
constants.insert(Constant::String(name.kind.clone()));
}
} else { } 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 constants
} }
Statement::Return(expr_list) => { Statement::Return(expr_list) => {
@ -97,18 +104,29 @@ impl Statement {
let mut instructions = Vec::new(); let mut instructions = Vec::new();
match self { match self {
Statement::Assignment(access_modifier, name, expr) => { Statement::Assignment(access_modifier, names, expr_list) => {
let (instr, regs) = expr.kind.compile(state, scope, Some(1)); instructions.push(Instruction::LoadNil(
instructions.extend(instr); 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 { match access_modifier {
AccessModifier::Local => { AccessModifier::Local => {
scope for (name, reg) in names.iter().zip(expr_regs) {
.locals scope.locals.insert(name.kind.clone(), reg);
.insert(name.kind.clone(), *regs.get(0).unwrap()); }
} }
AccessModifier::Global => { AccessModifier::Global => {
let global = state.get_constant(&Constant::String(name.kind.clone())); for (name, reg) in names.iter().zip(expr_regs) {
instructions.push(Instruction::SetGlobal(*regs.get(0).unwrap(), global)); 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()); .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(); inner_scope.upvalues = scope.upvalues.clone();
for (name, reg) in &scope.locals { for (name, reg) in &scope.locals {
inner_scope let new_reg = *reg + inner_scope.highest_upvalue + 1;
.upvalues inner_scope.upvalues.insert(name.clone(), new_reg);
.insert(name.clone(), *reg + highest_upvalue + 1);
} }
let instructions = block.compile(state, &mut inner_scope); let instructions = block.compile(state, &mut inner_scope);

View File

@ -28,6 +28,8 @@ pub enum Instruction {
Move(u16, u16), Move(u16, u16),
/// R(A) := K(Bx) /// R(A) := K(Bx)
LoadK(u16, u32), LoadK(u16, u32),
/// R(A), ..., R(B) := nil
LoadNil(u16, u16),
/// G[K(Bx)] := R(A) /// G[K(Bx)] := R(A)
SetGlobal(u16, u32), SetGlobal(u16, u32),
/// R(A) := G[K(Bx)] /// R(A) := G[K(Bx)]
@ -63,6 +65,7 @@ impl Debug for Instruction {
Instruction::Return(arg0, arg1) => write!(f, "RETURN {} {}", arg0, arg1), Instruction::Return(arg0, arg1) => write!(f, "RETURN {} {}", arg0, arg1),
Instruction::LessThan(arg0, arg1, arg2) => write!(f, "LE {} {} {}", arg0, arg1, arg2), Instruction::LessThan(arg0, arg1, arg2) => write!(f, "LE {} {} {}", arg0, arg1, arg2),
Instruction::Add(arg0, arg1, arg2) => write!(f, "ADD {} {} {}", 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) => { Instruction::SetGlobal(reg, global) => {
self.closure.environment.borrow_mut().globals.insert( self.closure.environment.borrow_mut().globals.insert(
constants.get(*global as usize).unwrap().clone(), constants.get(*global as usize).unwrap().clone(),
@ -308,6 +316,8 @@ impl ClosureRunner {
); );
} }
dbg!(&highest_upvalue, &upvalues);
self.stack.insert( self.stack.insert(
*reg, *reg,
Value::Function(Closure { Value::Function(Closure {