mirror of https://github.com/boa-dev/boa.git
Jason Williams
6 years ago
1 changed files with 339 additions and 0 deletions
@ -0,0 +1,339 @@
|
||||
use ast::{ |
||||
CompEqual, CompGreaterThan, CompGreaterThanOrEqual, CompLessThan, CompLessThanOrEqual, |
||||
CompNotEqual, CompStrictEqual, CompStrictNotEqual, |
||||
}; |
||||
use ast::{LogAnd, LogOr}; |
||||
use ast::{OpAdd, OpDiv, OpMod, OpMul, OpSub}; |
||||
use ast::{UnaryMinus, UnaryNot}; |
||||
use collections::treemap::TreeMap; |
||||
use js::function::{RegularFunc, RegularFunction}; |
||||
use js::object::{ObjectData, INSTANCE_PROTOTYPE, PROTOTYPE}; |
||||
use js::value::{ |
||||
from_value, to_value, ResultValue, VBoolean, VFunction, VInteger, VNull, VNumber, VObject, |
||||
VString, VUndefined, Value, ValueData, |
||||
}; |
||||
use js::{array, console, error, function, json, math, number, object, string, uri}; |
||||
use std::cell::RefCell; |
||||
use std::gc::Gc; |
||||
use std::vec::Vec; |
||||
use syntax::ast::constant::Const; |
||||
use syntax::ast::expr::{Expr, ExprDef}; |
||||
use syntax::ast::op::{BinOp, BitOp, CompOp, LogOp, NumOp, Operator, UnaryOp}; |
||||
use syntax |
||||
|
||||
|
||||
/// An execution engine
|
||||
pub trait Executor { |
||||
/// Make a new execution engine
|
||||
fn new() -> Self; |
||||
/// Set a global variable called `name` with the value `val`
|
||||
fn set_global(&mut self, name: StrBuf, val: Value) -> Value; |
||||
/// Resolve the global variable `name`
|
||||
fn get_global(&self, name: StrBuf) -> Value; |
||||
/// Create a new scope and return it
|
||||
fn make_scope(&mut self) -> Gc<RefCell<ObjectData>>; |
||||
/// Destroy the current scope
|
||||
fn destroy_scope(&mut self) -> (); |
||||
/// Run an expression
|
||||
fn run(&mut self, expr: &Expr) -> ResultValue; |
||||
} |
||||
#[deriving(Clone)] |
||||
/// A Javascript intepreter
|
||||
pub struct Interpreter { |
||||
/// An object representing the global object
|
||||
global: Value, |
||||
/// The variable scopes
|
||||
scopes: Vec<Gc<RefCell<ObjectData>>>, |
||||
} |
||||
impl Executor for Interpreter { |
||||
fn new() -> Interpreter { |
||||
let global = ValueData::new_obj(None); |
||||
object::init(global); |
||||
console::init(global); |
||||
math::init(global); |
||||
array::init(global); |
||||
function::init(global); |
||||
json::init(global); |
||||
number::init(global); |
||||
error::init(global); |
||||
string::init(global); |
||||
uri::init(global); |
||||
Interpreter { |
||||
global: global, |
||||
scopes: Vec::new(), |
||||
} |
||||
} |
||||
fn set_global(&mut self, name: StrBuf, val: Value) -> Value { |
||||
self.global.borrow().set_field(name, val) |
||||
} |
||||
fn get_global(&self, name: StrBuf) -> Value { |
||||
self.global.borrow().get_field(name) |
||||
} |
||||
fn make_scope(&mut self) -> Gc<RefCell<ObjectData>> { |
||||
let value = Gc::new(RefCell::new(TreeMap::new())); |
||||
self.scopes.push(value.clone()); |
||||
value |
||||
} |
||||
fn destroy_scope(&mut self) -> () { |
||||
self.scopes.pop(); |
||||
} |
||||
fn run(&mut self, expr: &Expr) -> ResultValue { |
||||
match expr.def { |
||||
ConstExpr(CNull) => Ok(Gc::new(VNull)), |
||||
ConstExpr(CUndefined) => Ok(Gc::new(VUndefined)), |
||||
ConstExpr(CNum(num)) => Ok(to_value(num)), |
||||
ConstExpr(CInt(num)) => Ok(to_value(num)), |
||||
ConstExpr(CString(ref str)) => Ok(Gc::new(VString(StrBuf::from_str(str.as_slice())))), |
||||
ConstExpr(CBool(val)) => Ok(Gc::new(VBoolean(val))), |
||||
ConstExpr(CRegExp(_, _, _)) => Ok(Gc::new(VNull)), |
||||
BlockExpr(ref es) => { |
||||
let mut obj = Gc::new(VNull); |
||||
for e in es.iter() { |
||||
let val = try!(self.run(e)); |
||||
if e == es.last().unwrap() { |
||||
obj = val; |
||||
} |
||||
} |
||||
Ok(obj) |
||||
} |
||||
LocalExpr(ref name) => { |
||||
let mut value = Gc::new(VUndefined); |
||||
for scope in self.scopes.iter().rev() { |
||||
match scope.borrow().borrow().find(name) { |
||||
Some(v) => { |
||||
value = v.value.clone(); |
||||
break; |
||||
} |
||||
None => (), |
||||
} |
||||
} |
||||
Ok(if value.borrow().is_undefined() { |
||||
self.global.borrow().get_field(name.clone()) |
||||
} else { |
||||
value |
||||
}) |
||||
} |
||||
GetConstFieldExpr(ref obj, ref field) => { |
||||
let val_obj = try!(self.run(*obj)); |
||||
Ok(val_obj.borrow().get_field(field.clone())) |
||||
} |
||||
GetFieldExpr(ref obj, ref field) => { |
||||
let val_obj = try!(self.run(*obj)); |
||||
let val_field = try!(self.run(*field)); |
||||
Ok(val_obj.borrow().get_field(val_field.borrow().to_str())) |
||||
} |
||||
CallExpr(ref callee, ref args) => { |
||||
let (this, func) = match callee.def { |
||||
GetConstFieldExpr(ref obj, ref field) => { |
||||
let obj = try!(self.run(*obj)); |
||||
(obj, obj.borrow().get_field(field.clone())) |
||||
} |
||||
GetFieldExpr(ref obj, ref field) => { |
||||
let obj = try!(self.run(*obj)); |
||||
let field = try!(self.run(*field)); |
||||
(obj, obj.borrow().get_field(field.borrow().to_str())) |
||||
} |
||||
_ => (self.global.clone(), try!(self.run(callee.clone()))), |
||||
}; |
||||
let mut v_args = Vec::with_capacity(args.len()); |
||||
for arg in args.iter() { |
||||
v_args.push(try!(self.run(arg))); |
||||
} |
||||
match *func.borrow() { |
||||
VFunction(ref func) => func.borrow().call(self, this, Gc::new(VNull), v_args), |
||||
_ => Err(Gc::new(VUndefined)), |
||||
} |
||||
} |
||||
WhileLoopExpr(ref cond, ref expr) => { |
||||
let mut result = Gc::new(VUndefined); |
||||
while try!(self.run(*cond)).borrow().is_true() { |
||||
result = try!(self.run(*expr)); |
||||
} |
||||
Ok(result) |
||||
} |
||||
IfExpr(ref cond, ref expr, None) => Ok(if try!(self.run(*cond)).borrow().is_true() { |
||||
try!(self.run(*expr)) |
||||
} else { |
||||
Gc::new(VUndefined) |
||||
}), |
||||
IfExpr(ref cond, ref expr, Some(ref else_e)) => { |
||||
Ok(if try!(self.run(*cond)).borrow().is_true() { |
||||
try!(self.run(*expr)) |
||||
} else { |
||||
try!(self.run(*else_e)) |
||||
}) |
||||
} |
||||
SwitchExpr(ref val_e, ref vals, ref default) => { |
||||
let val = try!(self.run(*val_e)).borrow().clone(); |
||||
let mut result = Gc::new(VNull); |
||||
let mut matched = false; |
||||
for tup in vals.iter() { |
||||
let tup: &(Expr, Vec<Expr>) = tup; |
||||
match *tup { |
||||
(ref cond, ref block) if (val == *try!(self.run(cond)).borrow()) => { |
||||
matched = true; |
||||
let last_expr = block.last().unwrap(); |
||||
for expr in block.iter() { |
||||
let e_result = try!(self.run(expr)); |
||||
if expr == last_expr { |
||||
result = e_result; |
||||
} |
||||
} |
||||
} |
||||
_ => (), |
||||
} |
||||
} |
||||
if !matched && default.is_some() { |
||||
result = try!(self.run(*default.as_ref().unwrap())); |
||||
} |
||||
Ok(result) |
||||
} |
||||
ObjectDeclExpr(ref map) => { |
||||
let obj = ValueData::new_obj(Some(self.global)); |
||||
for (key, val) in map.iter() { |
||||
obj.borrow().set_field(key.clone(), try!(self.run(val))); |
||||
} |
||||
Ok(obj) |
||||
} |
||||
ArrayDeclExpr(ref arr) => { |
||||
let arr_map = ValueData::new_obj(Some(self.global)); |
||||
let mut index: i32 = 0; |
||||
for val in arr.iter() { |
||||
let val = try!(self.run(val)); |
||||
arr_map.borrow().set_field(index.to_str(), val); |
||||
index += 1; |
||||
} |
||||
arr_map.borrow().set_field_slice( |
||||
INSTANCE_PROTOTYPE, |
||||
self.get_global("Array".into_strbuf()) |
||||
.borrow() |
||||
.get_field_slice(PROTOTYPE), |
||||
); |
||||
arr_map.borrow().set_field_slice("length", to_value(index)); |
||||
Ok(arr_map) |
||||
} |
||||
FunctionDeclExpr(ref name, ref args, ref expr) => { |
||||
let function = RegularFunc(RegularFunction::new(*expr.clone(), args.clone())); |
||||
let val = Gc::new(VFunction(RefCell::new(function))); |
||||
if name.is_some() { |
||||
self.global.borrow().set_field(name.clone().unwrap(), val); |
||||
} |
||||
Ok(val) |
||||
} |
||||
ArrowFunctionDeclExpr(ref args, ref expr) => { |
||||
let function = RegularFunc(RegularFunction::new(*expr.clone(), args.clone())); |
||||
Ok(Gc::new(VFunction(RefCell::new(function)))) |
||||
} |
||||
BinOpExpr(BinNum(ref op), ref a, ref b) => { |
||||
let v_r_a = try!(self.run(*a)); |
||||
let v_r_b = try!(self.run(*b)); |
||||
let v_a = v_r_a.borrow(); |
||||
let v_b = v_r_b.borrow(); |
||||
Ok(Gc::new(match *op { |
||||
OpAdd => *v_a + *v_b, |
||||
OpSub => *v_a - *v_b, |
||||
OpMul => *v_a * *v_b, |
||||
OpDiv => *v_a / *v_b, |
||||
OpMod => *v_a % *v_b, |
||||
})) |
||||
} |
||||
UnaryOpExpr(ref op, ref a) => { |
||||
let v_r_a = try!(self.run(*a)); |
||||
let v_a = v_r_a.borrow(); |
||||
Ok(match *op { |
||||
UnaryMinus => to_value(-v_a.to_num()), |
||||
UnaryNot => Gc::new(!v_a), |
||||
_ => unreachable!(), |
||||
}) |
||||
} |
||||
BinOpExpr(BinBit(ref op), ref a, ref b) => { |
||||
let v_r_a = try!(self.run(*a)); |
||||
let v_r_b = try!(self.run(*b)); |
||||
let v_a = v_r_a.borrow(); |
||||
let v_b = v_r_b.borrow(); |
||||
Ok(Gc::new(match *op { |
||||
BitAnd => *v_a & *v_b, |
||||
BitOr => *v_a | *v_b, |
||||
BitXor => *v_a ^ *v_b, |
||||
BitShl => *v_a << *v_b, |
||||
BitShr => *v_a >> *v_b, |
||||
})) |
||||
} |
||||
BinOpExpr(BinComp(ref op), ref a, ref b) => { |
||||
let v_r_a = try!(self.run(*a)); |
||||
let v_r_b = try!(self.run(*b)); |
||||
let v_a = v_r_a.borrow(); |
||||
let v_b = v_r_b.borrow(); |
||||
Ok(to_value(match *op { |
||||
CompEqual if v_a.is_object() => v_r_a.ptr_eq(&v_r_b), |
||||
CompEqual => v_a == v_b, |
||||
CompNotEqual if v_a.is_object() => !v_r_a.ptr_eq(&v_r_b), |
||||
CompNotEqual => v_a != v_b, |
||||
CompStrictEqual if v_a.is_object() => v_r_a.ptr_eq(&v_r_b), |
||||
CompStrictEqual => v_a == v_b, |
||||
CompStrictNotEqual if v_a.is_object() => !v_r_a.ptr_eq(&v_r_b), |
||||
CompStrictNotEqual => v_a != v_b, |
||||
CompGreaterThan => v_a.to_num() > v_b.to_num(), |
||||
CompGreaterThanOrEqual => v_a.to_num() >= v_b.to_num(), |
||||
CompLessThan => v_a.to_num() < v_b.to_num(), |
||||
CompLessThanOrEqual => v_a.to_num() <= v_b.to_num(), |
||||
})) |
||||
} |
||||
BinOpExpr(BinLog(ref op), ref a, ref b) => { |
||||
let v_a = from_value::<bool>(try!(self.run(*a))).unwrap(); |
||||
let v_b = from_value::<bool>(try!(self.run(*b))).unwrap(); |
||||
Ok(match *op { |
||||
LogAnd => to_value(v_a && v_b), |
||||
LogOr => to_value(v_a || v_b), |
||||
}) |
||||
} |
||||
ConstructExpr(ref callee, ref args) => { |
||||
let func = try!(self.run(*callee)); |
||||
let mut v_args = Vec::with_capacity(args.len()); |
||||
for arg in args.iter() { |
||||
v_args.push(try!(self.run(arg))); |
||||
} |
||||
let this = Gc::new(VObject(RefCell::new(TreeMap::new()))); |
||||
this.borrow() |
||||
.set_field_slice(INSTANCE_PROTOTYPE, func.borrow().get_field_slice(PROTOTYPE)); |
||||
Ok(match *func.borrow() { |
||||
VFunction(ref func) => { |
||||
try!(func.borrow().call(self, this, Gc::new(VNull), v_args)); |
||||
this |
||||
} |
||||
_ => Gc::new(VUndefined), |
||||
}) |
||||
} |
||||
ReturnExpr(ref ret) => match *ret { |
||||
Some(ref v) => self.run(*v), |
||||
None => Ok(Gc::new(VUndefined)), |
||||
}, |
||||
ThrowExpr(ref ex) => Err(try!(self.run(*ex))), |
||||
AssignExpr(ref ref_e, ref val_e) => { |
||||
let val = try!(self.run(*val_e)); |
||||
match ref_e.def { |
||||
LocalExpr(ref name) => { |
||||
self.global.borrow().set_field(name.clone(), val); |
||||
} |
||||
GetConstFieldExpr(ref obj, ref field) => { |
||||
let val_obj = try!(self.run(*obj)); |
||||
val_obj.borrow().set_field(field.clone(), val); |
||||
} |
||||
_ => (), |
||||
} |
||||
Ok(val) |
||||
} |
||||
TypeOfExpr(ref val_e) => { |
||||
let val = try!(self.run(*val_e)); |
||||
Ok(to_value(match *val.borrow() { |
||||
VUndefined => "undefined", |
||||
VNull | VObject(_) => "object", |
||||
VBoolean(_) => "boolean", |
||||
VNumber(_) | VInteger(_) => "number", |
||||
VString(_) => "string", |
||||
VFunction(_) => "function", |
||||
})) |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue