Browse Source

VM: Implement variable declaration (var, const, and let) (#1030)

* 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>
pull/1049/head
Annika 4 years ago committed by GitHub
parent
commit
89419e202f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 40
      boa/src/vm/compilation.rs
  2. 13
      boa/src/vm/instructions.rs
  3. 41
      boa/src/vm/mod.rs

40
boa/src/vm/compilation.rs

@ -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!(),
}
}

13
boa/src/vm/instructions.rs

@ -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 {
@ -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
boa/src/vm/mod.rs

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

Loading…
Cancel
Save