Skip to content

Commit

Permalink
Divide the run() function (#422)
Browse files Browse the repository at this point in the history
Co-authored-by: Iban Eguia <[email protected]>
  • Loading branch information
Paul Lancaster and Razican authored Jun 6, 2020
1 parent d847ff8 commit 84574b5
Show file tree
Hide file tree
Showing 50 changed files with 1,404 additions and 760 deletions.
19 changes: 19 additions & 0 deletions boa/src/exec/conditional/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use super::{Executable, Interpreter};
use crate::{
builtins::{ResultValue, Value},
syntax::ast::node::If,
};
use std::borrow::Borrow;

impl Executable for If {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
Ok(if self.cond().run(interpreter)?.borrow().is_true() {
self.body().run(interpreter)?
} else {
match self.else_node() {
Some(ref else_e) => else_e.run(interpreter)?,
None => Value::undefined(),
}
})
}
}
14 changes: 7 additions & 7 deletions boa/src/exec/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ impl Executable for Call {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let _timer = BoaProfiler::global().start_event("Call", "exec");
let (mut this, func) = match self.expr() {
Node::GetConstField(ref obj, ref field) => {
let mut obj = obj.run(interpreter)?;
Node::GetConstField(ref get_const_field) => {
let mut obj = get_const_field.obj().run(interpreter)?;
if obj.get_type() != "object" || obj.get_type() != "symbol" {
obj = interpreter
.to_object(&obj)
.expect("failed to convert to object");
}
(obj.clone(), obj.get_field(field))
(obj.clone(), obj.get_field(get_const_field.field()))
}
Node::GetField(ref obj, ref field) => {
let obj = obj.run(interpreter)?;
let field = field.run(interpreter)?;
(obj.clone(), obj.get_field(field))
Node::GetField(ref get_field) => {
let obj = get_field.obj().run(interpreter)?;
let field = get_field.field().run(interpreter)?;
(obj.clone(), obj.get_field(field.to_string()))
}
_ => (
interpreter.realm().global_obj.clone(),
Expand Down
27 changes: 27 additions & 0 deletions boa/src/exec/field/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use super::{Executable, Interpreter};
use crate::{
builtins::value::ResultValue,
syntax::ast::node::{GetConstField, GetField},
};

impl Executable for GetConstField {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let mut obj = self.obj().run(interpreter)?;
if obj.get_type() != "object" || obj.get_type() != "symbol" {
obj = interpreter
.to_object(&obj)
.expect("failed to convert to object");
}

Ok(obj.get_field(self.field()))
}
}

impl Executable for GetField {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let obj = self.obj().run(interpreter)?;
let field = self.field().run(interpreter)?;

Ok(obj.get_field(field.to_string()))
}
}
23 changes: 22 additions & 1 deletion boa/src/exec/iteration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use super::{Executable, Interpreter};
use crate::{
builtins::value::{ResultValue, Value},
environment::lexical_environment::new_declarative_environment,
syntax::ast::node::ForLoop,
syntax::ast::node::{DoWhileLoop, ForLoop, WhileLoop},
BoaProfiler,
};
use std::borrow::Borrow;

impl Executable for ForLoop {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
Expand Down Expand Up @@ -42,3 +43,23 @@ impl Executable for ForLoop {
Ok(Value::undefined())
}
}

impl Executable for WhileLoop {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let mut result = Value::undefined();
while self.cond().run(interpreter)?.borrow().is_true() {
result = self.expr().run(interpreter)?;
}
Ok(result)
}
}

impl Executable for DoWhileLoop {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let mut result = self.body().run(interpreter)?;
while self.cond().run(interpreter)?.borrow().is_true() {
result = self.body().run(interpreter)?;
}
Ok(result)
}
}
140 changes: 27 additions & 113 deletions boa/src/exec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@

mod array;
mod block;
mod conditional;
mod declaration;
mod exception;
mod expression;
mod field;
mod iteration;
mod object;
mod operator;
mod return_smt;
mod spread;
mod statement_list;
mod try_node;

mod switch;
#[cfg(test)]
mod tests;
mod throw;
mod try_node;

use crate::{
builtins::{
Expand All @@ -27,7 +33,7 @@ use crate::{
realm::Realm,
syntax::ast::{
constant::Const,
node::{FormalParameter, MethodDefinitionKind, Node, PropertyDefinition, StatementList},
node::{FormalParameter, Node, StatementList},
},
BoaProfiler,
};
Expand Down Expand Up @@ -391,10 +397,14 @@ impl Interpreter {
.set_mutable_binding(name.as_ref(), value.clone(), true);
Ok(value)
}
Node::GetConstField(ref obj, ref field) => Ok(obj.run(self)?.set_field(field, value)),
Node::GetField(ref obj, ref field) => {
Ok(obj.run(self)?.set_field(field.run(self)?, value))
}
Node::GetConstField(ref get_const_field_node) => Ok(get_const_field_node
.obj()
.run(self)?
.set_field(get_const_field_node.field(), value)),
Node::GetField(ref get_field) => Ok(get_field
.obj()
.run(self)?
.set_field(get_field.field().run(self)?, value)),
_ => panic!("TypeError: invalid assignment to {}", node),
}
}
Expand Down Expand Up @@ -422,100 +432,15 @@ impl Executable for Node {
.get_binding_value(name.as_ref());
Ok(val)
}
Node::GetConstField(ref obj, ref field) => {
let val_obj = obj.run(interpreter)?;
Ok(val_obj.borrow().get_field(field))
}
Node::GetField(ref obj, ref field) => {
let val_obj = obj.run(interpreter)?;
let val_field = field.run(interpreter)?;
Ok(val_obj.borrow().get_field(val_field.borrow().to_string()))
}
Node::GetConstField(ref get_const_field_node) => get_const_field_node.run(interpreter),
Node::GetField(ref get_field) => get_field.run(interpreter),
Node::Call(ref expr) => expr.run(interpreter),
Node::WhileLoop(ref cond, ref expr) => {
let mut result = Value::undefined();
while cond.run(interpreter)?.borrow().is_true() {
result = expr.run(interpreter)?;
}
Ok(result)
}
Node::DoWhileLoop(ref body, ref cond) => {
let mut result = body.run(interpreter)?;
while cond.run(interpreter)?.borrow().is_true() {
result = body.run(interpreter)?;
}
Ok(result)
}
Node::WhileLoop(ref while_loop) => while_loop.run(interpreter),
Node::DoWhileLoop(ref do_while) => do_while.run(interpreter),
Node::ForLoop(ref for_loop) => for_loop.run(interpreter),
Node::If(ref cond, ref expr, None) => {
Ok(if cond.run(interpreter)?.borrow().is_true() {
expr.run(interpreter)?
} else {
Value::undefined()
})
}
Node::If(ref cond, ref expr, Some(ref else_e)) => {
Ok(if cond.run(interpreter)?.borrow().is_true() {
expr.run(interpreter)?
} else {
else_e.run(interpreter)?
})
}
Node::Switch(ref val_e, ref vals, ref default) => {
let val = val_e.run(interpreter)?;
let mut result = Value::null();
let mut matched = false;
for tup in vals.iter() {
let cond = &tup.0;
let block = &tup.1;
if val.strict_equals(&cond.run(interpreter)?) {
matched = true;
let last_expr = block.last().expect("Block has no expressions");
for expr in block.iter() {
let e_result = expr.run(interpreter)?;
if expr == last_expr {
result = e_result;
}
}
}
}
if !matched {
if let Some(default) = default {
result = default.run(interpreter)?;
}
}
Ok(result)
}
Node::Object(ref properties) => {
let global_val = &interpreter
.realm()
.environment
.get_global_object()
.expect("Could not get the global object");
let obj = Value::new_object(Some(global_val));

// TODO: Implement the rest of the property types.
for property in properties.iter() {
match property {
PropertyDefinition::Property(key, value) => {
obj.borrow()
.set_field(&key.clone(), value.run(interpreter)?);
}
PropertyDefinition::MethodDefinition(kind, name, func) => {
if let MethodDefinitionKind::Ordinary = kind {
obj.borrow()
.set_field(&name.clone(), func.run(interpreter)?);
} else {
// TODO: Implement other types of MethodDefinitionKinds.
unimplemented!("other types of property method definitions.");
}
}
i => unimplemented!("{:?} type of property", i),
}
}

Ok(obj)
}
Node::If(ref if_smt) => if_smt.run(interpreter),
Node::Switch(ref switch) => switch.run(interpreter),
Node::Object(ref obj) => obj.run(interpreter),
Node::ArrayDecl(ref arr) => arr.run(interpreter),
// <https://tc39.es/ecma262/#sec-createdynamicfunction>
Node::FunctionDecl(ref decl) => decl.run(interpreter),
Expand All @@ -525,24 +450,13 @@ impl Executable for Node {
Node::BinOp(ref op) => op.run(interpreter),
Node::UnaryOp(ref op) => op.run(interpreter),
Node::New(ref call) => call.run(interpreter),
Node::Return(ref ret) => {
let result = match *ret {
Some(ref v) => v.run(interpreter),
None => Ok(Value::undefined()),
};
// Set flag for return
interpreter.is_return = true;
result
}
Node::Throw(ref ex) => Err(ex.run(interpreter)?),
Node::Return(ref ret) => ret.run(interpreter),
Node::Throw(ref throw) => throw.run(interpreter),
Node::Assign(ref op) => op.run(interpreter),
Node::VarDeclList(ref decl) => decl.run(interpreter),
Node::LetDeclList(ref decl) => decl.run(interpreter),
Node::ConstDeclList(ref decl) => decl.run(interpreter),
Node::Spread(ref node) => {
// TODO: for now we can do nothing but return the value as-is
node.run(interpreter)
}
Node::Spread(ref spread) => spread.run(interpreter),
Node::This => {
// Will either return `this` binding or undefined
Ok(interpreter.realm().environment.get_this_binding())
Expand Down
43 changes: 43 additions & 0 deletions boa/src/exec/object/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//! Object execution.

use super::{Executable, Interpreter};
use crate::{
builtins::value::{ResultValue, Value},
syntax::ast::node::MethodDefinitionKind,
syntax::ast::node::{Object, PropertyDefinition},
};

use std::borrow::Borrow;

impl Executable for Object {
fn run(&self, interpreter: &mut Interpreter) -> ResultValue {
let global_val = &interpreter
.realm()
.environment
.get_global_object()
.expect("Could not get the global object");
let obj = Value::new_object(Some(global_val));

// TODO: Implement the rest of the property types.
for property in self.properties().iter() {
match property {
PropertyDefinition::Property(key, value) => {
obj.borrow()
.set_field(&key.clone(), value.run(interpreter)?);
}
PropertyDefinition::MethodDefinition(kind, name, func) => {
if let MethodDefinitionKind::Ordinary = kind {
obj.borrow()
.set_field(&name.clone(), func.run(interpreter)?);
} else {
// TODO: Implement other types of MethodDefinitionKinds.
unimplemented!("other types of property method definitions.");
}
}
i => unimplemented!("{:?} type of property", i),
}
}

Ok(obj)
}
}
Loading

0 comments on commit 84574b5

Please sign in to comment.