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)]
|
#[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"))
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
10
src/vm.rs
10
src/vm.rs
@ -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 {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user