From 582327da046e6bbe5ad50818bb9da13b5719895f Mon Sep 17 00:00:00 2001 From: Jason Williams Date: Thu, 1 Nov 2018 16:02:07 +0000 Subject: [PATCH] updates --- src/lib/exec.rs | 200 +++++++++++++++++---------------- src/lib/js/array.rs | 11 +- src/lib/js/console.rs | 24 ++-- src/lib/js/function.rs | 11 +- src/lib/js/json.rs | 12 +- src/lib/js/math.rs | 74 ++++++------ src/lib/js/object.rs | 52 ++++----- src/lib/js/string.rs | 19 ++-- src/lib/js/value.rs | 158 +++++++++++++++++++------- src/lib/syntax/ast/constant.rs | 2 +- src/lib/syntax/ast/expr.rs | 4 +- src/lib/syntax/ast/op.rs | 12 +- 12 files changed, 323 insertions(+), 256 deletions(-) diff --git a/src/lib/exec.rs b/src/lib/exec.rs index 5ac3e71b7a..65af058838 100644 --- a/src/lib/exec.rs +++ b/src/lib/exec.rs @@ -1,9 +1,13 @@ -use gc::Gc; -use js::value::{to_value, ResultValue, Value, ValueData}; +use gc::{Gc, GcCell}; +use js::function::{Function, RegularFunction}; +use js::object::{INSTANCE_PROTOTYPE, PROTOTYPE}; +use js::value::{from_value, to_value, ResultValue, Value, ValueData}; use js::{array, console, function, json, math, object, string}; use std::borrow::Borrow; +use std::collections::HashMap; use syntax::ast::constant::Const; use syntax::ast::expr::{Expr, ExprDef}; +use syntax::ast::op::BinOp; /// A variable scope pub struct Scope { /// The value of `this` in the scope @@ -36,9 +40,9 @@ pub struct Interpreter { pub scopes: Vec, } -impl Executor for Interpreter { +impl Executor for Interpreter { fn new() -> Interpreter { - let global = Value::new_obj(None); + let global = ValueData::new_obj(None); object::init(global); console::init(global); math::init(global); @@ -66,7 +70,7 @@ impl Executor for Interpreter { fn make_scope(&mut self, this: Value) -> Scope { let scope = Scope { this: this, - vars: Value::new_obj(None), + vars: ValueData::new_obj(None), }; self.scopes.push(scope); scope @@ -76,14 +80,10 @@ impl Executor for Interpreter { self.scopes.pop().unwrap() } - fn compile<'a>(&self, expr: &'a Expr) -> &'a Expr { - expr - } - 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::Undefined) => Ok(Gc::new(ValueData::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)), @@ -100,11 +100,11 @@ impl Executor for Interpreter { Ok(obj) } ExprDef::LocalExpr(ref name) => { - let mut val = Value::undefined(); + let mut val = Gc::new(ValueData::Undefined); for scope in self.scopes.iter().rev() { let vars = scope.vars; let vars_ptr = vars.borrow(); - match *vars_ptr.ptr { + match *vars_ptr.clone() { ValueData::Object(ref obj) => match obj.borrow().get(name) { Some(v) => { val = v.value; @@ -143,18 +143,18 @@ impl Executor for Interpreter { for arg in args.iter() { v_args.push(try!(self.run(arg))); } - match *func.borrow().ptr { + match *func { ValueData::Function(ref func) => match *func.borrow() { - NativeFunc(ref ntv) => { + Function::NativeFunc(ref ntv) => { let func = ntv.data; - func(this, try!(self.run(*callee)), v_args) + func(this, try!(self.run(callee)), v_args) } - RegularFunc(ref data) => { + Function::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); + for i in 0..data.args.len() { + let name = data.args.get(i).unwrap(); + let expr = v_args.get(i).unwrap(); scope_vars_ptr.set_field(name.clone(), *expr); } let result = self.run(&data.expr); @@ -162,30 +162,32 @@ impl Executor for Interpreter { result } }, - _ => Err(Gc::new(VUndefined)), + _ => Err(Gc::new(ValueData::Undefined)), } } - WhileLoopExpr(ref cond, ref expr) => { - let mut result = Gc::new(VUndefined); - while try!(self.run(*cond)).borrow().is_true() { - result = try!(self.run(*expr)); + ExprDef::WhileLoopExpr(ref cond, ref expr) => { + let mut result = Gc::new(ValueData::Undefined); + 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)) + ExprDef::IfExpr(ref cond, ref expr, None) => { + Ok(if try!(self.run(cond)).borrow().is_true() { + try!(self.run(expr)) } else { - try!(self.run(*else_e)) + Gc::new(ValueData::Undefined) }) } - SwitchExpr(ref val_e, ref vals, ref default) => { - let val = try!(self.run(*val_e)).borrow().clone(); + ExprDef::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)) + }) + } + ExprDef::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() { @@ -205,61 +207,63 @@ impl Executor for Interpreter { } } if !matched && default.is_some() { - result = try!(self.run(*default.as_ref().unwrap())); + result = try!(self.run(default.as_ref().unwrap())); } Ok(result) } - ObjectDeclExpr(ref map) => { + ExprDef::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) => { + ExprDef::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); + arr_map.borrow().set_field(index.to_string(), val); index += 1; } arr_map.borrow().set_field_slice( INSTANCE_PROTOTYPE, - self.get_global("Array".into_strbuf()) + self.get_global("Array".to_string()) .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))); + ExprDef::FunctionDeclExpr(ref name, ref args, ref expr) => { + let function = + Function::RegularFunc(RegularFunction::new(*expr.clone(), args.clone())); + let val = Gc::new(ValueData::Function(GcCell::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)))) + ExprDef::ArrowFunctionDeclExpr(ref args, ref expr) => { + let function = + Function::RegularFunc(RegularFunction::new(*expr.clone(), args.clone())); + Ok(Gc::new(ValueData::Function(GcCell::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(); + ExprDef::BinOpExpr(BinOp::Num(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; + let v_b = *v_r_b; 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, + 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)); + ExprDef::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()), @@ -268,32 +272,32 @@ impl Executor for Interpreter { _ => 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(); + ExprDef::BinOpExpr(BinOp::Bit(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; + let v_b = *v_r_b; 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, + 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)); + ExprDef::BinOpExpr(BinOp::Comp(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 if v_a.is_object() => v_r_a == v_r_b, CompEqual => v_a == v_b, - CompNotEqual if v_a.is_object() => !v_r_a.ptr_eq(&v_r_b), + CompNotEqual if v_a.is_object() => v_r_a != v_r_b, CompNotEqual => v_a != v_b, - CompStrictEqual if v_a.is_object() => v_r_a.ptr_eq(&v_r_b), + CompStrictEqual if v_a.is_object() => v_r_a == v_r_b, CompStrictEqual => v_a == v_b, - CompStrictNotEqual if v_a.is_object() => !v_r_a.ptr_eq(&v_r_b), + CompStrictNotEqual if v_a.is_object() => v_r_a != 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(), @@ -301,30 +305,30 @@ impl Executor for Interpreter { CompLessThanOrEqual => v_a.to_num() <= v_b.to_num(), })) } - BinOpExpr(BinLog(ref op), ref a, ref b) => { - let v_a = from_value::(try!(self.run(*a))).unwrap(); - let v_b = from_value::(try!(self.run(*b))).unwrap(); + ExprDef::BinOpExpr(BinOp::Log(ref op), ref a, ref b) => { + let v_a = from_value::(try!(self.run(a))).unwrap(); + let v_b = from_value::(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)); + ExprDef::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()))); + let this = Gc::new(ValueData::Object(GcCell::new(HashMap::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) => { + match *func { + ValueData::Function(ref func) => match *func { + Function::NativeFunc(ref ntv) => { let func = ntv.data; - func(this, try!(self.run(*callee)), v_args) + func(this, try!(self.run(callee)), v_args) } - RegularFunc(ref data) => { + Function::RegularFunc(ref data) => { let scope = self.make_scope(this); let scope_vars_ptr = scope.vars.borrow(); for i in range(0, data.args.len()) { @@ -337,16 +341,16 @@ impl Executor for Interpreter { result } }, - _ => Ok(Gc::new(VUndefined)), + _ => Ok(Gc::new(ValueData::Undefined)), } } - ReturnExpr(ref ret) => match *ret { - Some(ref v) => self.run(*v), - None => Ok(Gc::new(VUndefined)), + ExprDef::ReturnExpr(ref ret) => match *ret { + Some(ref v) => self.run(v), + None => Ok(Gc::new(ValueData::Undefined)), }, - ThrowExpr(ref ex) => Err(try!(self.run(*ex))), - AssignExpr(ref ref_e, ref val_e) => { - let val = try!(self.run(*val_e)); + ExprDef::ThrowExpr(ref ex) => Err(try!(self.run(*ex))), + ExprDef::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); @@ -359,7 +363,7 @@ impl Executor for Interpreter { } Ok(val) } - VarDeclExpr(ref vars) => { + ExprDef::VarDeclExpr(ref vars) => { let scope_vars = self.scope().vars; let scope_vars_ptr = scope_vars.borrow(); for var in vars.iter() { @@ -370,17 +374,17 @@ impl Executor for Interpreter { }; scope_vars_ptr.set_field(name.clone(), val); } - Ok(Gc::new(VUndefined)) + Ok(Gc::new(ValueData::Undefined)) } - TypeOfExpr(ref val_e) => { + ExprDef::TypeOfExpr(ref val_e) => { let val = try!(self.run(*val_e)); Ok(to_value(match *val.borrow() { - VUndefined => "undefined", + ValueData::Undefined => "undefined", ValueData::Null | VObject(_) => "object", VBoolean(_) => "boolean", VNumber(_) | VInteger(_) => "number", VString(_) => "string", - VFunction(_) => "function", + ValueData::Function(_) => "function", })) } } diff --git a/src/lib/js/array.rs b/src/lib/js/array.rs index 02882b1ff2..53bd8eec1a 100644 --- a/src/lib/js/array.rs +++ b/src/lib/js/array.rs @@ -1,14 +1,15 @@ -use js::function::Function; -use js::value::{to_value, ResultValue, Value}; +use gc::Gc; +use js::value::{to_value, ResultValue, Value, ValueData}; /// Create a new array pub fn make_array(_: Vec, _: Value, _: Value, this: Value) -> ResultValue { - this.set_field_slice("length", to_value(0i32)); - Ok(Value::undefined()) + let this_ptr = *this; + this_ptr.set_field_slice("length", to_value(0i32)); + Ok(Gc::new(ValueData::Undefined)) } /// Create a new `Array` object pub fn _create() -> Value { - let array = Function::make(make_array, &[]); + let array = to_value(make_array); array } /// Initialise the global object with the `Array` object diff --git a/src/lib/js/console.rs b/src/lib/js/console.rs index fe9361425b..80a09d9091 100644 --- a/src/lib/js/console.rs +++ b/src/lib/js/console.rs @@ -1,15 +1,13 @@ -use js::function::Function; -use js::value::{from_value, ResultValue, Value}; +use gc::Gc; +use js::value::{from_value, to_value, ResultValue, Value, ValueData}; use std::iter::FromIterator; use time::{now, strftime}; /// Print a javascript value to the standard output stream -pub fn log(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { - let args: Vec = FromIterator::from_iter( - args.iter() - .map(|x| from_value::(x.clone()).unwrap()), - ); +pub fn log(_: Value, _: Value, args: Vec) -> ResultValue { + let args: Vec = + FromIterator::from_iter(args.iter().map(|x| from_value::(*x).unwrap())); println!("{}: {}", strftime("%X", &now()).unwrap(), args.join(" ")); - Ok(Value::undefined()) + Ok(Gc::new(ValueData::Undefined)) } /// Print a javascript value to the standard error stream pub fn error(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { @@ -18,14 +16,14 @@ pub fn error(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { .map(|x| from_value::(x.clone()).unwrap()), ); eprintln!("{}: {}", strftime("%X", &now()).unwrap(), args.join(" ")); - Ok(Value::undefined()) + Ok(Gc::new(ValueData::Undefined)) } /// Create a new `console` object pub fn _create(global: Value) -> Value { - let console = Value::new_obj(Some(global)); - console.set_field_slice("log", Function::make(log, &["object"])); - console.set_field_slice("error", Function::make(error, &["error"])); - console.set_field_slice("exception", Function::make(error, &["error"])); + let console = ValueData::new_obj(Some(global)); + console.set_field_slice("log", to_value(log)); + console.set_field_slice("error", to_value(error)); + console.set_field_slice("exception", to_value(error)); console } /// Initialise the global object with the `console` object diff --git a/src/lib/js/function.rs b/src/lib/js/function.rs index 46c3707146..bf387aade8 100644 --- a/src/lib/js/function.rs +++ b/src/lib/js/function.rs @@ -4,7 +4,6 @@ use js::value::{to_value, ResultValue, Value, ValueData}; use std::collections::HashMap; use syntax::ast::expr::Expr; -pub type FunctionData = fn(Vec, Value, Value, Value) -> ResultValue; pub type NativeFunctionData = fn(Value, Value, Vec) -> ResultValue; /// A Javascript function /// A member of the Object type that may be invoked as a subroutine @@ -12,7 +11,7 @@ pub type NativeFunctionData = fn(Value, Value, Vec) -> ResultValue; /// In our implementation, Function is extending Object by holding an object field which some extra data /// A Javascript function -#[derive(Trace, Finalize, Debug)] +#[derive(Trace, Finalize, Debug, Clone)] pub enum Function { /// A native javascript function NativeFunc(NativeFunction), @@ -21,7 +20,7 @@ pub enum Function { } /// Represents a regular javascript function in memory -#[derive(Trace, Finalize, Debug)] +#[derive(Trace, Finalize, Debug, Clone)] pub struct RegularFunction { /// The fields associated with the function pub object: ObjectData, @@ -47,7 +46,7 @@ impl RegularFunction { } } -#[derive(Trace, Finalize, Debug)] +#[derive(Trace, Finalize, Debug, Clone)] /// Represents a native javascript function in memory pub struct NativeFunction { /// The fields associated with the function @@ -73,6 +72,6 @@ pub fn _create() -> Value { } /// Initialise the global object with the `Function` object pub fn init(global: Value) { - let global_ptr = global.borrow(); - global_ptr.set_field_slice("Function", _create(global)); + let global_ptr = &global; + global_ptr.set_field_slice("Function", _create()); } diff --git a/src/lib/js/json.rs b/src/lib/js/json.rs index b7494c9882..f11ec34439 100644 --- a/src/lib/js/json.rs +++ b/src/lib/js/json.rs @@ -1,19 +1,19 @@ use js::function::Function; /// The JSON Object /// https://tc39.github.io/ecma262/#sec-json-object -use js::value::{to_value, ResultValue, Value}; +use js::value::{to_value, ResultValue, Value, ValueData}; use serde_json::{self, to_string_pretty, Value as JSONValue}; /// Parse a JSON string into a Javascript object /// https://tc39.github.io/ecma262/#sec-json.parse -pub fn parse(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn parse(_: Value, _: Value, args: Vec) -> ResultValue { match serde_json::from_str::(&args.get(0).unwrap().clone().to_string()) { Ok(json) => Ok(to_value(json)), Err(err) => Err(to_value(err.to_string())), } } /// Process a Javascript object into a JSON string -pub fn stringify(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn stringify(_: Value, _: Value, args: Vec) -> ResultValue { let obj = args.get(0).unwrap(); let json = obj.to_json(); Ok(to_value(to_string_pretty(&json).unwrap())) @@ -21,9 +21,9 @@ pub fn stringify(args: Vec, _: Value, _: Value, _: Value) -> ResultValue /// Create a new `JSON` object pub fn _create(global: Value) -> Value { - let object = Value::new_obj(Some(global)); - object.set_field_slice("stringify", Function::make(stringify, &["JSON"])); - object.set_field_slice("parse", Function::make(parse, &["JSON_string"])); + let object = ValueData::new_obj(Some(global)); + object.set_field_slice("stringify", to_value(stringify)); + object.set_field_slice("parse", to_value(parse)); object } diff --git a/src/lib/js/math.rs b/src/lib/js/math.rs index c00b7728e8..52e61ab8d2 100644 --- a/src/lib/js/math.rs +++ b/src/lib/js/math.rs @@ -4,7 +4,7 @@ use rand::random; use std::f64; /// Get the absolute value of a number -pub fn abs(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn abs(_: Value, _: Value, args: Vec) -> ResultValue { Ok(to_value(if args.len() >= 1 { from_value::(args.get(0).unwrap().clone()) .unwrap() @@ -14,7 +14,7 @@ pub fn abs(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { })) } /// Get the arccos of a number -pub fn acos(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn acos(_: Value, _: Value, args: Vec) -> ResultValue { Ok(to_value(if args.len() >= 1 { from_value::(args.get(0).unwrap().clone()) .unwrap() @@ -24,7 +24,7 @@ pub fn acos(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { })) } /// Get the arcsine of a number -pub fn asin(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn asin(_: Value, _: Value, args: Vec) -> ResultValue { Ok(to_value(if args.len() >= 1 { from_value::(args.get(0).unwrap().clone()) .unwrap() @@ -34,7 +34,7 @@ pub fn asin(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { })) } /// Get the arctangent of a number -pub fn atan(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn atan(_: Value, _: Value, args: Vec) -> ResultValue { Ok(to_value(if args.len() >= 1 { from_value::(args.get(0).unwrap().clone()) .unwrap() @@ -44,7 +44,7 @@ pub fn atan(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { })) } /// Get the arctangent of a numbers -pub fn atan2(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn atan2(_: Value, _: Value, args: Vec) -> ResultValue { Ok(to_value(if args.len() >= 1 { from_value::(args.get(0).unwrap().clone()) .unwrap() @@ -54,7 +54,7 @@ pub fn atan2(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { })) } /// Get the cubic root of a number -pub fn cbrt(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn cbrt(_: Value, _: Value, args: Vec) -> ResultValue { Ok(to_value(if args.len() >= 1 { from_value::(args.get(0).unwrap().clone()) .unwrap() @@ -64,7 +64,7 @@ pub fn cbrt(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { })) } /// Get lowest integer above a number -pub fn ceil(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn ceil(_: Value, _: Value, args: Vec) -> ResultValue { Ok(to_value(if args.len() >= 1 { from_value::(args.get(0).unwrap().clone()) .unwrap() @@ -74,7 +74,7 @@ pub fn ceil(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { })) } /// Get the cosine of a number -pub fn cos(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn cos(_: Value, _: Value, args: Vec) -> ResultValue { Ok(to_value(if args.len() >= 1 { from_value::(args.get(0).unwrap().clone()) .unwrap() @@ -84,7 +84,7 @@ pub fn cos(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { })) } /// Get the power to raise the natural logarithm to get the number -pub fn exp(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn exp(_: Value, _: Value, args: Vec) -> ResultValue { Ok(to_value(if args.len() >= 1 { from_value::(args.get(0).unwrap().clone()) .unwrap() @@ -94,7 +94,7 @@ pub fn exp(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { })) } /// Get the highest integer below a number -pub fn floor(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn floor(_: Value, _: Value, args: Vec) -> ResultValue { Ok(to_value(if args.len() >= 1 { from_value::(args.get(0).unwrap().clone()) .unwrap() @@ -104,7 +104,7 @@ pub fn floor(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { })) } /// Get the natural logarithm of a number -pub fn log(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn log(_: Value, _: Value, args: Vec) -> ResultValue { Ok(to_value(if args.len() >= 1 { from_value::(args.get(0).unwrap().clone()) .unwrap() @@ -114,7 +114,7 @@ pub fn log(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { })) } /// Get the maximum of several numbers -pub fn max(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn max(_: Value, _: Value, args: Vec) -> ResultValue { let mut max = f64::NEG_INFINITY; for arg in args.iter() { let num = arg.to_num(); @@ -123,7 +123,7 @@ pub fn max(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { Ok(to_value(max)) } /// Get the minimum of several numbers -pub fn min(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn min(_: Value, _: Value, args: Vec) -> ResultValue { let mut max = f64::INFINITY; for arg in args.iter() { let num = arg.to_num(); @@ -132,7 +132,7 @@ pub fn min(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { Ok(to_value(max)) } /// Raise a number to a power -pub fn pow(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn pow(_: Value, _: Value, args: Vec) -> ResultValue { Ok(to_value(if args.len() >= 2 { let num: f64 = from_value(args.get(0).unwrap().clone()).unwrap(); let power: f64 = from_value(args.get(1).unwrap().clone()).unwrap(); @@ -146,7 +146,7 @@ pub fn _random(_: Vec, _: Value, _: Value, _: Value) -> ResultValue { Ok(to_value(random::())) } /// Round a number to the nearest integer -pub fn round(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn round(_: Value, _: Value, args: Vec) -> ResultValue { Ok(to_value(if args.len() >= 1 { from_value::(args.get(0).unwrap().clone()) .unwrap() @@ -156,7 +156,7 @@ pub fn round(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { })) } /// Get the sine of a number -pub fn sin(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn sin(_: Value, _: Value, args: Vec) -> ResultValue { Ok(to_value(if args.len() >= 1 { from_value::(args.get(0).unwrap().clone()) .unwrap() @@ -166,7 +166,7 @@ pub fn sin(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { })) } /// Get the square root of a number -pub fn sqrt(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn sqrt(_: Value, _: Value, args: Vec) -> ResultValue { Ok(to_value(if args.len() >= 1 { from_value::(args.get(0).unwrap().clone()) .unwrap() @@ -176,7 +176,7 @@ pub fn sqrt(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { })) } /// Get the tangent of a number -pub fn tan(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn tan(_: Value, _: Value, args: Vec) -> ResultValue { Ok(to_value(if args.len() >= 1 { from_value::(args.get(0).unwrap().clone()) .unwrap() @@ -196,25 +196,25 @@ pub fn _create(global: Value) -> Value { math.set_field_slice("SQRT1_2", to_value(0.5f64.sqrt())); 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", to_value(abs)); + math.set_field_slice("acos", to_value(acos)); + math.set_field_slice("asin", to_value(asin)); + math.set_field_slice("atan", to_value(atan)); + math.set_field_slice("atan2", to_value(atan2)); + math.set_field_slice("cbrt", to_value(cbrt)); + math.set_field_slice("ceil", to_value(ceil)); + math.set_field_slice("cos", to_value(cos)); + math.set_field_slice("exp", to_value(exp)); + math.set_field_slice("floor", to_value(floor, &["num"])); + math.set_field_slice("log", to_value(log)); + math.set_field_slice("max", to_value(max)); + math.set_field_slice("min", to_value(min)); + math.set_field_slice("pow", to_value(pow)); + math.set_field_slice("random", to_value(_random)); + math.set_field_slice("round", to_value(round)); + math.set_field_slice("sin", to_value(sin)); + math.set_field_slice("sqrt", to_value(sqrt)); + math.set_field_slice("tan", to_value(tan)); math } /// Initialise the `Math` object on the global object diff --git a/src/lib/js/object.rs b/src/lib/js/object.rs index e78f22b2d9..d1f0baeb8c 100644 --- a/src/lib/js/object.rs +++ b/src/lib/js/object.rs @@ -1,5 +1,5 @@ -use js::function::Function; -use js::value::{from_value, to_value, FromValue, ResultValue, ToValue, Value}; +use gc::Gc; +use js::value::{from_value, to_value, FromValue, ResultValue, ToValue, Value, ValueData}; use std::collections::HashMap; pub static PROTOTYPE: &'static str = "prototype"; pub static INSTANCE_PROTOTYPE: &'static str = "__proto__"; @@ -33,15 +33,15 @@ impl Property { enumerable: false, writable: false, value: value, - get: Value::undefined(), - set: Value::undefined(), + get: Gc::new(ValueData::Undefined), + set: Gc::new(ValueData::Undefined), } } } impl ToValue for Property { fn to_value(&self) -> Value { - let prop = Value::new_obj(None); + let prop = ValueData::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)); @@ -67,17 +67,17 @@ impl FromValue for Property { /// Create a new object pub fn make_object(_: Vec, _: Value, _: Value, _: Value) -> ResultValue { - Ok(Value::undefined()) + Ok(Gc::new(ValueData::Undefined)) } /// Get the prototype of an object -pub fn get_proto_of(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn get_proto_of(_: Value, _: Value, args: Vec) -> 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) -> ResultValue { +pub fn set_proto_of(_: Value, _: Value, args: Vec) -> ResultValue { let obj = args.get(0).unwrap().clone(); let proto = args.get(1).unwrap().clone(); obj.set_field_slice(INSTANCE_PROTOTYPE, proto); @@ -85,21 +85,21 @@ pub fn set_proto_of(args: Vec, _: Value, _: Value, _: Value) -> ResultVal } /// Define a property in an object -pub fn define_prop(args: Vec, _: Value, _: Value, _: Value) -> ResultValue { +pub fn define_prop(_: Value, _: Value, args: Vec) -> ResultValue { let obj = args.get(0).unwrap(); let prop = from_value::(args.get(1).unwrap().clone()).unwrap(); let desc = from_value::(args.get(2).unwrap().clone()).unwrap(); obj.set_prop(prop, desc); - Ok(Value::undefined()) + Ok(Gc::new(ValueData::Undefined)) } /// To string -pub fn to_string(_: Vec, _: Value, _: Value, this: Value) -> ResultValue { +pub fn to_string(this: Value, _: Value, _: Vec) -> ResultValue { Ok(to_value(this.to_string())) } /// Check if it has a property -pub fn has_own_prop(args: Vec, _: Value, _: Value, this: Value) -> ResultValue { +pub fn has_own_prop(this: Value, _: Value, args: Vec) -> ResultValue { let prop = if args.len() == 0 { None } else { @@ -112,24 +112,16 @@ pub fn has_own_prop(args: Vec, _: Value, _: Value, this: Value) -> Result /// 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"]), - ); + let object = to_value(make_object); + let object_ptr = object; + let prototype = ValueData::new_obj(Some(global)); + prototype.set_field_slice("hasOwnProperty", to_value(has_own_prop)); + prototype.set_field_slice("toString", to_value(to_string)); + object_ptr.set_field_slice("length", to_value(1i32)); + object_ptr.set_field_slice(PROTOTYPE, prototype); + object_ptr.set_field_slice("setPrototypeOf", to_value(set_proto_of)); + object_ptr.set_field_slice("getPrototypeOf", to_value(get_proto_of)); + object_ptr.set_field_slice("defineProperty", to_value(define_prop)); object } diff --git a/src/lib/js/string.rs b/src/lib/js/string.rs index 3c9eff16d9..713f3984d1 100644 --- a/src/lib/js/string.rs +++ b/src/lib/js/string.rs @@ -1,28 +1,29 @@ +use gc::Gc; use js::function::Function; use js::object::{Property, PROTOTYPE}; -use js::value::{from_value, to_value, ResultValue, Value}; +use js::value::{from_value, to_value, ResultValue, Value, ValueData}; /// Create new string -pub fn make_string(_: Vec, _: Value, _: Value, this: Value) -> ResultValue { +pub fn make_string(this: Value, _: Value, _: Vec) -> ResultValue { this.set_field_slice("length", to_value(0i32)); - Ok(Value::undefined()) + Ok(Gc::new(ValueData::Undefined)) } /// Get a string's length -pub fn get_string_length(_: Vec, _: Value, _: Value, this: Value) -> ResultValue { +pub fn get_string_length(this: Value, _: Value, _: Vec) -> ResultValue { let this_str: String = from_value(this).unwrap(); Ok(to_value::(this_str.len() as i32)) } /// Create a new `String` object pub fn _create(global: Value) -> Value { - let string = Function::make(make_string, &["string"]); - let proto = Value::new_obj(Some(global)); + let string = to_value(make_string); + let proto = ValueData::new_obj(Some(global)); let prop = Property { configurable: false, enumerable: false, writable: false, - value: Value::undefined(), - get: Function::make(get_string_length, &[]), - set: Value::undefined(), + value: Gc::new(ValueData::Undefined), + get: to_value(get_string_length), + set: Gc::new(ValueData::Undefined), }; proto.set_prop_slice("length", prop); string.set_field_slice(PROTOTYPE, proto); diff --git a/src/lib/js/value.rs b/src/lib/js/value.rs index e1e8fc6e4d..515276f713 100644 --- a/src/lib/js/value.rs +++ b/src/lib/js/value.rs @@ -1,17 +1,20 @@ use gc::{Gc, GcCell}; -use js::function::Function; +use js::function::{Function, NativeFunction, NativeFunctionData}; use js::object::{ObjectData, Property, INSTANCE_PROTOTYPE, PROTOTYPE}; use serde_json::map::Map; use serde_json::Number as JSONNumber; use serde_json::Value as JSONValue; use std::collections::HashMap; use std::f64::NAN; +use std::fmt; use std::fmt::{Display, Formatter, Result as FmtResult}; use std::iter::FromIterator; use std::ops::Deref; use std::ops::DerefMut; +use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Not, Rem, Shl, Shr, Sub}; use std::str::FromStr; +#[must_use] /// The result of a Javascript expression is represented like this so it can succeed (`Ok`) or fail (`Err`) pub type ResultValue = Result; /// A Garbage-collected Javascript value as represented in the interpreter @@ -295,7 +298,7 @@ impl ValueData { } impl Display for ValueData { - fn fmt(&self, f: &mut Formatter) -> FmtResult { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { ValueData::Null => write!(f, "null"), ValueData::Undefined => write!(f, "undefined"), @@ -305,10 +308,9 @@ impl Display for ValueData { f, "{}", match v { - // https://tc39.github.io/ecma262/#sec-tostring-applied-to-the-number-type _ if v.is_nan() => "NaN".to_string(), - _ if v.is_infinite() && v.is_sign_positive() => "Infinity".to_string(), - _ if v.is_infinite() && v.is_sign_negative() => "-Infinity".to_string(), + std::f64::INFINITY => "Infinity".to_string(), + std::f64::NEG_INFINITY => "-Infinity".to_string(), _ => v.to_string(), } ), @@ -317,7 +319,7 @@ impl Display for ValueData { match v.borrow().iter().last() { Some((last_key, _)) => { for (key, val) in v.borrow().iter() { - try!(write!(f, "{}: {}", key, val.value)); + try!(write!(f, "{}: {}", key, val.value.clone())); if key != last_key { try!(write!(f, "{}", ", ")); } @@ -328,13 +330,18 @@ impl Display for ValueData { write!(f, "{}", "}") } ValueData::Integer(v) => write!(f, "{}", v), - ValueData::Function(ref v) => write!(f, "function({})", v.borrow().args.join(", ")), + ValueData::Function(ref v) => match *v.borrow() { + Function::NativeFunc(_) => write!(f, "{}", "function() { [native code] }"), + Function::RegularFunc(rf) => { + write!(f, "function({}){}", rf.args.join(", "), rf.expr) + } + }, } } } -impl PartialEq for Value { - fn eq(&self, other: &Value) -> bool { +impl PartialEq for ValueData { + fn eq(&self, other: &ValueData) -> bool { match (self.clone().deref(), other.clone().deref()) { // TODO: fix this // _ if self.ptr.to_inner() == &other.ptr.to_inner() => true, @@ -356,6 +363,68 @@ impl PartialEq for Value { } } +impl Add for ValueData { + type Output = ValueData; + fn add(self, other: ValueData) -> ValueData { + return match (self, other) { + (ValueData::String(s), other) | (other, ValueData::String(s)) => { + ValueData::String(s.clone().append(other.to_string())) + } + (_, _) => ValueData::Number(self.to_num() + other.to_num()), + }; + } +} +impl Sub for ValueData { + fn sub(&self, other: &ValueData) -> ValueData { + ValueData::Number(self.to_num() - other.to_num()) + } +} +impl Mul for ValueData { + fn mul(&self, other: &ValueData) -> ValueData { + ValueData::Number(self.to_num() * other.to_num()) + } +} +impl Div for ValueData { + fn div(&self, other: &ValueData) -> ValueData { + ValueData::Number(self.to_num() / other.to_num()) + } +} +impl Rem for ValueData { + fn rem(&self, other: ValueData) -> ValueData { + ValueData::Number(self.to_num() % other.to_num()) + } +} +impl BitAnd for ValueData { + fn bitand(&self, other: ValueData) -> ValueData { + ValueData::Integer(self.to_int() & other.to_int()) + } +} +impl BitOr for ValueData { + fn bitor(&self, other: &ValueData) -> ValueData { + ValueData::Integer(self.to_int() | other.to_int()) + } +} +impl BitXor for ValueData { + fn bitxor(&self, other: &ValueData) -> ValueData { + ValueData::Integer(self.to_int() ^ other.to_int()) + } +} +impl Shl for ValueData { + fn shl(&self, other: &ValueData) -> ValueData { + ValueData::Integer(self.to_int() << other.to_int()) + } +} +impl Shr for ValueData { + fn shr(&self, other: &ValueData) -> ValueData { + ValueData::Integer(self.to_int() >> other.to_int()) + } +} +impl Not for ValueData { + fn not(&self) -> ValueData { + ValueData::Boolean(!self.is_true()) + } +} + /// Conversion to Javascript values from Rust values pub trait ToValue { /// Convert this value to a Rust value @@ -371,7 +440,7 @@ pub trait FromValue { impl ToValue for String { fn to_value(&self) -> Value { - Gc::new(ValueData::String(self.clone())), + Gc::new(ValueData::String(self.clone())) } } @@ -383,17 +452,13 @@ impl FromValue for String { impl<'s> ToValue for &'s str { fn to_value(&self) -> Value { - Value { - ptr: Gc::new(ValueData::String(String::from_str(*self).unwrap())), - } + Gc::new(ValueData::String(String::from_str(*self).unwrap())) } } impl ToValue for char { fn to_value(&self) -> Value { - Value { - ptr: Gc::new(ValueData::String(self.to_string())), - } + Gc::new(ValueData::String(self.to_string())) } } impl FromValue for char { @@ -404,9 +469,7 @@ impl FromValue for char { impl ToValue for f64 { fn to_value(&self) -> Value { - Value { - ptr: Gc::new(ValueData::Number(*self)), - } + Gc::new(ValueData::Number(*self)) } } impl FromValue for f64 { @@ -417,9 +480,7 @@ impl FromValue for f64 { impl ToValue for i32 { fn to_value(&self) -> Value { - Value { - ptr: Gc::new(ValueData::Integer(*self)), - } + Gc::new(ValueData::Integer(*self)) } } impl FromValue for i32 { @@ -430,9 +491,7 @@ impl FromValue for i32 { impl ToValue for bool { fn to_value(&self) -> Value { - Value { - ptr: Gc::new(ValueData::Boolean(*self)), - } + Gc::new(ValueData::Boolean(*self)) } } impl FromValue for bool { @@ -477,19 +536,18 @@ impl FromValue for Vec { impl ToValue for ObjectData { fn to_value(&self) -> Value { - Value { - ptr: Gc::new(ValueData::Object(GcCell::new(self.clone()))), - } + Gc::new(ValueData::Object(GcCell::new(self.clone()))) } } + impl FromValue for ObjectData { fn from_value(v: Value) -> Result { - match *v.ptr { - ValueData::Object(ref obj) => { - let obj_data = obj.clone().into_inner(); - Ok(obj_data) - } - ValueData::Function(ref func) => Ok(func.borrow().object.clone()), + match *v { + ValueData::Object(ref obj) => Ok(obj.clone().borrow().deref().clone()), + ValueData::Function(ref func) => Ok(match *func.borrow().deref() { + Function::NativeFunc(ref data) => data.object.clone(), + Function::RegularFunc(ref data) => data.object.clone(), + }), _ => Err("Value is not a valid object"), } } @@ -497,11 +555,10 @@ impl FromValue for ObjectData { impl ToValue for JSONValue { fn to_value(&self) -> Value { - Value { - ptr: Gc::new(Value::from_json(self.clone())), - } + Gc::new(ValueData::from_json(self.clone())) } } + impl FromValue for JSONValue { fn from_value(v: Value) -> Result { Ok(v.to_json()) @@ -510,9 +567,7 @@ impl FromValue for JSONValue { impl ToValue for () { fn to_value(&self) -> Value { - Value { - ptr: Gc::new(ValueData::Null), - } + Gc::new(ValueData::Null) } } impl FromValue for () { @@ -525,9 +580,7 @@ impl ToValue for Option { fn to_value(&self) -> Value { match *self { Some(ref v) => v.to_value(), - None => Value { - ptr: Gc::new(ValueData::Null), - }, + None => Gc::new(ValueData::Null), } } } @@ -541,6 +594,25 @@ impl FromValue for Option { } } +impl ToValue for NativeFunctionData { + fn to_value(&self) -> Value { + Gc::new(ValueData::Function(GcCell::new(Function::NativeFunc( + NativeFunction::new(*self), + )))) + } +} +impl FromValue for NativeFunctionData { + fn from_value(v: Value) -> Result { + match *v { + ValueData::Function(ref func) => match *func.borrow() { + Function::NativeFunc(ref data) => Ok(data.data), + _ => Err("Value is not a native function"), + }, + _ => Err("Value is not a function"), + } + } +} + /// A utility function that just calls FromValue::from_value pub fn from_value(v: Value) -> Result { FromValue::from_value(v) diff --git a/src/lib/syntax/ast/constant.rs b/src/lib/syntax/ast/constant.rs index 747803d8c2..175739c5fe 100644 --- a/src/lib/syntax/ast/constant.rs +++ b/src/lib/syntax/ast/constant.rs @@ -1,6 +1,6 @@ use std::fmt::{Display, Formatter, Result}; -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] /// A Javascript Constant pub enum Const { /// A UTF-8 string, such as `"Hello, world"` diff --git a/src/lib/syntax/ast/expr.rs b/src/lib/syntax/ast/expr.rs index e686cdd480..1687d15170 100644 --- a/src/lib/syntax/ast/expr.rs +++ b/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, Trace, Debug, PartialEq)] +#[derive(Clone, Trace, Finalize, Debug, PartialEq)] pub struct Expr { /// The expression definition pub def: ExprDef, @@ -22,7 +22,7 @@ impl Display for Expr { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] /// A Javascript Expression pub enum ExprDef { /// Run a operation between 2 expressions diff --git a/src/lib/syntax/ast/op.rs b/src/lib/syntax/ast/op.rs index cd05b35be5..a9c634e278 100644 --- a/src/lib/syntax/ast/op.rs +++ b/src/lib/syntax/ast/op.rs @@ -12,7 +12,7 @@ pub trait Operator { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] /// A numeric operation between 2 values pub enum NumOp { /// `a + b` - Addition @@ -43,7 +43,7 @@ impl Display for NumOp { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] /// A unary operation on a single value pub enum UnaryOp { /// `a++` - increment the value @@ -78,7 +78,7 @@ impl Display for UnaryOp { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] /// A bitwise operation between 2 values pub enum BitOp { /// `a & b` - Bitwise and @@ -109,7 +109,7 @@ impl Display for BitOp { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] /// A comparitive operation between 2 values pub enum CompOp { /// `a == b` - Equality @@ -149,7 +149,7 @@ impl Display for CompOp { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] /// A logical operation between 2 boolean values pub enum LogOp { /// `a && b` - Logical and @@ -171,7 +171,7 @@ impl Display for LogOp { } } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, Trace, Finalize, PartialEq)] /// A binary operation between 2 values pub enum BinOp { /// Numeric operation