From fff39748664124d5710b841729c241ceb5a0893f Mon Sep 17 00:00:00 2001 From: jedel1043 Date: Fri, 6 Aug 2021 17:29:37 -0500 Subject: [PATCH] Implement `Value::type_of` method --- boa/src/builtins/object/mod.rs | 4 +-- boa/src/syntax/ast/node/call/mod.rs | 6 ++-- .../ast/node/field/get_const_field/mod.rs | 4 +-- .../syntax/ast/node/field/get_field/mod.rs | 4 +-- .../syntax/ast/node/operator/bin_op/mod.rs | 4 +-- .../syntax/ast/node/operator/unary_op/mod.rs | 2 +- boa/src/syntax/ast/node/template/mod.rs | 4 +-- boa/src/value/mod.rs | 27 ++++++++++++++ boa/src/value/type.rs | 35 ++++--------------- boa/src/vm/code_block.rs | 8 +---- boa/src/vm/mod.rs | 6 ++-- 11 files changed, 51 insertions(+), 53 deletions(-) diff --git a/boa/src/builtins/object/mod.rs b/boa/src/builtins/object/mod.rs index 4d4279ff541..ddf20f2bdcd 100644 --- a/boa/src/builtins/object/mod.rs +++ b/boa/src/builtins/object/mod.rs @@ -305,12 +305,12 @@ impl Object { if !matches!(proto.get_type(), Type::Object | Type::Null) { return ctx.throw_type_error(format!( "expected an object or null, got {}", - proto.get_type().as_str() + proto.type_of() )); } // 3. If Type(O) is not Object, return O. - if obj.get_type() != Type::Object { + if !obj.is_object() { return Ok(obj); } diff --git a/boa/src/syntax/ast/node/call/mod.rs b/boa/src/syntax/ast/node/call/mod.rs index d065d76a84f..da895cf7127 100644 --- a/boa/src/syntax/ast/node/call/mod.rs +++ b/boa/src/syntax/ast/node/call/mod.rs @@ -4,7 +4,7 @@ use crate::{ exec::InterpreterState, gc::{Finalize, Trace}, syntax::ast::node::{join_nodes, Node}, - value::{Type, Value}, + value::Value, BoaProfiler, Context, Result, }; use std::fmt; @@ -66,7 +66,7 @@ impl Executable for Call { let (this, func) = match self.expr() { Node::GetConstField(ref get_const_field) => { let mut obj = get_const_field.obj().run(context)?; - if obj.get_type() != Type::Object { + if !obj.is_object() { obj = Value::Object(obj.to_object(context)?); } ( @@ -76,7 +76,7 @@ impl Executable for Call { } Node::GetField(ref get_field) => { let mut obj = get_field.obj().run(context)?; - if obj.get_type() != Type::Object { + if !obj.is_object() { obj = Value::Object(obj.to_object(context)?); } let field = get_field.field().run(context)?; diff --git a/boa/src/syntax/ast/node/field/get_const_field/mod.rs b/boa/src/syntax/ast/node/field/get_const_field/mod.rs index c5b1de5dbe7..55e5c9574d7 100644 --- a/boa/src/syntax/ast/node/field/get_const_field/mod.rs +++ b/boa/src/syntax/ast/node/field/get_const_field/mod.rs @@ -2,7 +2,7 @@ use crate::{ exec::Executable, gc::{Finalize, Trace}, syntax::ast::node::Node, - value::{Type, Value}, + value::Value, Context, Result, }; use std::fmt; @@ -65,7 +65,7 @@ impl GetConstField { impl Executable for GetConstField { fn run(&self, context: &mut Context) -> Result { let mut obj = self.obj().run(context)?; - if obj.get_type() != Type::Object { + if !obj.is_object() { obj = Value::Object(obj.to_object(context)?); } diff --git a/boa/src/syntax/ast/node/field/get_field/mod.rs b/boa/src/syntax/ast/node/field/get_field/mod.rs index 4fc5fbcb2da..8b2963d957c 100644 --- a/boa/src/syntax/ast/node/field/get_field/mod.rs +++ b/boa/src/syntax/ast/node/field/get_field/mod.rs @@ -2,7 +2,7 @@ use crate::{ exec::Executable, gc::{Finalize, Trace}, syntax::ast::node::Node, - value::{Type, Value}, + value::Value, Context, Result, }; use std::fmt; @@ -64,7 +64,7 @@ impl GetField { impl Executable for GetField { fn run(&self, context: &mut Context) -> Result { let mut obj = self.obj().run(context)?; - if obj.get_type() != Type::Object { + if !obj.is_object() { obj = Value::Object(obj.to_object(context)?); } let field = self.field().run(context)?; diff --git a/boa/src/syntax/ast/node/operator/bin_op/mod.rs b/boa/src/syntax/ast/node/operator/bin_op/mod.rs index 50c6272af43..c23623231dd 100644 --- a/boa/src/syntax/ast/node/operator/bin_op/mod.rs +++ b/boa/src/syntax/ast/node/operator/bin_op/mod.rs @@ -140,7 +140,7 @@ impl Executable for BinOp { if !y.is_object() { return context.throw_type_error(format!( "right-hand side of 'in' should be an object, got {}", - y.get_type().as_str() + y.type_of() )); } let key = x.to_property_key(context)?; @@ -166,7 +166,7 @@ impl Executable for BinOp { } else { return context.throw_type_error(format!( "right-hand side of 'instanceof' should be an object, got {}", - y.get_type().as_str() + y.type_of() )); } } diff --git a/boa/src/syntax/ast/node/operator/unary_op/mod.rs b/boa/src/syntax/ast/node/operator/unary_op/mod.rs index 1692fef71fc..896f8e04951 100644 --- a/boa/src/syntax/ast/node/operator/unary_op/mod.rs +++ b/boa/src/syntax/ast/node/operator/unary_op/mod.rs @@ -116,7 +116,7 @@ impl Executable for UnaryOp { | Node::UnaryOp(_) => Value::boolean(true), _ => return context.throw_syntax_error(format!("wrong delete argument {}", self)), }, - op::UnaryOp::TypeOf => Value::from(self.target().run(context)?.get_type().as_str()), + op::UnaryOp::TypeOf => Value::from(self.target().run(context)?.type_of()), }) } } diff --git a/boa/src/syntax/ast/node/template/mod.rs b/boa/src/syntax/ast/node/template/mod.rs index 7d20af656fe..461b95e50b8 100644 --- a/boa/src/syntax/ast/node/template/mod.rs +++ b/boa/src/syntax/ast/node/template/mod.rs @@ -1,7 +1,7 @@ //! Template literal node. use super::Node; -use crate::{builtins::Array, exec::Executable, value::Type, BoaProfiler, Context, Result, Value}; +use crate::{builtins::Array, exec::Executable, BoaProfiler, Context, Result, Value}; use gc::{Finalize, Trace}; #[cfg(feature = "deser")] @@ -112,7 +112,7 @@ impl Executable for TaggedTemplate { let (this, func) = match *self.tag { Node::GetConstField(ref get_const_field) => { let mut obj = get_const_field.obj().run(context)?; - if obj.get_type() != Type::Object { + if !obj.is_object() { obj = Value::Object(obj.to_object(context)?); } ( diff --git a/boa/src/value/mod.rs b/boa/src/value/mod.rs index 0a6072911e0..6ae34488552 100644 --- a/boa/src/value/mod.rs +++ b/boa/src/value/mod.rs @@ -973,6 +973,33 @@ impl Value { } } + /// `typeof` operator. Returns a string representing the type of the + /// given ECMA Value. + /// + /// More information: + /// - [EcmaScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-typeof-operator + pub fn type_of(&self) -> JsString { + match *self { + Self::Rational(_) | Self::Integer(_) => "number", + Self::String(_) => "string", + Self::Boolean(_) => "boolean", + Self::Symbol(_) => "symbol", + Self::Null => "object", + Self::Undefined => "undefined", + Self::BigInt(_) => "bigint", + Self::Object(ref object) => { + if object.is_function() { + "function" + } else { + "object" + } + } + } + .into() + } + /// Check if it is an array. /// /// More information: diff --git a/boa/src/value/type.rs b/boa/src/value/type.rs index c884a9c7f3f..bcd6f382404 100644 --- a/boa/src/value/type.rs +++ b/boa/src/value/type.rs @@ -1,7 +1,6 @@ use super::Value; /// Possible types of values as defined at . -/// Note that an object which implements call is referred to here as 'Function'. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Type { Undefined, @@ -12,31 +11,15 @@ pub enum Type { Symbol, BigInt, Object, - Function, -} - -impl Type { - pub fn as_str(self) -> &'static str { - match self { - Self::Number => "number", - Self::String => "string", - Self::Boolean => "boolean", - Self::Symbol => "symbol", - Self::Null => "object", - Self::Undefined => "undefined", - Self::Function => "function", - Self::Object => "object", - Self::BigInt => "bigint", - } - } } impl Value { - /// Get the type of the value. + /// Get the type of a value /// - /// This is similar to typeof as described at but instead of - /// returning a string it returns a Type enum which implements fmt::Display to allow getting the string if - /// required using to_string(). + /// This is the abstract operation Type(v), as described in + /// + /// so it treats `Type::Function` objects and `Type::Object` objects as `Type::Object`. + /// If you instead need to call the `typeof` operator, check [`Value::type_of`] pub fn get_type(&self) -> Type { match *self { Self::Rational(_) | Self::Integer(_) => Type::Number, @@ -46,13 +29,7 @@ impl Value { Self::Null => Type::Null, Self::Undefined => Type::Undefined, Self::BigInt(_) => Type::BigInt, - Self::Object(ref object) => { - if object.is_function() { - Type::Function - } else { - Type::Object - } - } + Self::Object(_) => Type::Object, } } } diff --git a/boa/src/vm/code_block.rs b/boa/src/vm/code_block.rs index ee86cac53e1..ad221bd4067 100644 --- a/boa/src/vm/code_block.rs +++ b/boa/src/vm/code_block.rs @@ -189,13 +189,7 @@ impl std::fmt::Display for CodeBlock { f.write_str("Literals:\n")?; if !self.literals.is_empty() { for (i, value) in self.literals.iter().enumerate() { - writeln!( - f, - " {:04}: <{}> {}", - i, - value.get_type().as_str(), - value.display() - )?; + writeln!(f, " {:04}: <{}> {}", i, value.type_of(), value.display())?; } } else { writeln!(f, " ")?; diff --git a/boa/src/vm/mod.rs b/boa/src/vm/mod.rs index a3f0ddbc12f..11f7dd3e4a7 100644 --- a/boa/src/vm/mod.rs +++ b/boa/src/vm/mod.rs @@ -188,7 +188,7 @@ impl<'a> Vm<'a> { if !rhs.is_object() { return Err(self.context.construct_type_error(format!( "right-hand side of 'in' should be an object, got {}", - rhs.get_type().as_str() + rhs.type_of() ))); } let key = lhs.to_property_key(self.context)?; @@ -216,7 +216,7 @@ impl<'a> Vm<'a> { } else { return Err(self.context.construct_type_error(format!( "right-hand side of 'instanceof' should be an object, got {}", - y.get_type().as_str() + y.type_of() ))); }; @@ -228,7 +228,7 @@ impl<'a> Vm<'a> { } Opcode::TypeOf => { let value = self.pop(); - self.push(value.get_type().as_str()); + self.push(value.type_of()); } Opcode::Pos => { let value = self.pop();