From ff056812f70395b00851df4d3c5041b1826a03a5 Mon Sep 17 00:00:00 2001 From: Aapo Alasuutari Date: Sun, 21 Jul 2024 18:35:02 +0300 Subject: [PATCH] feat(ecmascript): `Date.prototype[Symbol.toPrimitive]` (#339) * feat(ecmascript): Date.prototype[Symbol.toPrimitive] * chore(test262): Update expectations --- .../date_objects/date_prototype.rs | 46 +++++++++++++++++-- tests/expectations.json | 15 ------ 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/nova_vm/src/ecmascript/builtins/numbers_and_dates/date_objects/date_prototype.rs b/nova_vm/src/ecmascript/builtins/numbers_and_dates/date_objects/date_prototype.rs index 0b6d2a2e7..b5e48412b 100644 --- a/nova_vm/src/ecmascript/builtins/numbers_and_dates/date_objects/date_prototype.rs +++ b/nova_vm/src/ecmascript/builtins/numbers_and_dates/date_objects/date_prototype.rs @@ -6,13 +6,14 @@ use std::time::SystemTime; use crate::{ ecmascript::{ + abstract_operations::type_conversion::{ordinary_to_primitive, PreferredType}, builders::{ builtin_function_builder::BuiltinFunctionBuilder, ordinary_object_builder::OrdinaryObjectBuilder, }, builtins::{date::Date, ArgumentsList, Behaviour, Builtin, BuiltinIntrinsic}, execution::{agent::ExceptionType, Agent, JsResult, RealmIdentifier}, - types::{IntoValue, Number, String, Value, BUILTIN_STRING_MEMORY}, + types::{IntoValue, Number, Object, String, Value, BUILTIN_STRING_MEMORY}, }, heap::{IntrinsicFunctionIndexes, WellKnownSymbolIndexes}, SmallInteger, @@ -574,8 +575,47 @@ impl DatePrototype { } } - fn to_primitive(_agent: &mut Agent, _this_value: Value, _: ArgumentsList) -> JsResult { - todo!() + /// ### [21.4.4.45 Date.prototype \[ %Symbol.toPrimitive% \] ( hint )](https://tc39.es/ecma262/#sec-date.prototype-%symbol.toprimitive%) + /// + /// This method is called by ECMAScript language operators to convert a + /// Date to a primitive value. The allowed values for hint are "default", + /// "number", and "string". Dates are unique among built-in ECMAScript + /// object in that they treat "default" as being equivalent to "string". + /// All other built-in ECMAScript objects treat "default" as being + /// equivalent to "number". + fn to_primitive( + agent: &mut Agent, + this_value: Value, + arguments: ArgumentsList, + ) -> JsResult { + let hint = arguments.get(0); + // 1. Let O be the this value. + // 2. If O is not an Object, throw a TypeError exception. + let Ok(o) = Object::try_from(this_value) else { + return Err( + agent.throw_exception(ExceptionType::TypeError, "argument is not an object") + ); + }; + // 3. If hint is either "string" or "default", then + let try_first = if hint == BUILTIN_STRING_MEMORY.string.into_value() + || hint == BUILTIN_STRING_MEMORY.default.into_value() + { + // a. Let tryFirst be string. + PreferredType::String + } else if hint == BUILTIN_STRING_MEMORY.number.into_value() { + // 4. Else if hint is "number", then + // a. Let tryFirst be number. + PreferredType::Number + } else { + // 5. Else, + // a. Throw a TypeError exception. + return Err(agent.throw_exception( + ExceptionType::TypeError, + "Expected 'hint' to be \"string\", \"default\", or \"number\"", + )); + }; + // 6. Return ? OrdinaryToPrimitive(O, tryFirst). + ordinary_to_primitive(agent, o, try_first).map(|result| result.into_value()) } pub(crate) fn create_intrinsic(agent: &mut Agent, realm: RealmIdentifier) { diff --git a/tests/expectations.json b/tests/expectations.json index fa4980027..23dc31f92 100644 --- a/tests/expectations.json +++ b/tests/expectations.json @@ -2489,21 +2489,7 @@ "built-ins/Date/proto-from-ctor-realm-one.js": "FAIL", "built-ins/Date/proto-from-ctor-realm-two.js": "FAIL", "built-ins/Date/proto-from-ctor-realm-zero.js": "FAIL", - "built-ins/Date/prototype/Symbol.toPrimitive/called-as-function.js": "CRASH", - "built-ins/Date/prototype/Symbol.toPrimitive/hint-default-first-invalid.js": "CRASH", - "built-ins/Date/prototype/Symbol.toPrimitive/hint-default-first-non-callable.js": "CRASH", - "built-ins/Date/prototype/Symbol.toPrimitive/hint-default-first-valid.js": "CRASH", - "built-ins/Date/prototype/Symbol.toPrimitive/hint-default-no-callables.js": "CRASH", "built-ins/Date/prototype/Symbol.toPrimitive/hint-invalid.js": "CRASH", - "built-ins/Date/prototype/Symbol.toPrimitive/hint-number-first-invalid.js": "CRASH", - "built-ins/Date/prototype/Symbol.toPrimitive/hint-number-first-non-callable.js": "CRASH", - "built-ins/Date/prototype/Symbol.toPrimitive/hint-number-first-valid.js": "CRASH", - "built-ins/Date/prototype/Symbol.toPrimitive/hint-number-no-callables.js": "CRASH", - "built-ins/Date/prototype/Symbol.toPrimitive/hint-string-first-invalid.js": "CRASH", - "built-ins/Date/prototype/Symbol.toPrimitive/hint-string-first-non-callable.js": "CRASH", - "built-ins/Date/prototype/Symbol.toPrimitive/hint-string-first-valid.js": "CRASH", - "built-ins/Date/prototype/Symbol.toPrimitive/hint-string-no-callables.js": "CRASH", - "built-ins/Date/prototype/Symbol.toPrimitive/this-val-non-obj.js": "CRASH", "built-ins/Date/prototype/getDate/not-a-constructor.js": "CRASH", "built-ins/Date/prototype/getDate/this-value-invalid-date.js": "CRASH", "built-ins/Date/prototype/getDate/this-value-valid-date.js": "CRASH", @@ -29326,7 +29312,6 @@ "language/white-space/string-nbsp.js": "FAIL", "language/white-space/string-space.js": "FAIL", "language/white-space/string-vertical-tab.js": "FAIL", - "language/expressions/object/11.1.5-0-1.js": "PASS", "staging/ArrayBuffer/resizable/access-out-of-bounds-typed-array.js": "CRASH", "staging/ArrayBuffer/resizable/array-fill-parameter-conversion-resizes.js": "CRASH", "staging/ArrayBuffer/resizable/array-sort-with-default-comparison.js": "CRASH",