From c502fc664a8247bdab940a21a08d057834b4a679 Mon Sep 17 00:00:00 2001 From: Javed Nissar Date: Wed, 13 May 2020 19:30:53 -0400 Subject: [PATCH] Resolved #359 Removed Node::TypeOf, implemented UnaryOp::TypeOf, and added tests --- boa/src/exec/mod.rs | 36 +++++++++++------------- boa/src/exec/tests.rs | 56 ++++++++++++++++++++++++++++++++++++++ boa/src/syntax/ast/node.rs | 30 ++------------------ 3 files changed, 75 insertions(+), 47 deletions(-) diff --git a/boa/src/exec/mod.rs b/boa/src/exec/mod.rs index 524b693771a..f68c2b569b1 100644 --- a/boa/src/exec/mod.rs +++ b/boa/src/exec/mod.rs @@ -402,7 +402,7 @@ impl Executor for Interpreter { } else { !(num_v_a as i32) }) - } + }, UnaryOp::Void => Value::undefined(), UnaryOp::Delete => match a.deref() { Node::GetConstField(ref obj, ref field) => { @@ -420,10 +420,24 @@ impl Executor for Interpreter { | Node::FunctionExpr(_, _, _) | Node::New(_) | Node::Object(_) - | Node::TypeOf(_) | Node::UnaryOp(_, _) => Value::boolean(true), _ => panic!("SyntaxError: wrong delete argument {}", node), }, + UnaryOp::TypeOf => Value::from(match v_a.data() { + 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" + } + } + }), _ => unimplemented!(), }) } @@ -607,24 +621,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" - } - } - })) - } Node::StatementList(ref list) => { { let env = &mut self.realm.environment; diff --git a/boa/src/exec/tests.rs b/boa/src/exec/tests.rs index 7f3b6f78125..0991a7d0c5c 100644 --- a/boa/src/exec/tests.rs +++ b/boa/src/exec/tests.rs @@ -385,6 +385,62 @@ fn unary_pre() { assert_eq!(&exec(execs_before_dec), "true"); } +#[test] +fn unary_typeof() { + let string_type_result = String::from("string"); + let number_type_result = String::from("number"); + let undefined_type_result = String::from("undefined"); + let boolean_type_result = String::from("boolean"); + let object_type_result = String::from("object"); + let function_type_result = String::from("function"); + let symbol_type_result = String::from("symbol"); + let typeof_string = r#" + const a = String(); + typeof a; + "#; + assert_eq!(exec(typeof_string), string_type_result); + let typeof_int = r#" + let a = 5; + typeof a; + "#; + assert_eq!(exec(typeof_int), number_type_result); + let typeof_rational = r#" + let a = 0.5; + typeof a; + "#; + assert_eq!(exec(typeof_rational), number_type_result); + let typeof_undefined = r#" + let a = undefined; + typeof a; + "#; + assert_eq!(exec(typeof_undefined), undefined_type_result); + let typeof_boolean = r#" + let a = true; + typeof a; + "#; + assert_eq!(exec(typeof_boolean), boolean_type_result); + let typeof_null = r#" + let a = null; + typeof a; + "#; + assert_eq!(exec(typeof_null), object_type_result); + let typeof_object = r#" + let a = {}; + typeof a; + "#; + assert_eq!(exec(typeof_object), object_type_result); + let typeof_symbol = r#" + let a = Symbol(); + typeof a; + "#; + assert_eq!(exec(typeof_symbol), symbol_type_result); + let typeof_function = r#" + let a = function(){}; + typeof a; + "#; + assert_eq!(exec(typeof_function), function_type_result); +} + #[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 b2288af8ea3..e5b14346c18 100644 --- a/boa/src/syntax/ast/node.rs +++ b/boa/src/syntax/ast/node.rs @@ -469,22 +469,7 @@ 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. + /// The `try...catch` statement marks a block of statements to try and specifies a response should an exception be thrown. /// /// The `try` statement consists of a `try`-block, which contains one or more statements. `{}` /// must always be used, even for single statements. At least one `catch`-block, or a @@ -564,7 +549,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 +565,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 +833,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 +1093,6 @@ impl Node { } Ok(()) } - Self::TypeOf(ref e) => write!(f, "typeof {}", e), } } }