Browse Source

working against f7a1d59bec384357ffdf2e0b3a52e8ef358cfefe

pull/5/head
Jason Williams 6 years ago
parent
commit
ecbcb9b52f
  1. 368
      src/lib/exec.rs
  2. 62
      src/lib/js/function.rs
  3. 106
      src/lib/js/math.rs
  4. 4
      src/lib/js/mod.rs
  5. 112
      src/lib/js/object.rs
  6. 4
      src/lib/js/string.rs
  7. 106
      src/lib/js/value.rs
  8. 2
      src/lib/lib.rs
  9. 6
      src/lib/syntax/ast/expr.rs

368
src/lib/exec.rs

@ -1,11 +1,16 @@
use gc::GcCell;
use js::object::ObjectData;
use js::value::{ResultValue, Value, ValueData};
use js::{function, json, object};
use gc::Gc;
use js::value::{to_value, ResultValue, Value, ValueData};
use js::{array, console, function, json, math, object, string};
use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::HashMap;
use syntax::ast::expr::Expr;
use syntax::ast::constant::Const;
use syntax::ast::expr::{Expr, ExprDef};
/// A variable scope
pub struct Scope {
/// The value of `this` in the scope
pub this: Value,
/// The variables declared in the scope
pub vars: Value,
}
/// An execution engine
pub trait Executor {
@ -16,29 +21,37 @@ pub trait Executor {
/// Resolve the global variable `name`
fn get_global(&self, name: String) -> Value;
/// Create a new scope and return it
fn make_scope(&mut self) -> GcCell<RefCell<ObjectData>>;
fn make_scope(&mut self, this: Value) -> Scope;
/// Destroy the current scope
fn destroy_scope(&mut self) -> ();
// fn run(&mut self, expr: &Expr) -> ResultValue;
fn destroy_scope(&mut self) -> Scope;
/// Run an expression
fn run(&mut self, expr: &Expr) -> ResultValue;
}
/// A Javascript intepreter
pub struct Interpreter {
/// An object representing the global object
global: Value,
/// The variable scopes
scopes: Vec<GcCell<RefCell<ObjectData>>>,
/// The scopes
pub scopes: Vec<Scope>,
}
impl Executor for Interpreter {
impl Executor<Expr> for Interpreter {
fn new() -> Interpreter {
let global = ValueData::new_obj(None);
let global = Value::new_obj(None);
object::init(global);
console::init(global);
math::init(global);
array::init(global);
function::init(global);
json::init(global);
string::init(global);
Interpreter {
global: global,
scopes: Vec::new(),
scopes: vec![Scope {
this: global,
vars: global,
}],
}
}
@ -50,13 +63,326 @@ impl Executor for Interpreter {
self.global.borrow().get_field(name)
}
fn make_scope(&mut self) -> GcCell<RefCell<ObjectData>> {
let value = GcCell::new(RefCell::new(HashMap::new()));
self.scopes.push(value.clone());
value
fn make_scope(&mut self, this: Value) -> Scope {
let scope = Scope {
this: this,
vars: Value::new_obj(None),
};
self.scopes.push(scope);
scope
}
fn destroy_scope(&mut self) -> Scope {
self.scopes.pop().unwrap()
}
fn compile<'a>(&self, expr: &'a Expr) -> &'a Expr {
expr
}
fn destroy_scope(&mut self) -> () {
self.scopes.pop();
fn run(&mut self, expr: &Expr) -> ResultValue {
match expr.def {
ExprDef::ConstExpr(Const::Null) => Ok(to_value(None)),
ExprDef::ConstExpr(Const::Undefined) => Ok(Value::undefined()),
ExprDef::ConstExpr(Const::Num(num)) => Ok(to_value(num)),
ExprDef::ConstExpr(Const::Int(num)) => Ok(to_value(num)),
ExprDef::ConstExpr(Const::String(str)) => Ok(to_value(str)),
ExprDef::ConstExpr(Const::Bool(val)) => Ok(to_value(val)),
ExprDef::ConstExpr(Const::RegExp(_, _, _)) => Ok(to_value(None)),
ExprDef::BlockExpr(ref es) => {
let mut obj = to_value(None);
for e in es.iter() {
let val = try!(self.run(e));
if e == es.last().unwrap() {
obj = val;
}
}
Ok(obj)
}
ExprDef::LocalExpr(ref name) => {
let mut val = Value::undefined();
for scope in self.scopes.iter().rev() {
let vars = scope.vars;
let vars_ptr = vars.borrow();
match *vars_ptr.ptr {
ValueData::Object(ref obj) => match obj.borrow().get(name) {
Some(v) => {
val = v.value;
break;
}
None => (),
},
_ => unreachable!(),
}
}
Ok(val)
}
ExprDef::GetConstFieldExpr(ref obj, ref field) => {
let val_obj = try!(self.run(obj));
Ok(val_obj.borrow().get_field(field.clone()))
}
ExprDef::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_string()))
}
ExprDef::CallExpr(ref callee, ref args) => {
let (this, func) = match callee.def {
ExprDef::GetConstFieldExpr(ref obj, ref field) => {
let obj = try!(self.run(obj));
(obj, obj.borrow().get_field(field.clone()))
}
ExprDef::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_string()))
}
_ => (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().ptr {
ValueData::Function(ref func) => match *func.borrow() {
NativeFunc(ref ntv) => {
let func = ntv.data;
func(this, try!(self.run(*callee)), v_args)
}
RegularFunc(ref data) => {
let scope = self.make_scope(this);
let scope_vars_ptr = scope.vars.borrow();
for i in range(0, data.args.len()) {
let name = data.args.get(i);
let expr = v_args.get(i);
scope_vars_ptr.set_field(name.clone(), *expr);
}
let result = self.run(&data.expr);
self.destroy_scope();
result
}
},
_ => 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(ValueData::Null);
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()),
UnaryPlus => 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));
match *func.borrow() {
VFunction(ref func) => match *func.borrow() {
NativeFunc(ref ntv) => {
let func = ntv.data;
func(this, try!(self.run(*callee)), v_args)
}
RegularFunc(ref data) => {
let scope = self.make_scope(this);
let scope_vars_ptr = scope.vars.borrow();
for i in range(0, data.args.len()) {
let name = data.args.get(i);
let expr = v_args.get(i);
scope_vars_ptr.set_field(name.clone(), *expr);
}
let result = self.run(&data.expr);
self.destroy_scope();
result
}
},
_ => Ok(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.scope().vars.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)
}
VarDeclExpr(ref vars) => {
let scope_vars = self.scope().vars;
let scope_vars_ptr = scope_vars.borrow();
for var in vars.iter() {
let (name, value) = var.clone();
let val = match value {
Some(v) => try!(self.run(&v)),
None => Gc::new(ValueData::Null),
};
scope_vars_ptr.set_field(name.clone(), val);
}
Ok(Gc::new(VUndefined))
}
TypeOfExpr(ref val_e) => {
let val = try!(self.run(*val_e));
Ok(to_value(match *val.borrow() {
VUndefined => "undefined",
ValueData::Null | VObject(_) => "object",
VBoolean(_) => "boolean",
VNumber(_) | VInteger(_) => "number",
VString(_) => "string",
VFunction(_) => "function",
}))
}
}
}
}

