Skip to content

Commit

Permalink
Merge 6cb8859 into 607a534
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat authored Aug 11, 2020
2 parents 607a534 + 6cb8859 commit 76153ff
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 61 deletions.
6 changes: 3 additions & 3 deletions boa/src/builtins/date/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ use crate::{
builtins::{
function::{make_builtin_fn, make_constructor_fn},
object::ObjectData,
value::PreferredType,
ResultValue, Value,
},
exec::PreferredType,
BoaProfiler, Interpreter,
};
use chrono::{prelude::*, Duration, LocalResult};
Expand Down Expand Up @@ -306,8 +306,8 @@ impl Date {
let value = &args[0];
let tv = match this_time_value(value, ctx) {
Ok(dt) => dt.0,
_ => match &ctx.to_primitive(value, PreferredType::Default)? {
Value::String(str) => match chrono::DateTime::parse_from_rfc3339(&str) {
_ => match value.to_primitive(ctx, PreferredType::Default)? {
Value::String(ref str) => match chrono::DateTime::parse_from_rfc3339(&str) {
Ok(dt) => Some(dt.naive_utc()),
_ => None,
},
Expand Down
10 changes: 5 additions & 5 deletions boa/src/builtins/date/tests.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#![allow(clippy::zero_prefixed_literal)]

use crate::{
builtins::{object::ObjectData, Value},
forward, forward_val, Interpreter, Realm,
};
use chrono::prelude::*;

// NB: Javascript Uses 0-based months, where chrono uses 1-based months. Many of the assertions look wrong because of
// NOTE: Javascript Uses 0-based months, where chrono uses 1-based months. Many of the assertions look wrong because of
// this.

fn forward_dt_utc(engine: &mut Interpreter, src: &str) -> Option<NaiveDateTime> {
Expand All @@ -20,13 +22,11 @@ fn forward_dt_utc(engine: &mut Interpreter, src: &str) -> Option<NaiveDateTime>
panic!("expected object")
};

let date_time = if let ObjectData::Date(date_time) = &date_time.borrow().data {
if let ObjectData::Date(date_time) = &date_time.borrow().data {
date_time.0
} else {
panic!("expected date")
};

date_time.clone()
}
}

fn forward_dt_local(engine: &mut Interpreter, src: &str) -> Option<NaiveDateTime> {
Expand Down
6 changes: 3 additions & 3 deletions boa/src/builtins/value/equality.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::*;
use crate::{builtins::Number, exec::PreferredType, Interpreter};
use crate::{builtins::Number, Interpreter};

use std::borrow::Borrow;

Expand Down Expand Up @@ -94,14 +94,14 @@ impl Value {
// 10. If Type(x) is either String, Number, BigInt, or Symbol and Type(y) is Object, return the result
// of the comparison x == ? ToPrimitive(y).
(Self::Object(_), _) => {
let primitive = interpreter.to_primitive(self, PreferredType::Default)?;
let primitive = self.to_primitive(interpreter, PreferredType::Default)?;
return primitive.equals(other, interpreter);
}

// 11. If Type(x) is Object and Type(y) is either String, Number, BigInt, or Symbol, return the result
// of the comparison ? ToPrimitive(x) == y.
(_, Self::Object(_)) => {
let primitive = interpreter.to_primitive(other, PreferredType::Default)?;
let primitive = other.to_primitive(interpreter, PreferredType::Default)?;
return primitive.equals(self, interpreter);
}

Expand Down
35 changes: 35 additions & 0 deletions boa/src/builtins/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -704,10 +704,45 @@ impl Value {
new_func_val.set_field("length", Value::from(length));
new_func_val
}

/// The abstract operation ToPrimitive takes an input argument and an optional argument PreferredType.
///
/// <https://tc39.es/ecma262/#sec-toprimitive>
pub fn to_primitive(
&self,
ctx: &mut Interpreter,
preferred_type: PreferredType,
) -> ResultValue {
// 1. Assert: input is an ECMAScript language value. (always a value not need to check)
// 2. If Type(input) is Object, then
if let Value::Object(_) = self {
let mut hint = preferred_type;

// Skip d, e we don't support Symbols yet
// TODO: add when symbols are supported
// TODO: Add other steps.
if hint == PreferredType::Default {
hint = PreferredType::Number;
};

// g. Return ? OrdinaryToPrimitive(input, hint).
ctx.ordinary_to_primitive(self, hint)
} else {
// 3. Return input.
Ok(self.clone())
}
}
}

impl Default for Value {
fn default() -> Self {
Self::Undefined
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum PreferredType {
String,
Number,
Default,
}
18 changes: 10 additions & 8 deletions boa/src/builtins/value/operations.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use super::*;
use crate::builtins::number::{f64_to_int32, f64_to_uint32, Number};
use crate::exec::PreferredType;
use crate::builtins::{
number::{f64_to_int32, f64_to_uint32, Number},
value::PreferredType,
};

impl Value {
#[inline]
Expand All @@ -20,8 +22,8 @@ impl Value {

// Slow path:
(_, _) => match (
ctx.to_primitive(self, PreferredType::Default)?,
ctx.to_primitive(other, PreferredType::Default)?,
self.to_primitive(ctx, PreferredType::Default)?,
other.to_primitive(ctx, PreferredType::Default)?,
) {
(Self::String(ref x), ref y) => Self::string(format!("{}{}", x, ctx.to_string(y)?)),
(ref x, Self::String(ref y)) => Self::string(format!("{}{}", ctx.to_string(x)?, y)),
Expand Down Expand Up @@ -440,13 +442,13 @@ impl Value {
// Slow path:
(_, _) => {
let (px, py) = if left_first {
let px = ctx.to_primitive(self, PreferredType::Number)?;
let py = ctx.to_primitive(other, PreferredType::Number)?;
let px = self.to_primitive(ctx, PreferredType::Number)?;
let py = other.to_primitive(ctx, PreferredType::Number)?;
(px, py)
} else {
// NOTE: The order of evaluation needs to be reversed to preserve left to right evaluation.
let py = ctx.to_primitive(other, PreferredType::Number)?;
let px = ctx.to_primitive(self, PreferredType::Number)?;
let py = other.to_primitive(ctx, PreferredType::Number)?;
let px = self.to_primitive(ctx, PreferredType::Number)?;
(px, py)
};

Expand Down
1 change: 1 addition & 0 deletions boa/src/builtins/value/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ fn bitand_rational_and_rational() {
}

#[test]
#[allow(clippy::float_cmp)]
fn pow_number_and_number() {
let realm = Realm::create();
let mut engine = Interpreter::new(realm);
Expand Down
49 changes: 7 additions & 42 deletions boa/src/exec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use crate::{
number::{f64_to_int32, f64_to_uint32},
object::{Object, ObjectData, PROTOTYPE},
property::PropertyKey,
value::{RcBigInt, RcString, ResultValue, Type, Value},
value::{PreferredType, RcBigInt, RcString, ResultValue, Type, Value},
BigInt, Console, Number,
},
realm::Realm,
Expand All @@ -54,12 +54,6 @@ pub(crate) enum InterpreterState {
Return,
Break(Option<String>),
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PreferredType {
String,
Number,
Default,
}

/// A Javascript intepreter
#[derive(Debug)]
Expand Down Expand Up @@ -210,7 +204,7 @@ impl Interpreter {
Value::Symbol(_) => Err(self.construct_type_error("can't convert symbol to string")),
Value::BigInt(ref bigint) => Ok(RcString::from(bigint.to_string())),
Value::Object(_) => {
let primitive = self.to_primitive(value, PreferredType::String)?;
let primitive = value.to_primitive(self, PreferredType::String)?;
self.to_string(&primitive)
}
}
Expand Down Expand Up @@ -239,7 +233,7 @@ impl Interpreter {
}
Value::BigInt(b) => Ok(b.clone()),
Value::Object(_) => {
let primitive = self.to_primitive(value, PreferredType::Number)?;
let primitive = value.to_primitive(self, PreferredType::Number)?;
self.to_bigint(&primitive)
}
Value::Symbol(_) => Err(self.construct_type_error("cannot convert Symbol to a BigInt")),
Expand Down Expand Up @@ -352,7 +346,7 @@ impl Interpreter {
Value::Symbol(_) => Err(self.construct_type_error("argument must not be a symbol")),
Value::BigInt(_) => Err(self.construct_type_error("argument must not be a bigint")),
Value::Object(_) => {
let primitive = self.to_primitive(value, PreferredType::Number)?;
let primitive = value.to_primitive(self, PreferredType::Number)?;
self.to_number(&primitive)
}
}
Expand All @@ -363,7 +357,7 @@ impl Interpreter {
/// See: https://tc39.es/ecma262/#sec-tonumeric
#[allow(clippy::wrong_self_convention)]
pub fn to_numeric(&mut self, value: &Value) -> ResultValue {
let primitive = self.to_primitive(value, PreferredType::Number)?;
let primitive = value.to_primitive(self, PreferredType::Number)?;
if primitive.is_bigint() {
return Ok(primitive);
}
Expand All @@ -377,7 +371,7 @@ impl Interpreter {
/// See: https://tc39.es/ecma262/#sec-tonumeric
#[allow(clippy::wrong_self_convention)]
pub(crate) fn to_numeric_number(&mut self, value: &Value) -> Result<f64, Value> {
let primitive = self.to_primitive(value, PreferredType::Number)?;
let primitive = value.to_primitive(self, PreferredType::Number)?;
if let Some(ref bigint) = primitive.as_bigint() {
return Ok(bigint.to_f64());
}
Expand Down Expand Up @@ -476,41 +470,12 @@ impl Interpreter {
self.throw_type_error("cannot convert object to primitive value")
}

/// The abstract operation ToPrimitive takes an input argument and an optional argument PreferredType.
///
/// <https://tc39.es/ecma262/#sec-toprimitive>
#[allow(clippy::wrong_self_convention)]
pub(crate) fn to_primitive(
&mut self,
input: &Value,
preferred_type: PreferredType,
) -> ResultValue {
// 1. Assert: input is an ECMAScript language value. (always a value not need to check)
// 2. If Type(input) is Object, then
if let Value::Object(_) = input {
let mut hint = preferred_type;

// Skip d, e we don't support Symbols yet
// TODO: add when symbols are supported
// TODO: Add other steps.
if hint == PreferredType::Default {
hint = PreferredType::Number;
};

// g. Return ? OrdinaryToPrimitive(input, hint).
self.ordinary_to_primitive(input, hint)
} else {
// 3. Return input.
Ok(input.clone())
}
}

/// The abstract operation ToPropertyKey takes argument argument. It converts argument to a value that can be used as a property key.
///
/// https://tc39.es/ecma262/#sec-topropertykey
#[allow(clippy::wrong_self_convention)]
pub(crate) fn to_property_key(&mut self, value: &Value) -> Result<PropertyKey, Value> {
let key = self.to_primitive(value, PreferredType::String)?;
let key = value.to_primitive(self, PreferredType::String)?;
if let Value::Symbol(ref symbol) = key {
Ok(PropertyKey::from(symbol.clone()))
} else {
Expand Down

0 comments on commit 76153ff

Please sign in to comment.