Skip to content

Commit

Permalink
VM: Implement variable declaration (var, const, and let) (#1030)
Browse files Browse the repository at this point in the history
* VM: Implement LetDeclList and the `let` keyword
* Support var and const
* Split defining and initializing into separate instructions
* DefLet doesn't need the value
* InitLexical initializes value if set
* Code review
* Fix rustfmt
* Add documentation
* InitLexical fix

Co-authored-by: jasonwilliams <jase.williams@gmail.com>
  • Loading branch information
AnnikaCodes and jasonwilliams authored Jan 7, 2021
1 parent 1a7e832 commit 89419e2
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 2 deletions.
40 changes: 40 additions & 0 deletions boa/src/vm/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,46 @@ impl CodeGen for Node {
}
Node::BinOp(ref op) => op.compile(compiler),
Node::UnaryOp(ref op) => op.compile(compiler),
Node::VarDeclList(ref list) => {
for var_decl in list.as_ref() {
let name = var_decl.name();
let index = compiler.pool.len();
compiler.add_instruction(Instruction::DefVar(index));
compiler.pool.push(name.into());

if let Some(v) = var_decl.init() {
v.compile(compiler);
compiler.add_instruction(Instruction::InitLexical(index))
};
}
}
Node::LetDeclList(ref list) => {
for let_decl in list.as_ref() {
let name = let_decl.name();
let index = compiler.pool.len();
compiler.add_instruction(Instruction::DefLet(index));
compiler.pool.push(name.into());

// If name has a value we can init here too
if let Some(v) = let_decl.init() {
v.compile(compiler);
compiler.add_instruction(Instruction::InitLexical(index))
};
}
}
Node::ConstDeclList(ref list) => {
for const_decl in list.as_ref() {
let name = const_decl.name();
let index = compiler.pool.len();
compiler.add_instruction(Instruction::DefConst(index));
compiler.pool.push(name.into());

if let Some(v) = const_decl.init() {
v.compile(compiler);
compiler.add_instruction(Instruction::InitLexical(index))
};
}
}
_ => unimplemented!(),
}
}
Expand Down
13 changes: 13 additions & 0 deletions boa/src/vm/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ pub enum Instruction {
Neg,
BitNot,
Not,

/// The usize is the index of the variable name in the pool
DefVar(usize),
/// The usize is the index of the variable name in the pool
DefLet(usize),
/// The usize is the index of the variable name in the pool
DefConst(usize),
/// The usize is the index of the value to initiate the variable with in the pool
InitLexical(usize),
}

impl std::fmt::Display for Instruction {
Expand Down Expand Up @@ -100,6 +109,10 @@ impl std::fmt::Display for Instruction {
Self::Neg => write!(f, "Neg"),
Self::BitNot => write!(f, "BitNot"),
Self::Not => write!(f, "Not"),
Self::DefVar(name) => write!(f, "DefVar({})", name),
Self::DefLet(name) => write!(f, "DefLet({})", name),
Self::DefConst(name) => write!(f, "DefConst({})", name),
Self::InitLexical(value) => write!(f, "InitLexical({})", value),
}
}
}
41 changes: 39 additions & 2 deletions boa/src/vm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use crate::{Context, Result, Value};
use crate::{environment::lexical_environment::VariableScope, BoaProfiler, Context, Result, Value};

pub(crate) mod compilation;
pub(crate) mod instructions;

use crate::BoaProfiler;
pub use compilation::Compiler;
pub use instructions::Instruction;

Expand Down Expand Up @@ -268,6 +267,44 @@ impl<'a> VM<'a> {
};
self.push(value.into());
}
Instruction::DefVar(name_index) => {
let name: String = self.pool[name_index].to_string(self.ctx)?.to_string();

self.ctx
.realm_mut()
.environment
.create_mutable_binding(name.to_string(), false, VariableScope::Function)
.map_err(|e| e.to_error(self.ctx))?;
}
Instruction::DefLet(name_index) => {
let name = self.pool[name_index].to_string(self.ctx)?;

self.ctx
.realm_mut()
.environment
.create_mutable_binding(name.to_string(), false, VariableScope::Block)
.map_err(|e| e.to_error(self.ctx))?;
}
Instruction::DefConst(name_index) => {
let name = self.pool[name_index].to_string(self.ctx)?;

self.ctx
.realm_mut()
.environment
.create_immutable_binding(name.to_string(), false, VariableScope::Block)
.map_err(|e| e.to_error(self.ctx))?;
}
Instruction::InitLexical(name_index) => {
let name = self.pool[name_index].to_string(self.ctx)?;
let value = self.pop();
self.ctx
.realm_mut()
.environment
.initialize_binding(&name, value.clone())
.map_err(|e| e.to_error(self.ctx))?;

self.push(value);
}
}

idx += 1;
Expand Down

0 comments on commit 89419e2

Please sign in to comment.