Skip to content

Commit

Permalink
Implement Value::type_of method
Browse files Browse the repository at this point in the history
  • Loading branch information
jedel1043 authored Aug 6, 2021
1 parent f331694 commit fff3974
Show file tree
Hide file tree
Showing 11 changed files with 51 additions and 53 deletions.
4 changes: 2 additions & 2 deletions boa/src/builtins/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
6 changes: 3 additions & 3 deletions boa/src/syntax/ast/node/call/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)?);
}
(
Expand All @@ -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)?;
Expand Down
4 changes: 2 additions & 2 deletions boa/src/syntax/ast/node/field/get_const_field/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -65,7 +65,7 @@ impl GetConstField {
impl Executable for GetConstField {
fn run(&self, context: &mut Context) -> Result<Value> {
let mut obj = self.obj().run(context)?;
if obj.get_type() != Type::Object {
if !obj.is_object() {
obj = Value::Object(obj.to_object(context)?);
}

Expand Down
4 changes: 2 additions & 2 deletions boa/src/syntax/ast/node/field/get_field/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -64,7 +64,7 @@ impl GetField {
impl Executable for GetField {
fn run(&self, context: &mut Context) -> Result<Value> {
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)?;
Expand Down
4 changes: 2 additions & 2 deletions boa/src/syntax/ast/node/operator/bin_op/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
Expand All @@ -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()
));
}
}
Expand Down
2 changes: 1 addition & 1 deletion boa/src/syntax/ast/node/operator/unary_op/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()),
})
}
}
Expand Down
4 changes: 2 additions & 2 deletions boa/src/syntax/ast/node/template/mod.rs
Original file line number Diff line number Diff line change
@@ -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")]
Expand Down Expand Up @@ -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)?);
}
(
Expand Down
27 changes: 27 additions & 0 deletions boa/src/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
35 changes: 6 additions & 29 deletions boa/src/value/type.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use super::Value;

/// Possible types of values as defined at <https://tc39.es/ecma262/#sec-typeof-operator>.
/// 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,
Expand All @@ -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 <https://tc39.es/ecma262/#sec-typeof-operator> 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
/// <https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-ecmascript-language-types>
/// 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,
Expand All @@ -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,
}
}
}
8 changes: 1 addition & 7 deletions boa/src/vm/code_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, " <empty>")?;
Expand Down
6 changes: 3 additions & 3 deletions boa/src/vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
Expand Down Expand Up @@ -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()
)));
};

Expand All @@ -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();
Expand Down

0 comments on commit fff3974

Please sign in to comment.