From 29abfd6147b744b2ddb53b536d7fc67fcfb98107 Mon Sep 17 00:00:00 2001 From: Javed Nissar <1396351+RestitutorOrbis@users.noreply.github.com> Date: Thu, 21 May 2020 04:45:11 -0400 Subject: [PATCH] Resolved #359 (#396) Removed Node::TypeOf, implemented UnaryOp::TypeOf, and added tests --- boa/src/builtins/value/mod.rs | 2 +- boa/src/builtins/value/operations.rs | 8 ++++ boa/src/exec/mod.rs | 22 +---------- boa/src/exec/tests.rs | 57 ++++++++++++++++++++++++++++ boa/src/syntax/ast/node.rs | 27 +------------ 5 files changed, 69 insertions(+), 47 deletions(-) diff --git a/boa/src/builtins/value/mod.rs b/boa/src/builtins/value/mod.rs index 5fe5ee74ed..77de6df642 100644 --- a/boa/src/builtins/value/mod.rs +++ b/boa/src/builtins/value/mod.rs @@ -755,7 +755,7 @@ impl ValueData { Self::String(_) => "string", Self::Boolean(_) => "boolean", Self::Symbol(_) => "symbol", - Self::Null => "null", + Self::Null => "object", Self::Undefined => "undefined", Self::Object(ref o) => { if o.deref().borrow().is_callable() { diff --git a/boa/src/builtins/value/operations.rs b/boa/src/builtins/value/operations.rs index 10eefde1bb..1a733542b0 100644 --- a/boa/src/builtins/value/operations.rs +++ b/boa/src/builtins/value/operations.rs @@ -19,6 +19,14 @@ impl Value { return number::equals(f64::from(self), f64::from(other)); } + //Null has to be handled specially because "typeof null" returns object and if we managed + //this without a special case we would compare self and other as if they were actually + //objects which unfortunately fails + //Specification Link: https://tc39.es/ecma262/#sec-typeof-operator + if self.is_null() { + return true; + } + same_value_non_number(self, other) } diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index f61e55a062..ebc7fba8f8 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -362,11 +362,10 @@ impl Executor for Interpreter { | Node::FunctionExpr(_, _, _) | Node::New(_) | Node::Object(_) - | Node::TypeOf(_) | Node::UnaryOp(_, _) => Value::boolean(true), _ => panic!("SyntaxError: wrong delete argument {}", node), }, - _ => unimplemented!(), + UnaryOp::TypeOf => Value::from(v_a.get_type()), }) } Node::BinOp(BinOp::Bit(ref op), ref a, ref b) => { @@ -549,25 +548,6 @@ impl Executor for Interpreter { } Ok(Value::undefined()) } - Node::TypeOf(ref val_e) => { - let val = self.run(val_e)?; - Ok(Value::from(match *val { - ValueData::Undefined => "undefined", - ValueData::Symbol(_) => "symbol", - ValueData::Null => "object", - ValueData::Boolean(_) => "boolean", - ValueData::Rational(_) | ValueData::Integer(_) => "number", - ValueData::String(_) => "string", - ValueData::Object(ref o) => { - if o.deref().borrow().is_callable() { - "function" - } else { - "object" - } - } - ValueData::BigInt(_) => "bigint", - })) - } Node::StatementList(ref list) => { let mut obj = Value::null(); for (i, item) in list.iter().enumerate() { diff --git a/boa/src/exec/tests.rs b/boa/src/exec/tests.rs index 45fa718d32..1bee7bb4b5 100644 --- a/boa/src/exec/tests.rs +++ b/boa/src/exec/tests.rs @@ -385,6 +385,63 @@ fn unary_pre() { assert_eq!(&exec(execs_before_dec), "true"); } +#[test] +fn unary_typeof() { + let typeof_string = r#" + const a = String(); + typeof a; + "#; + assert_eq!(&exec(typeof_string), "string"); + + let typeof_int = r#" + let a = 5; + typeof a; + "#; + assert_eq!(&exec(typeof_int), "number"); + + let typeof_rational = r#" + let a = 0.5; + typeof a; + "#; + assert_eq!(&exec(typeof_rational), "number"); + + let typeof_undefined = r#" + let a = undefined; + typeof a; + "#; + assert_eq!(&exec(typeof_undefined), "undefined"); + + let typeof_boolean = r#" + let a = true; + typeof a; + "#; + assert_eq!(&exec(typeof_boolean), "boolean"); + + let typeof_null = r#" + let a = null; + typeof a; + "#; + assert_eq!(&exec(typeof_null), "object"); + + let typeof_object = r#" + let a = {}; + typeof a; + "#; + assert_eq!(&exec(typeof_object), "object"); + + let typeof_symbol = r#" + let a = Symbol(); + typeof a; + "#; + assert_eq!(&exec(typeof_symbol), "symbol"); + + let typeof_function = r#" + let a = function(){}; + typeof a; + "#; + assert_eq!(&exec(typeof_function), "function"); +} + #[test] fn unary_post() { let unary_inc = r#" diff --git a/boa/src/syntax/ast/node.rs b/boa/src/syntax/ast/node.rs index b2288af8ea..dc27bde520 100644 --- a/boa/src/syntax/ast/node.rs +++ b/boa/src/syntax/ast/node.rs @@ -469,20 +469,6 @@ pub enum Node { /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw Throw(Box), - /// The `typeof` operator returns a string indicating the type of the unevaluated operand. - /// - /// Syntax: `typeof operand` - /// - /// Returns a string indicating the type of the unevaluated operand. - /// - /// More information: - /// - [ECMAScript reference][spec] - /// - [MDN documentation][mdn] - /// - /// [spec]: https://tc39.es/ecma262/#sec-typeof-operator - /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof - TypeOf(Box), - /// The `try...catch` statement marks a block of statements to try and specifies a response /// should an exception be thrown. /// @@ -564,7 +550,7 @@ pub enum Node { impl Operator for Node { fn get_assoc(&self) -> bool { match *self { - Self::UnaryOp(_, _) | Self::TypeOf(_) | Self::If(_, _, _) | Self::Assign(_, _) => false, + Self::UnaryOp(_, _) | Self::If(_, _, _) | Self::Assign(_, _) => false, _ => true, } } @@ -580,7 +566,7 @@ impl Operator for Node { Self::UnaryOp(UnaryOp::Not, _) | Self::UnaryOp(UnaryOp::Tilde, _) | Self::UnaryOp(UnaryOp::Minus, _) - | Self::TypeOf(_) => 4, + | Self::UnaryOp(UnaryOp::TypeOf, _) => 4, Self::BinOp(op, _, _) => op.get_precedence(), Self::If(_, _, _) => 15, // 16 should be yield @@ -848,14 +834,6 @@ impl Node { Self::Throw(val.into()) } - /// Creates a `TypeOf` AST node. - pub fn type_of(expr: E) -> Self - where - E: Into>, - { - Self::TypeOf(expr.into()) - } - /// Creates a `Try` AST node. pub fn try_node(try_node: T, catch: OC, param: OP, finally: OF) -> Self where @@ -1116,7 +1094,6 @@ impl Node { } Ok(()) } - Self::TypeOf(ref e) => write!(f, "typeof {}", e), } } }