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)]
pub enum Statement {
Assignment(AccessModifier, Node<String>, Node<Expression>),
Assignment(AccessModifier, Vec<Node<String>>, ExpressionList),
Return(ExpressionList),
If(Node<Expression>, 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"))

View File

@ -25,6 +25,7 @@ impl State {
pub struct Scope {
pub locals: HashMap<String, u16>,
pub register_counter: LocalCounter,
pub highest_upvalue: u16,
pub upvalues: HashMap<String, u16>,
}
@ -67,14 +68,20 @@ impl Block {
impl Statement {
pub fn find_constants(&self, scope: &mut Scope) -> HashSet<Constant> {
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);

View File

@ -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 {