Skip to content

Commit

Permalink
Resolved #359
Browse files Browse the repository at this point in the history
Removed Node::TypeOf, implemented UnaryOp::TypeOf, and added tests
  • Loading branch information
JavedNissar committed May 19, 2020
1 parent 402041d commit 55b4610
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 46 deletions.
2 changes: 1 addition & 1 deletion boa/src/builtins/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -710,7 +710,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() {
Expand Down
8 changes: 8 additions & 0 deletions boa/src/builtins/value/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,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)
}

Expand Down
21 changes: 1 addition & 20 deletions boa/src/exec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,11 +420,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) => {
Expand Down Expand Up @@ -607,24 +606,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;
Expand Down
57 changes: 57 additions & 0 deletions boa/src/exec/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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#"
Expand Down
27 changes: 2 additions & 25 deletions boa/src/syntax/ast/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,20 +469,6 @@ pub enum Node {
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw
Throw(Box<Node>),

/// 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<Node>),

/// The `try...catch` statement marks a block of statements to try and specifies a response
/// should an exception be thrown.
///
Expand Down Expand Up @@ -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,
}
}
Expand All @@ -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
Expand Down Expand Up @@ -848,14 +834,6 @@ impl Node {
Self::Throw(val.into())
}

/// Creates a `TypeOf` AST node.
pub fn type_of<E>(expr: E) -> Self
where
E: Into<Box<Self>>,
{
Self::TypeOf(expr.into())
}

/// Creates a `Try` AST node.
pub fn try_node<T, OC, OP, OF, C, P, F>(try_node: T, catch: OC, param: OP, finally: OF) -> Self
where
Expand Down Expand Up @@ -1116,7 +1094,6 @@ impl Node {
}
Ok(())
}
Self::TypeOf(ref e) => write!(f, "typeof {}", e),
}
}
}
Expand Down

0 comments on commit 55b4610

Please sign in to comment.