Implement @@toStringTag well-known symbol related features (#2739)
JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu
This commit is contained in:
committed by
László Langó
parent
ca8442c523
commit
5c1a4f18ea
@@ -33,6 +33,13 @@ ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_BYTE_LENGTH_UL,
|
||||
ecma_builtin_arraybuffer_prototype_bytelength_getter,
|
||||
ECMA_PROPERTY_FIXED)
|
||||
|
||||
#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
|
||||
/* ECMA-262 v6, 24.1.4.4 */
|
||||
STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG,
|
||||
LIT_MAGIC_STRING_ARRAY_BUFFER_UL,
|
||||
ECMA_PROPERTY_FLAG_CONFIGURABLE)
|
||||
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */
|
||||
|
||||
/* Routine properties:
|
||||
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
|
||||
ROUTINE (LIT_MAGIC_STRING_SLICE, ecma_builtin_arraybuffer_prototype_object_slice, 2, 2)
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
#include "ecma-conversion.h"
|
||||
#include "ecma-function-object.h"
|
||||
#include "ecma-exceptions.h"
|
||||
#include "ecma-gc.h"
|
||||
#include "ecma-helpers.h"
|
||||
#include "jmem.h"
|
||||
#include "ecma-objects.h"
|
||||
#include "ecma-try-catch-macro.h"
|
||||
#include "lit-magic-strings.h"
|
||||
@@ -33,6 +35,69 @@
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
|
||||
/**
|
||||
* Helper function for Object.prototype.toString routine when
|
||||
* the @@toStringTag property is present
|
||||
*
|
||||
* See also:
|
||||
* ECMA-262 v6, 19.1.3.6
|
||||
*
|
||||
* @return ecma value
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
static ecma_value_t
|
||||
ecma_builtin_helper_object_to_string_tag_helper (ecma_value_t tag_value) /**< string tag */
|
||||
{
|
||||
JERRY_ASSERT (ecma_is_value_string (tag_value));
|
||||
|
||||
ecma_string_t *tag_str_p = ecma_get_string_from_value (tag_value);
|
||||
ecma_string_t *ret_string_p;
|
||||
|
||||
/* Building string "[object #@@toStringTag#]"
|
||||
The string size will be size("[object ") + size(#@@toStringTag#) + size ("]"). */
|
||||
const lit_utf8_size_t buffer_size = 9 + ecma_string_get_size (tag_str_p);
|
||||
JMEM_DEFINE_LOCAL_ARRAY (str_buffer, buffer_size, lit_utf8_byte_t);
|
||||
|
||||
lit_utf8_byte_t *buffer_ptr = str_buffer;
|
||||
|
||||
const lit_magic_string_id_t magic_string_ids[] =
|
||||
{
|
||||
LIT_MAGIC_STRING_LEFT_SQUARE_CHAR,
|
||||
LIT_MAGIC_STRING_OBJECT,
|
||||
LIT_MAGIC_STRING_SPACE_CHAR,
|
||||
};
|
||||
|
||||
/* Copy to buffer the "[object " string */
|
||||
for (uint32_t i = 0; i < sizeof (magic_string_ids) / sizeof (lit_magic_string_id_t); ++i)
|
||||
{
|
||||
buffer_ptr = lit_copy_magic_string_to_buffer (magic_string_ids[i], buffer_ptr,
|
||||
(lit_utf8_size_t) ((str_buffer + buffer_size) - buffer_ptr));
|
||||
|
||||
JERRY_ASSERT (buffer_ptr <= str_buffer + buffer_size);
|
||||
}
|
||||
|
||||
/* Copy to buffer the #@@toStringTag# string */
|
||||
buffer_ptr += ecma_string_copy_to_utf8_buffer (tag_str_p, buffer_ptr,
|
||||
(lit_utf8_size_t) ((str_buffer + buffer_size) - buffer_ptr));
|
||||
|
||||
JERRY_ASSERT (buffer_ptr <= str_buffer + buffer_size);
|
||||
|
||||
/* Copy to buffer the "]" string */
|
||||
buffer_ptr = lit_copy_magic_string_to_buffer (LIT_MAGIC_STRING_RIGHT_SQUARE_CHAR, buffer_ptr,
|
||||
(lit_utf8_size_t) ((str_buffer + buffer_size) - buffer_ptr));
|
||||
|
||||
JERRY_ASSERT (buffer_ptr <= str_buffer + buffer_size);
|
||||
|
||||
ret_string_p = ecma_new_ecma_string_from_utf8 (str_buffer, (lit_utf8_size_t) (buffer_ptr - str_buffer));
|
||||
|
||||
JMEM_FINALIZE_LOCAL_ARRAY (str_buffer);
|
||||
ecma_deref_ecma_string (tag_str_p);
|
||||
|
||||
return ecma_make_string_value (ret_string_p);
|
||||
} /* ecma_builtin_helper_object_to_string_tag_helper */
|
||||
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */
|
||||
|
||||
/**
|
||||
* Common implementation of the Object.prototype.toString routine
|
||||
*
|
||||
@@ -75,7 +140,25 @@ ecma_builtin_helper_object_to_string (const ecma_value_t this_arg) /**< this arg
|
||||
|
||||
type_string = ecma_object_get_class_name (obj_p);
|
||||
|
||||
ecma_free_value (obj_this);
|
||||
#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
|
||||
ecma_value_t tag_value = ecma_op_object_get_by_symbol_id (obj_p, LIT_MAGIC_STRING_TO_STRING_TAG);
|
||||
|
||||
if (ECMA_IS_VALUE_ERROR (tag_value))
|
||||
{
|
||||
ecma_deref_object (obj_p);
|
||||
return tag_value;
|
||||
}
|
||||
|
||||
if (ecma_is_value_string (tag_value))
|
||||
{
|
||||
ecma_deref_object (obj_p);
|
||||
return ecma_builtin_helper_object_to_string_tag_helper (tag_value);
|
||||
}
|
||||
|
||||
ecma_free_value (tag_value);
|
||||
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */
|
||||
|
||||
ecma_deref_object (obj_p);
|
||||
}
|
||||
|
||||
ecma_string_t *ret_string_p;
|
||||
|
||||
@@ -21,6 +21,13 @@
|
||||
|
||||
#ifndef CONFIG_DISABLE_JSON_BUILTIN
|
||||
|
||||
#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
|
||||
/* ECMA-262 v6, 24.3.3 */
|
||||
STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG,
|
||||
LIT_MAGIC_STRING_JSON_U,
|
||||
ECMA_PROPERTY_FLAG_CONFIGURABLE)
|
||||
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */
|
||||
|
||||
/* Routine properties:
|
||||
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
|
||||
ROUTINE (LIT_MAGIC_STRING_PARSE, ecma_builtin_json_parse, 2, 2)
|
||||
|
||||
@@ -29,6 +29,13 @@ OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR,
|
||||
ECMA_BUILTIN_ID_MAP,
|
||||
ECMA_PROPERTY_CONFIGURABLE_WRITABLE)
|
||||
|
||||
#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
|
||||
/* ECMA-262 v6, 23.1.3.13 */
|
||||
STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG,
|
||||
LIT_MAGIC_STRING_MAP_UL,
|
||||
ECMA_PROPERTY_FLAG_CONFIGURABLE)
|
||||
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */
|
||||
|
||||
/* Routine properties:
|
||||
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
|
||||
ROUTINE (LIT_MAGIC_STRING_CLEAR, ecma_builtin_map_prototype_object_clear, 0, 0)
|
||||
|
||||
@@ -64,6 +64,13 @@ NUMBER_VALUE (LIT_MAGIC_STRING_SQRT2_U,
|
||||
ECMA_BUILTIN_NUMBER_SQRT2,
|
||||
ECMA_PROPERTY_FIXED)
|
||||
|
||||
#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
|
||||
/* ECMA-262 v6, 20.2.1.9 */
|
||||
STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG,
|
||||
LIT_MAGIC_STRING_MATH_UL,
|
||||
ECMA_PROPERTY_FLAG_CONFIGURABLE)
|
||||
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */
|
||||
|
||||
/* Routine properties:
|
||||
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
|
||||
ROUTINE (LIT_MAGIC_STRING_ABS, ECMA_MATH_OBJECT_ABS, 1, 1)
|
||||
|
||||
@@ -28,6 +28,13 @@ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
|
||||
1,
|
||||
ECMA_PROPERTY_FLAG_WRITABLE)
|
||||
|
||||
#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
|
||||
/* ECMA-262 v6, 25.4.5.4 */
|
||||
STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG,
|
||||
LIT_MAGIC_STRING_PROMISE_UL,
|
||||
ECMA_PROPERTY_FLAG_CONFIGURABLE)
|
||||
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */
|
||||
|
||||
ROUTINE (LIT_MAGIC_STRING_THEN, ecma_builtin_promise_prototype_then, 2, 2)
|
||||
ROUTINE (LIT_MAGIC_STRING_CATCH, ecma_builtin_promise_prototype_catch, 1, 1)
|
||||
|
||||
|
||||
@@ -140,6 +140,28 @@ ecma_builtin_typedarray_prototype_length_getter (ecma_value_t this_arg) /**< thi
|
||||
return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a TypedArray."));
|
||||
} /* ecma_builtin_typedarray_prototype_length_getter */
|
||||
|
||||
#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
|
||||
/**
|
||||
* The %TypedArray%.prototype[Symbol.toStringTag] accessor
|
||||
*
|
||||
* See also:
|
||||
* ES2015, 22.2.3.31
|
||||
*
|
||||
* @return ecma value
|
||||
* Returned value must be freed with ecma_free_value.
|
||||
*/
|
||||
static ecma_value_t
|
||||
ecma_builtin_typedarray_prototype_to_string_tag_getter (ecma_value_t this_arg) /**< this argument */
|
||||
{
|
||||
if (!ecma_is_typedarray (this_arg))
|
||||
{
|
||||
return ECMA_VALUE_UNDEFINED;
|
||||
}
|
||||
|
||||
return ecma_make_magic_string_value (ecma_object_get_class_name (ecma_get_object_from_value (this_arg)));
|
||||
} /* ecma_builtin_typedarray_prototype_to_string_tag_getter */
|
||||
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */
|
||||
|
||||
/**
|
||||
* Type of routine.
|
||||
*/
|
||||
|
||||
@@ -45,6 +45,13 @@ ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_LENGTH,
|
||||
ecma_builtin_typedarray_prototype_length_getter,
|
||||
ECMA_PROPERTY_FIXED)
|
||||
|
||||
#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
|
||||
/* ECMA-262 v6, 23.1.3.13 */
|
||||
ACCESSOR_READ_ONLY (LIT_GLOBAL_SYMBOL_TO_STRING_TAG,
|
||||
ecma_builtin_typedarray_prototype_to_string_tag_getter,
|
||||
ECMA_PROPERTY_FLAG_CONFIGURABLE)
|
||||
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */
|
||||
|
||||
/* Routine properties:
|
||||
* (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */
|
||||
ROUTINE (LIT_MAGIC_STRING_TO_STRING_UL, ecma_builtin_typedarray_prototype_object_to_string, 0, 0)
|
||||
|
||||
@@ -734,6 +734,30 @@ ecma_op_object_get_by_magic_id (ecma_object_t *object_p, /**< the object */
|
||||
return ecma_op_object_get (object_p, ecma_get_magic_string (property_id));
|
||||
} /* ecma_op_object_get_by_magic_id */
|
||||
|
||||
#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
|
||||
/**
|
||||
* [[Get]] operation of ecma object where the property is a well-known symbol
|
||||
*
|
||||
* @return ecma value
|
||||
* Returned value must be freed with ecma_free_value
|
||||
*/
|
||||
ecma_value_t
|
||||
ecma_op_object_get_by_symbol_id (ecma_object_t *object_p, /**< the object */
|
||||
lit_magic_string_id_t property_id) /**< property symbol id */
|
||||
{
|
||||
ecma_value_t symbol_value = ecma_op_object_get_by_magic_id (ecma_builtin_get (ECMA_BUILTIN_ID_SYMBOL),
|
||||
property_id);
|
||||
JERRY_ASSERT (ecma_is_value_symbol (symbol_value));
|
||||
|
||||
ecma_string_t *symbol_p = ecma_get_symbol_from_value (symbol_value);
|
||||
ecma_value_t ret_value = ecma_op_object_get (object_p, symbol_p);
|
||||
|
||||
ecma_deref_ecma_string (symbol_p);
|
||||
|
||||
return ret_value;
|
||||
} /* ecma_op_object_get_by_symbol_id */
|
||||
#endif /* !CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */
|
||||
|
||||
/**
|
||||
* [[Put]] ecma general object's operation
|
||||
*
|
||||
|
||||
@@ -35,6 +35,9 @@ ecma_value_t ecma_op_object_find (ecma_object_t *object_p, ecma_string_t *proper
|
||||
ecma_value_t ecma_op_object_get_own_data_prop (ecma_object_t *object_p, ecma_string_t *property_name_p);
|
||||
ecma_value_t ecma_op_object_get (ecma_object_t *object_p, ecma_string_t *property_name_p);
|
||||
ecma_value_t ecma_op_object_get_by_magic_id (ecma_object_t *object_p, lit_magic_string_id_t property_id);
|
||||
#ifndef CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN
|
||||
ecma_value_t ecma_op_object_get_by_symbol_id (ecma_object_t *object_p, lit_magic_string_id_t property_id);
|
||||
#endif /* CONFIG_DISABLE_ES2015_SYMBOL_BUILTIN */
|
||||
ecma_value_t ecma_op_object_put (ecma_object_t *object_p, ecma_string_t *property_name_p, ecma_value_t value,
|
||||
bool is_throw);
|
||||
ecma_value_t ecma_op_object_delete (ecma_object_t *obj_p, ecma_string_t *property_name_p, bool is_throw);
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
// 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.
|
||||
|
||||
/* Symbol prototype @@toStringTag */
|
||||
assert (Symbol.prototype[Symbol.toStringTag] === "Symbol");
|
||||
assert (Object.prototype.toString.call (Symbol ()) === "[object Symbol]");
|
||||
|
||||
assert (delete Symbol.prototype[Symbol.toStringTag]);
|
||||
assert (Symbol.prototype[Symbol.toStringTag] === undefined);
|
||||
Symbol.prototype[Symbol.toStringTag] = "myStringTag1";
|
||||
assert (Object.prototype.toString.call (Symbol ()) === "[object myStringTag1]");
|
||||
Symbol.prototype[Symbol.toStringTag] = {};
|
||||
assert (Object.prototype.toString.call (Symbol ()) === "[object Symbol]");
|
||||
|
||||
/* Math @@toStringTag */
|
||||
assert (Math[Symbol.toStringTag] === "Math");
|
||||
assert (Object.prototype.toString.call (Math) === "[object Math]");
|
||||
|
||||
assert (delete Math[Symbol.toStringTag]);
|
||||
assert (Math[Symbol.toStringTag] === undefined);
|
||||
Math[Symbol.toStringTag] = "myStringTag2";
|
||||
assert (Object.prototype.toString.call (Math) === "[object myStringTag2]");
|
||||
Math[Symbol.toStringTag] = {};
|
||||
assert (Object.prototype.toString.call (Math) === "[object Math]");
|
||||
|
||||
/* ArrayBuffer.prototype @@toStringTag */
|
||||
assert (ArrayBuffer.prototype[Symbol.toStringTag] === "ArrayBuffer");
|
||||
assert (Object.prototype.toString.call (new ArrayBuffer ()) === "[object ArrayBuffer]");
|
||||
|
||||
assert (delete ArrayBuffer.prototype[Symbol.toStringTag]);
|
||||
assert (ArrayBuffer.prototype[Symbol.toStringTag] === undefined);
|
||||
ArrayBuffer.prototype[Symbol.toStringTag] = "myStringTag3";
|
||||
assert (Object.prototype.toString.call (new ArrayBuffer ()) === "[object myStringTag3]");
|
||||
ArrayBuffer.prototype[Symbol.toStringTag] = {};
|
||||
assert (ArrayBuffer.prototype.toString.call (new ArrayBuffer ()) === "[object ArrayBuffer]");
|
||||
|
||||
/* Promise.prototype @@toStringTag */
|
||||
assert (Promise.prototype[Symbol.toStringTag] === "Promise");
|
||||
assert (Object.prototype.toString.call (new Promise (function () {})) === "[object Promise]");
|
||||
|
||||
assert (delete Promise.prototype[Symbol.toStringTag]);
|
||||
assert (Promise.prototype[Symbol.toStringTag] === undefined);
|
||||
Promise.prototype[Symbol.toStringTag] = "myStringTag4";
|
||||
assert (Object.prototype.toString.call (new Promise (function () {})) === "[object myStringTag4]");
|
||||
Promise.prototype[Symbol.toStringTag] = {};
|
||||
assert (Promise.prototype.toString.call (new Promise (function () {})) === "[object Promise]");
|
||||
|
||||
/* Map.prototype @@toStringTag */
|
||||
assert (Map.prototype[Symbol.toStringTag] === "Map");
|
||||
assert (Object.prototype.toString.call (new Map ()) === "[object Map]");
|
||||
assert (Object.prototype.toString.call (Map) === "[object Function]");
|
||||
|
||||
assert (delete Map.prototype[Symbol.toStringTag]);
|
||||
assert (Map.prototype[Symbol.toStringTag] === undefined);
|
||||
Map.prototype[Symbol.toStringTag] = "myStringTag5";
|
||||
assert (Map.prototype.toString.call (new Map ()) === "[object myStringTag5]");
|
||||
assert (Object.prototype.toString.call (Map) === "[object Function]");
|
||||
Map.prototype[Symbol.toStringTag] = {};
|
||||
assert (Map.prototype.toString.call (new Map) === "[object Map]");
|
||||
|
||||
/* JSON @@toStringTag */
|
||||
assert (JSON[Symbol.toStringTag] === "JSON");
|
||||
assert (Object.prototype.toString.call (JSON) === "[object JSON]");
|
||||
|
||||
assert (delete JSON[Symbol.toStringTag]);
|
||||
assert (JSON[Symbol.toStringTag] === undefined);
|
||||
JSON[Symbol.toStringTag] = "myStringTag6";
|
||||
assert (Map.prototype.toString.call (JSON) === "[object myStringTag6]");
|
||||
JSON[Symbol.toStringTag] = {};
|
||||
assert (Object.prototype.toString.call (JSON) === "[object JSON]");
|
||||
|
||||
var typedArrayTypes = ["Int8Array",
|
||||
"Uint8Array",
|
||||
"Uint8ClampedArray",
|
||||
"Int16Array",
|
||||
"Uint16Array",
|
||||
"Int32Array",
|
||||
"Uint32Array",
|
||||
"Float32Array",
|
||||
"Float64Array"];
|
||||
|
||||
for (var i = 0; i < typedArrayTypes.length; i++) {
|
||||
var typedArray = this[typedArrayTypes[i]];
|
||||
assert (typedArray.prototype[Symbol.toStringTag] === undefined);
|
||||
assert (Object.prototype.toString.call (typedArray) === "[object Function]");
|
||||
assert (Object.prototype.toString.call (typedArray.prototype) === "[object Object]");
|
||||
|
||||
var newArray = new typedArray ();
|
||||
assert (newArray[Symbol.toStringTag] === typedArrayTypes[i]);
|
||||
assert (Object.prototype.toString.call (newArray) === "[object " + typedArrayTypes[i] + "]");
|
||||
}
|
||||
Reference in New Issue
Block a user