From e8c5c46894a68626bcb456f1e3b0b9d0d74ed304 Mon Sep 17 00:00:00 2001 From: Szilagyi Adam Date: Mon, 20 Jul 2020 13:47:25 +0200 Subject: [PATCH] Implement Symbol.prototype.description (#3995) The algorithm is based on ECMA-262 v11, 19.4.3.2 Also added a custom dispatcher for the Symbol prototype JerryScript-DCO-1.0-Signed-off-by: Adam Szilagyi aszilagy@inf.u-szeged.hu --- .../ecma-builtin-symbol-prototype.c | 85 +++++++++++-------- .../ecma-builtin-symbol-prototype.inc.h | 10 ++- .../ecma/operations/ecma-symbol-object.c | 26 +++--- .../ecma/operations/ecma-symbol-object.h | 2 +- jerry-core/lit/lit-magic-strings.inc.h | 3 + jerry-core/lit/lit-magic-strings.ini | 1 + .../es.next/symbol-prototype-description.js | 75 ++++++++++++++++ 7 files changed, 149 insertions(+), 53 deletions(-) create mode 100644 tests/jerry/es.next/symbol-prototype-description.js diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-symbol-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-symbol-prototype.c index 1ac623d1c..ae559a792 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-symbol-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-symbol-prototype.c @@ -30,6 +30,23 @@ #define ECMA_BUILTINS_INTERNAL #include "ecma-builtins-internal.h" +/** + * This object has a custom dispatch function. + */ +#define BUILTIN_CUSTOM_DISPATCH + +/** + * List of built-in routine identifiers. + */ +enum +{ + ECMA_SYMBOL_PROTOTYPE_ROUTINE_START = ECMA_BUILTIN_ID__COUNT - 1, + ECMA_SYMBOL_PROTOTYPE_VALUE_OF, /**< ECMA-262 v11, 19.4.3.4 */ + ECMA_SYMBOL_PROTOTYPE_TO_PRIMITIVE, /**< ECMA-262 v11, 19.4.3.5 */ + ECMA_SYMBOL_PROTOTYPE_TO_STRING, /**< ECMA-262 v11, 19.4.3.3 */ + ECMA_SYMBOL_PROTOTYPE_DESCRIPTION, /**< ECMA-262 v11, 19.4.3.2 */ +}; + #define BUILTIN_INC_HEADER_NAME "ecma-builtin-symbol-prototype.inc.h" #define BUILTIN_UNDERSCORED_ID symbol_prototype #include "ecma-builtin-internal-routines-template.inc.h" @@ -45,49 +62,45 @@ */ /** - * The Symbol.prototype object's 'toString' routine - * - * See also: - * ECMA-262 v6, 19.4.3.2 + * Dispatcher of the Symbol built-in's routines * * @return ecma value * Returned value must be freed with ecma_free_value. */ -static ecma_value_t -ecma_builtin_symbol_prototype_object_to_string (ecma_value_t this_arg) /**< this argument */ +ecma_value_t +ecma_builtin_symbol_prototype_dispatch_routine (uint16_t builtin_routine_id, /**< built-in wide routine + * identifier */ + ecma_value_t this_arg, /**< 'this' argument value */ + const ecma_value_t arguments_list[], /**< list of arguments + * passed to routine */ + ecma_length_t arguments_number) /**< length of arguments' list */ { - return ecma_symbol_to_string_helper (this_arg, true); -} /* ecma_builtin_symbol_prototype_object_to_string */ + JERRY_UNUSED_2 (arguments_list, arguments_number); -/** - * The Symbol.prototype object's 'valueOf' routine - * - * See also: - * ECMA-262 v6, 19.4.3.3 - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_symbol_prototype_object_value_of (ecma_value_t this_arg) /**< this argument */ -{ - return ecma_symbol_to_string_helper (this_arg, false); -} /* ecma_builtin_symbol_prototype_object_value_of */ + ecma_value_t sym = ecma_symbol_this_value (this_arg); -/** - * The Symbol.prototype object's '@@toPrimitive' routine - * - * See also: - * ECMA-262 v6, 19.4.3.3 - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_symbol_prototype_object_to_primitive (ecma_value_t this_arg) /**< this argument */ -{ - return ecma_builtin_symbol_prototype_object_value_of (this_arg); -} /* ecma_builtin_symbol_prototype_object_to_primitive */ + if (ECMA_IS_VALUE_ERROR (sym)) + { + return sym; + } + + if (builtin_routine_id < ECMA_SYMBOL_PROTOTYPE_TO_STRING) + { + return ecma_copy_value (sym); + } + + if (builtin_routine_id == ECMA_SYMBOL_PROTOTYPE_TO_STRING) + { + return ecma_get_symbol_descriptive_string (sym); + } + + JERRY_ASSERT (builtin_routine_id == ECMA_SYMBOL_PROTOTYPE_DESCRIPTION); + ecma_string_t *symbol_p = ecma_get_symbol_from_value (sym); + ecma_string_t *desc_p = ecma_get_symbol_description (symbol_p); + ecma_ref_ecma_string (desc_p); + + return ecma_make_string_value (desc_p); +} /* ecma_builtin_symbol_prototype_dispatch_routine */ /** * @} diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-symbol-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-symbol-prototype.inc.h index 317aa8872..d502de18f 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-symbol-prototype.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-symbol-prototype.inc.h @@ -28,10 +28,10 @@ OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, ECMA_BUILTIN_ID_SYMBOL, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) -ROUTINE (LIT_MAGIC_STRING_TO_STRING_UL, ecma_builtin_symbol_prototype_object_to_string, 0, 0) -ROUTINE (LIT_MAGIC_STRING_VALUE_OF_UL, ecma_builtin_symbol_prototype_object_value_of, 0, 0) +ROUTINE (LIT_MAGIC_STRING_TO_STRING_UL, ECMA_SYMBOL_PROTOTYPE_TO_STRING, 0, 0) +ROUTINE (LIT_MAGIC_STRING_VALUE_OF_UL, ECMA_SYMBOL_PROTOTYPE_VALUE_OF, 0, 0) ROUTINE_CONFIGURABLE_ONLY (LIT_GLOBAL_SYMBOL_TO_PRIMITIVE, - ecma_builtin_symbol_prototype_object_to_primitive, + ECMA_SYMBOL_PROTOTYPE_TO_PRIMITIVE, 0, 1) @@ -40,6 +40,10 @@ STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, LIT_MAGIC_STRING_SYMBOL_UL, ECMA_PROPERTY_FLAG_CONFIGURABLE) +/* ECMA-262, v11, 19.4.3.2 */ +ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_DESCRIPTION, + ECMA_SYMBOL_PROTOTYPE_DESCRIPTION, + ECMA_PROPERTY_FLAG_CONFIGURABLE) #endif /* ENABLED (JERRY_ESNEXT) */ #include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/operations/ecma-symbol-object.c b/jerry-core/ecma/operations/ecma-symbol-object.c index 04926c8fd..2e24721a8 100644 --- a/jerry-core/ecma/operations/ecma-symbol-object.c +++ b/jerry-core/ecma/operations/ecma-symbol-object.c @@ -137,42 +137,42 @@ ecma_get_symbol_descriptive_string (ecma_value_t symbol_value) /**< symbol to st } /* ecma_get_symbol_descriptive_string */ /** - * Helper for Symbol.prototype.{toString, valueOf} routines + * thisSymbolValue abstract operation * - * See also: 19.4.3.2, 19.4.3.3 + * See also: + * ECMA-262 v11, 19.4.3 * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t -ecma_symbol_to_string_helper (ecma_value_t this_arg, /**< this argument value */ - bool is_to_string) /**< true - perform the 'toString' routine steps - * false - perform the 'valueOf' routine steps */ +ecma_symbol_this_value (ecma_value_t this_arg) /**< this argument value */ { + /* 1. */ if (ecma_is_value_symbol (this_arg)) { - return is_to_string ? ecma_get_symbol_descriptive_string (this_arg) : ecma_copy_value (this_arg); + return this_arg; } + /* 2. */ if (ecma_is_value_object (this_arg)) { ecma_object_t *object_p = ecma_get_object_from_value (this_arg); if (ecma_get_object_type (object_p) == ECMA_OBJECT_TYPE_CLASS) { - ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; + ecma_extended_object_t *ext_obj_p = (ecma_extended_object_t *) object_p; - if (ext_object_p->u.class_prop.class_id == LIT_MAGIC_STRING_SYMBOL_UL) + if (ext_obj_p->u.class_prop.class_id == LIT_MAGIC_STRING_SYMBOL_UL) { - return (is_to_string ? ecma_get_symbol_descriptive_string (ext_object_p->u.class_prop.u.value) - : ecma_copy_value (ext_object_p->u.class_prop.u.value)); + return ext_obj_p->u.class_prop.u.value; } } } - return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is must be a Symbol.")); -} /* ecma_symbol_to_string_helper */ - + /* 3. */ + return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' must be a Symbol.")); +} /* ecma_symbol_this_value */ #endif /* ENABLED (JERRY_ESNEXT) */ /** diff --git a/jerry-core/ecma/operations/ecma-symbol-object.h b/jerry-core/ecma/operations/ecma-symbol-object.h index 7a9bc643a..410f40f50 100644 --- a/jerry-core/ecma/operations/ecma-symbol-object.h +++ b/jerry-core/ecma/operations/ecma-symbol-object.h @@ -39,7 +39,7 @@ ecma_string_t * ecma_get_symbol_description (ecma_string_t *symbol_p); ecma_value_t -ecma_symbol_to_string_helper (ecma_value_t this_arg, bool is_to_string); +ecma_symbol_this_value (ecma_value_t this_arg); ecma_value_t ecma_get_symbol_descriptive_string (ecma_value_t symbol_value); diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index e9614ca46..0befa04cb 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -721,6 +721,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UINT32_ARRAY_UL, "Uint32Array") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CODE_POINT_AT, "codePointAt") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CONSTRUCTOR, "constructor") +#if ENABLED (JERRY_ESNEXT) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DESCRIPTION, "description") +#endif #if ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_FULL_YEAR_UL, "getFullYear") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UTC_HOURS_UL, "getUTCHours") diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index e2757cfc9..ac2019225 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -285,6 +285,7 @@ LIT_MAGIC_STRING_SET_UTC_DATE_UL = "setUTCDate" LIT_MAGIC_STRING_STARTS_WITH = "startsWith" LIT_MAGIC_STRING_RESOURCE_ANON = "" LIT_MAGIC_STRING_ARRAY_BUFFER_UL = "ArrayBuffer" +LIT_MAGIC_STRING_DESCRIPTION = "description" LIT_MAGIC_STRING_SYNTAX_ERROR_UL = "SyntaxError" LIT_MAGIC_STRING_UINT16_ARRAY_UL = "Uint16Array" LIT_MAGIC_STRING_UINT32_ARRAY_UL = "Uint32Array" diff --git a/tests/jerry/es.next/symbol-prototype-description.js b/tests/jerry/es.next/symbol-prototype-description.js new file mode 100644 index 000000000..cee7f8220 --- /dev/null +++ b/tests/jerry/es.next/symbol-prototype-description.js @@ -0,0 +1,75 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +assert(Symbol('desc').description === "desc"); +assert(Symbol.iterator.description === "Symbol.iterator"); +assert(Symbol.for('foo').description === "foo"); +assert(`${Symbol('foo').description}bar` === "foobar"); + +var desc = Object.getOwnPropertyDescriptor(Symbol.prototype, 'description'); + +assert(desc.set === undefined); +assert(typeof desc.get === "function"); +assert(desc.writable === undefined); +assert(desc.enumerable === false); +assert(desc.configurable === true); + +var sym = Symbol('foo') +assert(desc.get.call(Object(sym)) === "foo") + +var obj_sym = Object(Symbol('foo')); +assert(obj_sym.description === "foo"); + +try { + desc.get.call(null); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + desc.get.call(123); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + desc.get.call('test'); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + desc.get.call(undefined); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + desc.get.call({}); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +} + +try { + desc.get.call(new Proxy({}, {})); + assert(false); +} catch (e) { + assert(e instanceof TypeError); +}