Implement assignment of multiple values
This commit is contained in:
parent
167649d9e4
commit
1673ae964a
21
src/ast.rs
21
src/ast.rs
@ -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"))
|
||||
|
||||
@ -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);
|
||||
|
||||
10
src/vm.rs
10
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 {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user