62
src/lib/js/function.rs

@ -1,51 +1,68 @@
use gc::{Gc, GcCell};
use gc::Gc;
use js::object::{ObjectData, Property};
use js::value::{to_value, ResultValue, Value, ValueData};
use std::collections::HashMap;
use std::iter::FromIterator;
use syntax::ast::expr::Expr;
pub type FunctionData = fn(Vec<Value>, Value, Value, Value) -> ResultValue;
pub type NativeFunctionData = fn(Value, Value, Vec<Value>) -> ResultValue;
/// A Javascript function
/// A member of the Object type that may be invoked as a subroutine
/// https://tc39.github.io/ecma262/#sec-terms-and-definitions-function
/// In our implementation, Function is extending Object by holding an object field which some extra data
/// A Javascript function
#[derive(Trace, Finalize, Debug)]
pub struct Function {
pub enum Function {
/// A native javascript function
NativeFunc(NativeFunction),
/// A regular javascript function
RegularFunc(RegularFunction),
}
/// Represents a regular javascript function in memory
#[derive(Trace, Finalize, Debug)]
pub struct RegularFunction {
/// The fields associated with the function
pub object: ObjectData,
/// This function's JIT representation
pub repr: FunctionData,
/// This function's expression
pub expr: Expr,
/// The argument names of the function
pub args: Vec<String>,
}
impl Function {
/// Make a new function
pub fn new(repr: FunctionData, args: Vec<String>) -> Function {
impl RegularFunction {
/// Make a new regular function
pub fn new(expr: Expr, args: Vec<String>) -> RegularFunction {
let mut obj = HashMap::new();
obj.insert(
"arguments".to_string(),
Property::from_value(to_value(args.len() as i32)),
Property::new(Gc::new(ValueData::Integer(args.len() as i32))),
);
Function {
RegularFunction {
object: obj,
repr: repr,
expr: expr,
args: args,
}
}
/// Create a function from function data and arguments
pub fn make(repr: FunctionData, args: &[&'static str]) -> Value {
Value {
ptr: Gc::new(ValueData::Function(GcCell::new(Function::new(
repr,
FromIterator::from_iter(args.iter().map(|arg| arg.to_string())),
)))),
}
#[derive(Trace, Finalize, Debug)]
/// Represents a native javascript function in memory
pub struct NativeFunction {
/// The fields associated with the function
pub object: ObjectData,
/// The callable function data
pub data: NativeFunctionData,
}
impl NativeFunction {
/// Make a new native function with the given function data
pub fn new(data: NativeFunctionData) -> NativeFunction {
let obj = HashMap::new();
NativeFunction {
object: obj,
data: data,
}
/// Call with some args
pub fn call(&self, args: Vec<Value>, global: Value, scope: Value, this: Value) -> ResultValue {
(self.repr)(args, global, scope, this)
}
}
@ -56,5 +73,6 @@ pub fn _create() -> Value {
}
/// Initialise the global object with the `Function` object
pub fn init(global: Value) {
global.set_field_slice("Function", _create());
let global_ptr = global.borrow();
global_ptr.set_field_slice("Function", _create(global));
}

106
src/lib/js/math.rs

@ -6,7 +6,9 @@ use std::f64;
/// Get the absolute value of a number
pub fn abs(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(to_value(if args.len() >= 1 {
from_value::<f64>(*args.get(0)).unwrap().abs()
from_value::<f64>(args.get(0).unwrap().clone())
.unwrap()
.abs()
} else {
f64::NAN
}))
@ -14,7 +16,9 @@ pub fn abs(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
/// Get the arccos of a number
pub fn acos(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(to_value(if args.len() >= 1 {
from_value::<f64>(*args.get(0)).unwrap().acos()
from_value::<f64>(args.get(0).unwrap().clone())
.unwrap()
.acos()
} else {
f64::NAN
}))
@ -22,7 +26,9 @@ pub fn acos(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
/// Get the arcsine of a number
pub fn asin(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(to_value(if args.len() >= 1 {
from_value::<f64>(*args.get(0)).unwrap().asin()
from_value::<f64>(args.get(0).unwrap().clone())
.unwrap()
.asin()
} else {
f64::NAN
}))
@ -30,7 +36,9 @@ pub fn asin(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
/// Get the arctangent of a number
pub fn atan(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(to_value(if args.len() >= 1 {
from_value::<f64>(*args.get(0)).unwrap().atan()
from_value::<f64>(args.get(0).unwrap().clone())
.unwrap()
.atan()
} else {
f64::NAN
}))
@ -38,9 +46,9 @@ pub fn atan(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
/// Get the arctangent of a numbers
pub fn atan2(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(to_value(if args.len() >= 1 {
from_value::<f64>(*args.get(0))
from_value::<f64>(args.get(0).unwrap().clone())
.unwrap()
.atan2(args.get(1).to_num())
.atan2(args.get(1).unwrap().to_num())
} else {
f64::NAN
}))
@ -48,7 +56,9 @@ pub fn atan2(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
/// Get the cubic root of a number
pub fn cbrt(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(to_value(if args.len() >= 1 {
from_value::<f64>(*args.get(0)).unwrap().cbrt()
from_value::<f64>(args.get(0).unwrap().clone())
.unwrap()
.cbrt()
} else {
f64::NAN
}))
@ -56,7 +66,9 @@ pub fn cbrt(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
/// Get lowest integer above a number
pub fn ceil(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(to_value(if args.len() >= 1 {
from_value::<f64>(*args.get(0)).unwrap().ceil()
from_value::<f64>(args.get(0).unwrap().clone())
.unwrap()
.ceil()
} else {
f64::NAN
}))
@ -64,7 +76,9 @@ pub fn ceil(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
/// Get the cosine of a number
pub fn cos(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(to_value(if args.len() >= 1 {
from_value::<f64>(*args.get(0)).unwrap().cos()
from_value::<f64>(args.get(0).unwrap().clone())
.unwrap()
.cos()
} else {
f64::NAN
}))
@ -72,7 +86,9 @@ pub fn cos(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
/// Get the power to raise the natural logarithm to get the number
pub fn exp(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(to_value(if args.len() >= 1 {
from_value::<f64>(*args.get(0)).unwrap().exp()
from_value::<f64>(args.get(0).unwrap().clone())
.unwrap()
.exp()
} else {
f64::NAN
}))
@ -80,7 +96,9 @@ pub fn exp(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
/// Get the highest integer below a number
pub fn floor(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(to_value(if args.len() >= 1 {
from_value::<f64>(*args.get(0)).unwrap().floor()
from_value::<f64>(args.get(0).unwrap().clone())
.unwrap()
.floor()
} else {
f64::NAN
}))
@ -88,7 +106,9 @@ pub fn floor(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
/// Get the natural logarithm of a number
pub fn log(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(to_value(if args.len() >= 1 {
from_value::<f64>(*args.get(0)).unwrap().log(f64::consts::E)
from_value::<f64>(args.get(0).unwrap().clone())
.unwrap()
.log(f64::consts::E)
} else {
f64::NAN
}))
@ -114,8 +134,8 @@ pub fn min(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
/// Raise a number to a power
pub fn pow(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(to_value(if args.len() >= 2 {
let num: f64 = from_value(*args.get(0)).unwrap();
let power: f64 = from_value(*args.get(1)).unwrap();
let num: f64 = from_value(args.get(0).unwrap().clone()).unwrap();
let power: f64 = from_value(args.get(1).unwrap().clone()).unwrap();
num.powf(power)
} else {
f64::NAN
@ -128,7 +148,9 @@ pub fn _random(_: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
/// Round a number to the nearest integer
pub fn round(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(to_value(if args.len() >= 1 {
from_value::<f64>(*args.get(0)).unwrap().round()
from_value::<f64>(args.get(0).unwrap().clone())
.unwrap()
.round()
} else {
f64::NAN
}))
@ -136,7 +158,9 @@ pub fn round(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
/// Get the sine of a number
pub fn sin(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(to_value(if args.len() >= 1 {
from_value::<f64>(*args.get(0)).unwrap().sin()
from_value::<f64>(args.get(0).unwrap().clone())
.unwrap()
.sin()
} else {
f64::NAN
}))
@ -144,7 +168,9 @@ pub fn sin(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
/// Get the square root of a number
pub fn sqrt(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(to_value(if args.len() >= 1 {
from_value::<f64>(*args.get(0)).unwrap().sqrt()
from_value::<f64>(args.get(0).unwrap().clone())
.unwrap()
.sqrt()
} else {
f64::NAN
}))
@ -152,7 +178,9 @@ pub fn sqrt(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
/// Get the tangent of a number
pub fn tan(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(to_value(if args.len() >= 1 {
from_value::<f64>(*args.get(0)).unwrap().tan()
from_value::<f64>(args.get(0).unwrap().clone())
.unwrap()
.tan()
} else {
f64::NAN
}))
@ -166,30 +194,30 @@ pub fn _create(global: Value) -> Value {
math.set_field_slice("LOG2E", to_value(f64::consts::LOG2_E));
math.set_field_slice("LOG10E", to_value(f64::consts::LOG10_E));
math.set_field_slice("SQRT1_2", to_value(0.5f64.sqrt()));
math.set_field_slice("SQRT2", to_value(f64::consts::SQRT2));
math.set_field_slice("SQRT2", to_value(f64::consts::SQRT_2));
math.set_field_slice("PI", to_value(f64::consts::PI));
math.set_field_slice("abs", Function::make(abs, ["num1", "num2"]));
math.set_field_slice("acos", Function::make(acos, ["num1", "num2"]));
math.set_field_slice("asin", Function::make(asin, ["num1", "num2"]));
math.set_field_slice("atan", Function::make(atan, ["num1", "num2"]));
math.set_field_slice("atan2", Function::make(atan2, ["num1", "num2"]));
math.set_field_slice("cbrt", Function::make(cbrt, ["num1", "num2"]));
math.set_field_slice("ceil", Function::make(ceil, ["num1", "num2"]));
math.set_field_slice("cos", Function::make(cos, ["num1", "num2"]));
math.set_field_slice("exp", Function::make(exp, ["num1", "num2"]));
math.set_field_slice("floor", Function::make(floor, ["num"]));
math.set_field_slice("log", Function::make(log, ["num1", "num2"]));
math.set_field_slice("max", Function::make(max, ["num1", "num2"]));
math.set_field_slice("min", Function::make(min, ["num1", "num2"]));
math.set_field_slice("pow", Function::make(pow, ["num1", "num2"]));
math.set_field_slice("random", Function::make(_random, []));
math.set_field_slice("round", Function::make(round, ["num"]));
math.set_field_slice("sin", Function::make(sin, ["num"]));
math.set_field_slice("sqrt", Function::make(sqrt, ["num"]));
math.set_field_slice("tan", Function::make(tan, ["num"]));
math.set_field_slice("abs", Function::make(abs, &["num1", "num2"]));
math.set_field_slice("acos", Function::make(acos, &["num1", "num2"]));
math.set_field_slice("asin", Function::make(asin, &["num1", "num2"]));
math.set_field_slice("atan", Function::make(atan, &["num1", "num2"]));
math.set_field_slice("atan2", Function::make(atan2, &["num1", "num2"]));
math.set_field_slice("cbrt", Function::make(cbrt, &["num1", "num2"]));
math.set_field_slice("ceil", Function::make(ceil, &["num1", "num2"]));
math.set_field_slice("cos", Function::make(cos, &["num1", "num2"]));
math.set_field_slice("exp", Function::make(exp, &["num1", "num2"]));
math.set_field_slice("floor", Function::make(floor, &["num"]));
math.set_field_slice("log", Function::make(log, &["num1", "num2"]));
math.set_field_slice("max", Function::make(max, &["num1", "num2"]));
math.set_field_slice("min", Function::make(min, &["num1", "num2"]));
math.set_field_slice("pow", Function::make(pow, &["num1", "num2"]));
math.set_field_slice("random", Function::make(_random, &[]));
math.set_field_slice("round", Function::make(round, &["num"]));
math.set_field_slice("sin", Function::make(sin, &["num"]));
math.set_field_slice("sqrt", Function::make(sqrt, &["num"]));
math.set_field_slice("tan", Function::make(tan, &["num"]));
math
}
/// Initialise the `Math` object on the global object
pub fn init(global: Value) {
global.set_field_slice("Math", _create(global));
global.set_field_slice("Math", _create(global.clone()));
}

4
src/lib/js/mod.rs

@ -8,7 +8,11 @@ pub mod error;
pub mod function;
/// The global `JSON` object
pub mod json;
/// The global `Math` object
pub mod math;
/// The global `Object` object
pub mod object;
/// The global `String` object
pub mod string;
/// Javascript values, utility methods and conversion between Javascript values and Rust values
pub mod value;

112
src/lib/js/object.rs

@ -1,4 +1,5 @@
use js::value::Value;
use js::function::Function;
use js::value::{from_value, to_value, FromValue, ResultValue, ToValue, Value};
use std::collections::HashMap;
pub static PROTOTYPE: &'static str = "prototype";
pub static INSTANCE_PROTOTYPE: &'static str = "__proto__";
@ -26,26 +27,113 @@ pub struct Property {
impl Property {
/// Make a new property with the given value
pub fn new() -> Property {
pub fn new(value: Value) -> Property {
Property {
configurable: false,
enumerable: false,
writable: false,
value: Value::undefined(),
value: value,
get: Value::undefined(),
set: Value::undefined(),
}
}
}
/// Make a new property with the given value
pub fn from_value(value: Value) -> Property {
Property {
configurable: false,
enumerable: false,
writable: false,
value: value,
get: Value::undefined(),
set: Value::undefined(),
impl ToValue for Property {
fn to_value(&self) -> Value {
let prop = Value::new_obj(None);
prop.set_field_slice("configurable", to_value(self.configurable));
prop.set_field_slice("enumerable", to_value(self.enumerable));
prop.set_field_slice("writable", to_value(self.writable));
prop.set_field_slice("value", self.value.clone());
prop.set_field_slice("get", self.get.clone());
prop.set_field_slice("set", self.set.clone());
prop
}
}
impl FromValue for Property {
fn from_value(v: Value) -> Result<Property, &'static str> {
Ok(Property {
configurable: from_value(v.get_field_slice("configurable")).unwrap(),
enumerable: from_value(v.get_field_slice("enumerable")).unwrap(),
writable: from_value(v.get_field_slice("writable")).unwrap(),
value: v.get_field_slice("value"),
get: v.get_field_slice("get"),
set: v.get_field_slice("set"),
})
}
}
/// Create a new object
pub fn make_object(_: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
Ok(Value::undefined())
}
/// Get the prototype of an object
pub fn get_proto_of(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
let obj = args.get(0).unwrap();
Ok(obj.get_field_slice(INSTANCE_PROTOTYPE))
}
/// Set the prototype of an object
pub fn set_proto_of(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
let obj = args.get(0).unwrap().clone();
let proto = args.get(1).unwrap().clone();
obj.set_field_slice(INSTANCE_PROTOTYPE, proto);
Ok(obj)
}
/// Define a property in an object
pub fn define_prop(args: Vec<Value>, _: Value, _: Value, _: Value) -> ResultValue {
let obj = args.get(0).unwrap();
let prop = from_value::<String>(args.get(1).unwrap().clone()).unwrap();
let desc = from_value::<Property>(args.get(2).unwrap().clone()).unwrap();
obj.set_prop(prop, desc);
Ok(Value::undefined())
}
/// To string
pub fn to_string(_: Vec<Value>, _: Value, _: Value, this: Value) -> ResultValue {
Ok(to_value(this.to_string()))
}
/// Check if it has a property
pub fn has_own_prop(args: Vec<Value>, _: Value, _: Value, this: Value) -> ResultValue {
let prop = if args.len() == 0 {
None
} else {
from_value::<String>(args.get(0).unwrap().clone()).ok()
};
Ok(to_value(
prop.is_some() && this.get_prop(prop.unwrap()).is_some(),
))
}
/// Create a new `Object` object
pub fn _create(global: Value) -> Value {
let object = Function::make(make_object, &[]);
let prototype = Value::new_obj(Some(global));
prototype.set_field_slice(
"hasOwnProperty",
Function::make(has_own_prop, &["property"]),
);
prototype.set_field_slice("toString", Function::make(to_string, &[]));
object.set_field_slice("length", to_value(1i32));
object.set_field_slice(PROTOTYPE, prototype);
object.set_field_slice(
"setPrototypeOf",
Function::make(get_proto_of, &["object", "prototype"]),
);
object.set_field_slice("getPrototypeOf", Function::make(get_proto_of, &["object"]));
object.set_field_slice(
"defineProperty",
Function::make(define_prop, &["object", "property"]),
);
object
}
/// Initialise the `Object` object on the global object
pub fn init(global: Value) {
global.set_field_slice("Object", _create(global.clone()));
}

4
src/lib/js/string.rs

@ -14,14 +14,14 @@ pub fn get_string_length(_: Vec<Value>, _: Value, _: Value, this: Value) -> Resu
}
/// Create a new `String` object
pub fn _create(global: Value) -> Value {
let string = Function::make(make_string, ["string"]);
let string = Function::make(make_string, &["string"]);
let proto = Value::new_obj(Some(global));
let prop = Property {
configurable: false,
enumerable: false,
writable: false,
value: Value::undefined(),
get: Function::make(get_string_length, []),
get: Function::make(get_string_length, &[]),
set: Value::undefined(),
};
proto.set_prop_slice("length", prop);

106
src/lib/js/value.rs

@ -9,16 +9,13 @@ use std::f64::NAN;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::iter::FromIterator;
use std::ops::Deref;
use std::ops::DerefMut;
use std::str::FromStr;
/// The result of a Javascript expression is represented like this so it can succeed (`Ok`) or fail (`Err`)
pub type ResultValue = Result<Value, Value>;
/// A Garbage-collected Javascript value as represented in the interpreter
#[derive(Trace, Finalize, Clone, Debug)]
pub struct Value {
/// The garbage-collected pointer
pub ptr: Gc<ValueData>,
}
pub type Value = Gc<ValueData>;
/// A Javascript value
#[derive(Trace, Finalize, Debug)]
@ -41,7 +38,7 @@ pub enum ValueData {
Function(GcCell<Function>),
}
impl Value {
impl ValueData {
/// Returns a new empty object
pub fn new_obj(global: Option<Value>) -> Value {
let mut obj: ObjectData = HashMap::new();
@ -50,19 +47,14 @@ impl Value {
.unwrap()
.get_field_slice("Object")
.get_field_slice(PROTOTYPE);
obj.insert(
INSTANCE_PROTOTYPE.to_string(),
Property::from_value(obj_proto),
);
}
Value {
ptr: Gc::new(ValueData::Object(GcCell::new(obj))),
obj.insert(INSTANCE_PROTOTYPE.to_string(), Property::new(obj_proto));
}
Gc::new(ValueData::Object(GcCell::new(obj)))
}
/// Returns true if the value is an object
pub fn is_object(&self) -> bool {
match *self.ptr {
match *self {
ValueData::Object(_) => true,
_ => false,
}
@ -70,7 +62,7 @@ impl Value {
/// Returns true if the value is undefined
pub fn is_undefined(&self) -> bool {
match *self.ptr {
match *self {
ValueData::Undefined => true,
_ => false,
}
@ -78,7 +70,7 @@ impl Value {
/// Returns true if the value is null
pub fn is_null(&self) -> bool {
match *self.ptr {
match *self {
ValueData::Null => true,
_ => false,
}
@ -86,7 +78,7 @@ impl Value {
/// Returns true if the value is null or undefined
pub fn is_null_or_undefined(&self) -> bool {
match *self.ptr {
match *self {
ValueData::Null | ValueData::Undefined => true,
_ => false,
}
@ -94,7 +86,7 @@ impl Value {
/// Returns true if the value is a 64-bit floating-point number
pub fn is_double(&self) -> bool {
match *self.ptr {
match *self {
ValueData::Number(_) => true,
_ => false,
}
@ -102,7 +94,7 @@ impl Value {
/// Returns true if the value is a string
pub fn is_string(&self) -> bool {
match *self.ptr {
match *self {
ValueData::String(_) => true,
_ => false,
}
@ -111,7 +103,7 @@ impl Value {
/// Returns true if the value is true
/// [toBoolean](https://tc39.github.io/ecma262/#sec-toboolean)
pub fn is_true(&self) -> bool {
match *self.ptr {
match *self {
ValueData::Object(_) => true,
ValueData::String(ref s) if !s.is_empty() => true,
ValueData::Number(n) if n >= 1.0 && n % 1.0 == 0.0 => true,
@ -123,7 +115,7 @@ impl Value {
/// Converts the value into a 64-bit floating point number
pub fn to_num(&self) -> f64 {
match *self.ptr {
match *self {
ValueData::Object(_) | ValueData::Undefined | ValueData::Function(_) => NAN,
ValueData::String(ref str) => match FromStr::from_str(str) {
Ok(num) => num,
@ -138,7 +130,7 @@ impl Value {
/// Converts the value into a 32-bit integer
pub fn to_int(&self) -> i32 {
match *self.ptr {
match *self {
ValueData::Object(_)
| ValueData::Undefined
| ValueData::Null
@ -157,7 +149,7 @@ impl Value {
/// Resolve the property in the object
/// Returns a copy of the Property
pub fn get_prop(&self, field: String) -> Option<Property> {
let obj: ObjectData = match *self.ptr {
let obj: ObjectData = match *self {
ValueData::Object(ref obj) => {
let hash = obj.clone();
hash.into_inner()
@ -179,9 +171,7 @@ impl Value {
pub fn get_field(&self, field: String) -> Value {
match self.get_prop(field) {
Some(prop) => prop.value.clone(),
None => Value {
ptr: Gc::new(ValueData::Undefined),
},
None => Gc::new(ValueData::Undefined),
}
}
@ -192,15 +182,20 @@ impl Value {
/// Set the field in the value
pub fn set_field(&self, field: String, val: Value) -> Value {
match *self.ptr {
match *self {
ValueData::Object(ref obj) => {
obj.borrow_mut()
.insert(field.clone(), Property::from_value(val.clone()));
.insert(field.clone(), Property::new(val.clone()));
}
ValueData::Function(ref func) => {
func.borrow_mut()
.object
.insert(field.clone(), Property::from_value(val.clone()));
match *func.borrow_mut().deref_mut() {
Function::NativeFunc(ref mut f) => {
f.object.insert(field.clone(), Property::new(val))
}
Function::RegularFunc(ref mut f) => {
f.object.insert(field.clone(), Property::new(val))
}
};
}
_ => (),
}
@ -214,18 +209,26 @@ impl Value {
/// Set the property in the value
pub fn set_prop(&self, field: String, prop: Property) -> Property {
match *self.ptr {
match *self {
ValueData::Object(ref obj) => {
obj.borrow_mut().insert(field.clone(), prop.clone());
obj.borrow_mut().insert(field.clone(), prop);
}
ValueData::Function(ref func) => {
func.borrow_mut().object.insert(field.clone(), prop.clone());
match *func.borrow_mut().deref_mut() {
Function::NativeFunc(ref mut f) => f.object.insert(field.clone(), prop),
Function::RegularFunc(ref mut f) => f.object.insert(field.clone(), prop),
};
}
_ => (),
}
prop
}
/// Set the property in the value
pub fn set_prop_slice<'t>(&self, field: &'t str, prop: Property) -> Property {
self.set_prop(field.to_string(), prop)
}
/// Convert from a JSON value to a JS value
pub fn from_json(json: JSONValue) -> ValueData {
match json {
@ -238,19 +241,20 @@ impl Value {
i += 1;
(
(i - 1).to_string().to_string(),
Property::from_value(to_value(json.clone())),
Property::new(to_value(json.clone())),
)
}));
data.insert(
"length".to_string(),
Property::from_value(to_value(vs.len() as i32)),
Property::new(to_value(vs.len() as i32)),
);
ValueData::Object(GcCell::new(data))
}
JSONValue::Object(obj) => {
let data: ObjectData = FromIterator::from_iter(obj.iter().map(|(key, json)| {
(key.clone(), Property::from_value(to_value(json.clone())))
}));
let data: ObjectData = FromIterator::from_iter(
obj.iter()
.map(|(key, json)| (key.clone(), Property::new(to_value(json.clone())))),
);
ValueData::Object(GcCell::new(data))
}
JSONValue::Null => ValueData::Null,
@ -258,7 +262,7 @@ impl Value {
}
pub fn to_json(&self) -> JSONValue {
match *self.ptr {
match *self {
ValueData::Null | ValueData::Undefined => JSONValue::Null,
ValueData::Boolean(b) => JSONValue::Bool(b),
ValueData::Object(ref obj) => {
@ -279,7 +283,7 @@ impl Value {
/// Get the type of the value
pub fn get_type(&self) -> &'static str {
match *self.ptr {
match *self {
ValueData::Number(_) | ValueData::Integer(_) => "number",
ValueData::String(_) => "string",
ValueData::Boolean(_) => "boolean",
@ -288,17 +292,11 @@ impl Value {
_ => "object",
}
}
/// Get the value for undefined
pub fn undefined() -> Value {
Value {
ptr: Gc::new(ValueData::Undefined),
}
}
}
impl Display for Value {
impl Display for ValueData {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
match *self.ptr {
match *self {
ValueData::Null => write!(f, "null"),
ValueData::Undefined => write!(f, "undefined"),
ValueData::Boolean(v) => write!(f, "{}", v),
@ -337,7 +335,7 @@ impl Display for Value {
impl PartialEq for Value {
fn eq(&self, other: &Value) -> bool {
match (self.ptr.clone().deref(), other.ptr.clone().deref()) {
match (self.clone().deref(), other.clone().deref()) {
// TODO: fix this
// _ if self.ptr.to_inner() == &other.ptr.to_inner() => true,
_ if self.is_null_or_undefined() && other.is_null_or_undefined() => true,
@ -373,9 +371,7 @@ pub trait FromValue {
impl ToValue for String {
fn to_value(&self) -> Value {
Value {
ptr: Gc::new(ValueData::String(self.clone())),
}
Gc::new(ValueData::String(self.clone())),
}
}
@ -450,7 +446,7 @@ impl<'s, T: ToValue> ToValue for &'s [T] {
let mut arr = HashMap::new();
let mut i = 0;
for item in self.iter() {
arr.insert(i.to_string(), Property::from_value(item.to_value()));
arr.insert(i.to_string(), Property::new(item.to_value()));
i += 1;
}
to_value(arr)
@ -461,7 +457,7 @@ impl<T: ToValue> ToValue for Vec<T> {
let mut arr = HashMap::new();
let mut i = 0;
for item in self.iter() {
arr.insert(i.to_string(), Property::from_value(item.to_value()));
arr.insert(i.to_string(), Property::new(item.to_value()));
i += 1;
}
to_value(arr)

2
src/lib/lib.rs

@ -6,6 +6,6 @@ extern crate time;
#[macro_use]
extern crate gc_derive;
// pub mod exec;
pub mod exec;
pub mod js;
pub mod syntax;

6
src/lib/syntax/ast/expr.rs

@ -3,7 +3,7 @@ use std::fmt::{Display, Formatter, Result};
use syntax::ast::constant::Const;
use syntax::ast::op::{BinOp, Operator, UnaryOp};
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Trace, Debug, PartialEq)]
pub struct Expr {
/// The expression definition
pub def: ExprDef,
@ -12,9 +12,7 @@ pub struct Expr {
impl Expr {
/// Create a new expression with a starting and ending position
pub fn new(def: ExprDef) -> Expr {
Expr {
def: def,
}
Expr { def: def }
}
}

Loading…
Cancel
Save