From 4331e39b9ab001f81265780c2e6e6060eeab989b Mon Sep 17 00:00:00 2001 From: Robert Fancsik Date: Fri, 10 May 2019 20:28:43 +0200 Subject: [PATCH] Implement the Set builtin object (#2841) Also implement the missing iterator initializer part from the Map builtin object constructor. JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu --- jerry-core/config.h | 8 + jerry-core/ecma/base/ecma-gc.c | 7 +- .../builtin-objects/ecma-builtin-global.inc.h | 7 + .../ecma-builtin-map-prototype.c | 16 +- .../ecma/builtin-objects/ecma-builtin-map.c | 4 +- .../ecma-builtin-set-prototype.c | 143 ++++++++++ .../ecma-builtin-set-prototype.inc.h | 53 ++++ .../ecma/builtin-objects/ecma-builtin-set.c | 71 +++++ .../builtin-objects/ecma-builtin-set.inc.h | 47 +++ .../ecma/builtin-objects/ecma-builtins.inc.h | 18 ++ ...a-map-object.c => ecma-container-object.c} | 270 +++++++++++++----- .../ecma/operations/ecma-container-object.h | 49 ++++ .../ecma/operations/ecma-iterator-object.c | 235 +++++++++++++++ .../ecma/operations/ecma-iterator-object.h | 9 + jerry-core/ecma/operations/ecma-map-object.h | 47 --- jerry-core/ecma/operations/ecma-objects.c | 53 ++++ jerry-core/ecma/operations/ecma-objects.h | 1 + jerry-core/lit/lit-magic-strings.inc.h | 23 +- jerry-core/lit/lit-magic-strings.ini | 2 + jerry-core/profiles/README.md | 4 + tests/jerry/es2015/map.js | 6 + tests/jerry/es2015/set.js | 89 ++++++ 22 files changed, 1031 insertions(+), 131 deletions(-) create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-set-prototype.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-set-prototype.inc.h create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-set.c create mode 100644 jerry-core/ecma/builtin-objects/ecma-builtin-set.inc.h rename jerry-core/ecma/operations/{ecma-map-object.c => ecma-container-object.c} (55%) create mode 100644 jerry-core/ecma/operations/ecma-container-object.h delete mode 100644 jerry-core/ecma/operations/ecma-map-object.h create mode 100644 tests/jerry/es2015/set.js diff --git a/jerry-core/config.h b/jerry-core/config.h index 8f87e5e72..23fa383c3 100644 --- a/jerry-core/config.h +++ b/jerry-core/config.h @@ -86,6 +86,10 @@ # define JERRY_ES2015_BUILTIN_MAP JERRY_ES2015 #endif /* !defined (JERRY_ES2015_BUILTIN_MAP) */ +#ifndef JERRY_ES2015_BUILTIN_SET +# define JERRY_ES2015_BUILTIN_SET JERRY_ES2015 +#endif /* !defined (JERRY_ES2015_BUILTIN_SET) */ + #ifndef JERRY_ES2015_BUILTIN_PROMISE # define JERRY_ES2015_BUILTIN_PROMISE JERRY_ES2015 #endif /* !defined (JERRY_ES2015_BUILTIN_PROMISE) */ @@ -274,6 +278,10 @@ || ((JERRY_ES2015_BUILTIN_MAP != 0) && (JERRY_ES2015_BUILTIN_MAP != 1)) # error "Invalid value for JERRY_ES2015_BUILTIN_MAP macro." #endif +#if !defined (JERRY_ES2015_BUILTIN_SET) \ +|| ((JERRY_ES2015_BUILTIN_SET != 0) && (JERRY_ES2015_BUILTIN_SET != 1)) +# error "Invalid value for JERRY_ES2015_BUILTIN_SET macro." +#endif #if !defined (JERRY_ES2015_BUILTIN_PROMISE) \ || ((JERRY_ES2015_BUILTIN_PROMISE != 0) && (JERRY_ES2015_BUILTIN_PROMISE != 1)) # error "Invalid value for JERRY_ES2015_BUILTIN_PROMISE macro." diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index a78712bda..86617fd50 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -37,7 +37,7 @@ #include "ecma-promise-object.h" #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ #if ENABLED (JERRY_ES2015_BUILTIN_MAP) -#include "ecma-map-object.h" +#include "ecma-container-object.h" #endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ /* TODO: Extract GC to a separate component */ @@ -639,10 +639,13 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */ return; } #endif /* ENABLED (JERRY_ES2015_BUILTIN_PROMISE) */ +#if ENABLED (JERRY_ES2015_BUILTIN_SET) + case LIT_MAGIC_STRING_SET_UL: +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ #if ENABLED (JERRY_ES2015_BUILTIN_MAP) case LIT_MAGIC_STRING_MAP_UL: { - ecma_op_map_clear_map ((ecma_map_object_t *) object_p); + ecma_op_container_clear_map ((ecma_map_object_t *) object_p); ecma_dealloc_extended_object (object_p, sizeof (ecma_map_object_t)); return; } diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h index 164ed7ae1..4964887f2 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-global.inc.h @@ -205,6 +205,13 @@ OBJECT_VALUE (LIT_MAGIC_STRING_MAP_UL, ECMA_PROPERTY_CONFIGURABLE_WRITABLE) #endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_SET) +/* ECMA-262 v6, 23.1.1.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_SET_UL, + ECMA_BUILTIN_ID_SET, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ + #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) /* ECMA-262 v6, 19.4.1.1 */ OBJECT_VALUE (LIT_MAGIC_STRING_SYMBOL_UL, diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.c index 5a8941beb..de6d8b1af 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-map-prototype.c @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "ecma-map-object.h" +#include "ecma-container-object.h" #if ENABLED (JERRY_ES2015_BUILTIN_MAP) @@ -46,7 +46,7 @@ static ecma_value_t ecma_builtin_map_prototype_object_clear (ecma_value_t this_arg) /**< this argument */ { - return ecma_op_map_clear (this_arg); + return ecma_op_container_clear (this_arg, false); } /* ecma_builtin_map_prototype_object_clear */ /** @@ -62,7 +62,7 @@ static ecma_value_t ecma_builtin_map_prototype_object_delete (ecma_value_t this_arg, /**< this argument */ ecma_value_t key_arg) /**< key argument */ { - return ecma_op_map_delete (this_arg, key_arg); + return ecma_op_container_delete (this_arg, key_arg, false); } /* ecma_builtin_map_prototype_object_delete */ /** @@ -80,7 +80,7 @@ ecma_builtin_map_prototype_object_foreach (ecma_value_t this_arg, /**< this argu ecma_value_t predicate_this_arg) /**< this argument for * invoke predicate */ { - return ecma_op_map_foreach (this_arg, predicate, predicate_this_arg); + return ecma_op_container_foreach (this_arg, predicate, predicate_this_arg, false); } /* ecma_builtin_map_prototype_object_foreach */ /** @@ -96,7 +96,7 @@ static ecma_value_t ecma_builtin_map_prototype_object_get (ecma_value_t this_arg, /**< this argument */ ecma_value_t key_arg) /**< key argument */ { - return ecma_op_map_get (this_arg, key_arg); + return ecma_op_container_get (this_arg, key_arg); } /* ecma_builtin_map_prototype_object_get */ /** @@ -112,7 +112,7 @@ static ecma_value_t ecma_builtin_map_prototype_object_has (ecma_value_t this_arg, /**< this argument */ ecma_value_t key_arg) /**< key argument */ { - return ecma_op_map_has (this_arg, key_arg); + return ecma_op_container_has (this_arg, key_arg, false); } /* ecma_builtin_map_prototype_object_has */ /** @@ -129,7 +129,7 @@ ecma_builtin_map_prototype_object_set (ecma_value_t this_arg, /**< this argument ecma_value_t key_arg, /**< key argument */ ecma_value_t value_arg) /**< value argument */ { - return ecma_op_map_set (this_arg, key_arg, value_arg); + return ecma_op_container_set (this_arg, key_arg, value_arg, false); } /* ecma_builtin_map_prototype_object_set */ /** @@ -144,7 +144,7 @@ ecma_builtin_map_prototype_object_set (ecma_value_t this_arg, /**< this argument static ecma_value_t ecma_builtin_map_prototype_object_size_getter (ecma_value_t this_arg) /**< this argument */ { - return ecma_op_map_size (this_arg); + return ecma_op_container_size (this_arg, false); } /* ecma_builtin_map_prototype_object_size_getter */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-map.c b/jerry-core/ecma/builtin-objects/ecma-builtin-map.c index d71d2e8db..fe8886f99 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-map.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-map.c @@ -15,7 +15,7 @@ #include "ecma-builtins.h" #include "ecma-exceptions.h" -#include "ecma-map-object.h" +#include "ecma-container-object.h" #if ENABLED (JERRY_ES2015_BUILTIN_MAP) @@ -59,7 +59,7 @@ ecma_value_t ecma_builtin_map_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ ecma_length_t arguments_list_len) /**< number of arguments */ { - return ecma_op_map_create (arguments_list_p, arguments_list_len); + return ecma_op_container_create (arguments_list_p, arguments_list_len, false); } /* ecma_builtin_map_dispatch_construct */ /** diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-set-prototype.c b/jerry-core/ecma/builtin-objects/ecma-builtin-set-prototype.c new file mode 100644 index 000000000..c052721b2 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-set-prototype.c @@ -0,0 +1,143 @@ +/* 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. + */ + +#include "ecma-container-object.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_SET) + +#if !ENABLED (JERRY_ES2015_BUILTIN_MAP) +#error "Set builtin requires ES2015 map builtin" +#endif /* !ENABLED (JERRY_ES2015_BUILTIN_MAP) */ + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-set-prototype.inc.h" +#define BUILTIN_UNDERSCORED_ID set_prototype +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup set ECMA Set object built-in + * @{ + */ + +/** + * The Set.prototype object's 'add' routine + * + * See also: + * ECMA-262 v6, 23.2.3.1 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_set_prototype_object_add (ecma_value_t this_arg, /**< this argument */ + ecma_value_t value_arg) /**< value argument */ +{ + return ecma_op_container_set (this_arg, value_arg, value_arg, true); +} /* ecma_builtin_set_prototype_object_add */ + +/** + * The Set.prototype object's 'clear' routine + * + * See also: + * ECMA-262 v6, 23.2.3.2 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_set_prototype_object_clear (ecma_value_t this_arg) /**< this argument */ +{ + return ecma_op_container_clear (this_arg, true); +} /* ecma_builtin_set_prototype_object_clear */ + +/** + * The Set.prototype object's 'delete' routine + * + * See also: + * ECMA-262 v6, 23.2.3.4 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_set_prototype_object_delete (ecma_value_t this_arg, /**< this argument */ + ecma_value_t value_arg) /**< value argument */ +{ + return ecma_op_container_delete (this_arg, value_arg, true); +} /* ecma_builtin_set_prototype_object_delete */ + +/** + * The Set.prototype object's 'forEach' routine + * + * See also: + * ECMA-262 v6, 23.2.3.6 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_set_prototype_object_foreach (ecma_value_t this_arg, /**< this argument */ + ecma_value_t predicate, /**< callback function */ + ecma_value_t predicate_this_arg) /**< this argument for + * invoke predicate */ +{ + return ecma_op_container_foreach (this_arg, predicate, predicate_this_arg, true); +} /* ecma_builtin_set_prototype_object_foreach */ + +/** + * The Set.prototype object's 'has' routine + * + * See also: + * ECMA-262 v6, 23.2.3.7 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_set_prototype_object_has (ecma_value_t this_arg, /**< this argument */ + ecma_value_t value_arg) /**< value argument */ +{ + return ecma_op_container_has (this_arg, value_arg, true); +} /* ecma_builtin_set_prototype_object_has */ + +/** + * The Set.prototype object's 'size' getter + * + * See also: + * ECMA-262 v6, 23.2.3.9 + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +static ecma_value_t +ecma_builtin_set_prototype_object_size_getter (ecma_value_t this_arg) /**< this argument */ +{ + return ecma_op_container_size (this_arg, true); +} /* ecma_builtin_set_prototype_object_size_getter */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-set-prototype.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-set-prototype.inc.h new file mode 100644 index 000000000..d6bf0d5df --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-set-prototype.inc.h @@ -0,0 +1,53 @@ +/* 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. + */ + +/* + * Set.prototype built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_SET) + +/* Object properties: + * (property name, object pointer getter) */ + +/* ECMA-262 v6, 23.2.3.2 */ +OBJECT_VALUE (LIT_MAGIC_STRING_CONSTRUCTOR, + ECMA_BUILTIN_ID_MAP, + ECMA_PROPERTY_CONFIGURABLE_WRITABLE) + +#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +/* ECMA-262 v6, 23.1.3.13 */ +STRING_VALUE (LIT_GLOBAL_SYMBOL_TO_STRING_TAG, + LIT_MAGIC_STRING_SET_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ + +/* Routine properties: + * (property name, C routine name, arguments number or NON_FIXED, value of the routine's length property) */ +ROUTINE (LIT_MAGIC_STRING_ADD, ecma_builtin_set_prototype_object_add, 1, 1) +ROUTINE (LIT_MAGIC_STRING_CLEAR, ecma_builtin_set_prototype_object_clear, 0, 0) +ROUTINE (LIT_MAGIC_STRING_DELETE, ecma_builtin_set_prototype_object_delete, 1, 1) +ROUTINE (LIT_MAGIC_STRING_FOR_EACH_UL, ecma_builtin_set_prototype_object_foreach, 2, 1) +ROUTINE (LIT_MAGIC_STRING_HAS, ecma_builtin_set_prototype_object_has, 1, 1) + +ACCESSOR_READ_ONLY (LIT_MAGIC_STRING_SIZE, + ecma_builtin_set_prototype_object_size_getter, + ECMA_PROPERTY_FIXED) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-set.c b/jerry-core/ecma/builtin-objects/ecma-builtin-set.c new file mode 100644 index 000000000..297b5c489 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-set.c @@ -0,0 +1,71 @@ +/* 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. + */ + +#include "ecma-builtins.h" +#include "ecma-exceptions.h" +#include "ecma-container-object.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_SET) + +#define ECMA_BUILTINS_INTERNAL +#include "ecma-builtins-internal.h" + +#define BUILTIN_INC_HEADER_NAME "ecma-builtin-set.inc.h" +#define BUILTIN_UNDERSCORED_ID set +#include "ecma-builtin-internal-routines-template.inc.h" + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmabuiltins + * @{ + * + * \addtogroup set ECMA Set object built-in + * @{ + */ + +/** + * Handle calling [[Call]] of built-in Set object + * + * @return ecma value + */ +ecma_value_t +ecma_builtin_set_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); + + return ecma_raise_type_error (ECMA_ERR_MSG ("Constructor Set requires 'new'.")); +} /* ecma_builtin_set_dispatch_call */ + +/** + * Handle calling [[Construct]] of built-in Map object + * + * @return ecma value + */ +ecma_value_t +ecma_builtin_set_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len) /**< number of arguments */ +{ + return ecma_op_container_create (arguments_list_p, arguments_list_len, true); +} /* ecma_builtin_set_dispatch_construct */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-set.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtin-set.inc.h new file mode 100644 index 000000000..c2847bbc4 --- /dev/null +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-set.inc.h @@ -0,0 +1,47 @@ +/* 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. + */ + +/* + * Set built-in description + */ + +#include "ecma-builtin-helpers-macro-defines.inc.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_SET) + +/* Number properties: + * (property name, number value, writable, enumerable, configurable) */ + +/* ECMA-262 v6, 23.2.2 */ +NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH, + 0, + ECMA_PROPERTY_FIXED) + +/* ECMA-262 v6, 23.1 */ +STRING_VALUE (LIT_MAGIC_STRING_NAME, + LIT_MAGIC_STRING_SET_UL, + ECMA_PROPERTY_FLAG_CONFIGURABLE) + +/* Object properties: + * (property name, object pointer getter) */ + +/* ECMA-262 v6, 23.2.2.1 */ +OBJECT_VALUE (LIT_MAGIC_STRING_PROTOTYPE, + ECMA_BUILTIN_ID_SET_PROTOTYPE, + ECMA_PROPERTY_FIXED) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ + +#include "ecma-builtin-helpers-macro-undefs.inc.h" diff --git a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h index 0254aa98d..5882c1182 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h +++ b/jerry-core/ecma/builtin-objects/ecma-builtins.inc.h @@ -441,6 +441,24 @@ BUILTIN_ROUTINE (ECMA_BUILTIN_ID_MAP, #endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_SET) + +/* The Set prototype object (23.1.3) */ +BUILTIN (ECMA_BUILTIN_ID_SET_PROTOTYPE, + ECMA_OBJECT_TYPE_GENERAL, + ECMA_BUILTIN_ID_OBJECT_PROTOTYPE, + true, + set_prototype) + +/* The Set routine (ECMA-262 v6, 23.1.1.1) */ +BUILTIN_ROUTINE (ECMA_BUILTIN_ID_SET, + ECMA_OBJECT_TYPE_FUNCTION, + ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE, + true, + set) + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ + #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) /* The Symbol prototype object (ECMA-262 v6, 19.4.2.7) */ diff --git a/jerry-core/ecma/operations/ecma-map-object.c b/jerry-core/ecma/operations/ecma-container-object.c similarity index 55% rename from jerry-core/ecma/operations/ecma-map-object.c rename to jerry-core/ecma/operations/ecma-container-object.c index 490b85675..003d6fb1c 100644 --- a/jerry-core/ecma/operations/ecma-map-object.c +++ b/jerry-core/ecma/operations/ecma-container-object.c @@ -19,7 +19,8 @@ #include "ecma-function-object.h" #include "ecma-gc.h" #include "ecma-helpers.h" -#include "ecma-map-object.h" +#include "ecma-iterator-object.h" +#include "ecma-container-object.h" #include "ecma-property-hashmap.h" #include "ecma-objects.h" @@ -28,19 +29,19 @@ /** \addtogroup ecma ECMA * @{ * - * \addtogroup \addtogroup ecmamaphelpers ECMA builtin map helper functions + * \addtogroup \addtogroup ecmamaphelpers ECMA builtin map/set helper functions * @{ */ /** - * Creates an empty object for the map object's internal slot. + * Creates an empty object for the map/set object's internal slot. * * Note: The created object is not registered to the GC. * * @return ecma value of the created object */ static ecma_value_t -ecma_op_map_create_internal_object (void) +ecma_op_container_create_internal_object (void) { ecma_object_t *internal_object_p = ecma_alloc_object (); internal_object_p->type_flags_refs = (ECMA_OBJECT_TYPE_GENERAL | ECMA_OBJECT_FLAG_EXTENSIBLE | ECMA_OBJECT_REF_ONE); @@ -48,58 +49,181 @@ ecma_op_map_create_internal_object (void) internal_object_p->prototype_or_outer_reference_cp = JMEM_CP_NULL; return ecma_make_object_value (internal_object_p); -} /* ecma_op_map_create_internal_object */ +} /* ecma_op_container_create_internal_object */ /** - * Handle calling [[Construct]] of built-in map like objects + * Handle calling [[Construct]] of built-in map/set like objects * * @return ecma value */ ecma_value_t -ecma_op_map_create (const ecma_value_t *arguments_list_p, /**< arguments list */ - ecma_length_t arguments_list_len) /**< number of arguments */ +ecma_op_container_create (const ecma_value_t *arguments_list_p, /**< arguments list */ + ecma_length_t arguments_list_len, /**< number of arguments */ + bool is_set) /**< true - to perform Set operations + * false - to perform Map operations */ { JERRY_ASSERT (arguments_list_len == 0 || arguments_list_p != NULL); - ecma_object_t *object_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_MAP_PROTOTYPE), + ecma_object_t *proto_p = ecma_builtin_get (is_set ? ECMA_BUILTIN_ID_SET_PROTOTYPE : ECMA_BUILTIN_ID_MAP_PROTOTYPE); + + ecma_object_t *object_p = ecma_create_object (proto_p, sizeof (ecma_map_object_t), ECMA_OBJECT_TYPE_CLASS); ecma_map_object_t *map_obj_p = (ecma_map_object_t *) object_p; - map_obj_p->header.u.class_prop.class_id = LIT_MAGIC_STRING_MAP_UL; - map_obj_p->header.u.class_prop.u.value = ecma_op_map_create_internal_object (); + map_obj_p->header.u.class_prop.class_id = is_set ? LIT_MAGIC_STRING_SET_UL : LIT_MAGIC_STRING_MAP_UL; + map_obj_p->header.u.class_prop.u.value = ecma_op_container_create_internal_object (); map_obj_p->size = 0; - return ecma_make_object_value (object_p); -} /* ecma_op_map_create */ + ecma_value_t set_value = ecma_make_object_value (object_p); + +#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) + if (arguments_list_len == 0) + { + return set_value; + } + + ecma_value_t iterable = arguments_list_p[0]; + + if (ecma_is_value_undefined (iterable) || ecma_is_value_null (iterable)) + { + return set_value; + } + + ecma_value_t iter = ecma_op_get_iterator (iterable, ECMA_VALUE_EMPTY); + + if (ECMA_IS_VALUE_ERROR (iter)) + { + ecma_deref_object (object_p); + return iter; + } + + while (true) + { + ecma_value_t next = ecma_op_iterator_step (iter); + + if (ECMA_IS_VALUE_ERROR (next)) + { + ecma_free_value (iter); + ecma_deref_object (object_p); + return next; + } + + if (ecma_is_value_false (next)) + { + break; + } + + ecma_value_t next_value = ecma_op_iterator_value (next); + + if (ECMA_IS_VALUE_ERROR (next_value)) + { + ecma_free_value (next); + ecma_free_value (iter); + ecma_deref_object (object_p); + return next_value; + } + + ecma_value_t result; + if (is_set) + { + result = ecma_op_container_set (set_value, next_value, next_value, is_set); + } + else + { + if (!ecma_is_value_object (next_value)) + { + // TODO close the iterator when generator function will be supported + ecma_free_value (next_value); + ecma_free_value (next); + ecma_free_value (iter); + ecma_deref_object (object_p); + return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator value is not an object.")); + } + + ecma_object_t *next_object_p = ecma_get_object_from_value (next_value); + + ecma_value_t key = ecma_op_object_get (next_object_p, ecma_new_ecma_string_from_uint32 (0)); + + if (ECMA_IS_VALUE_ERROR (key)) + { + // TODO close the iterator when generator function will be supported + ecma_free_value (next_value); + ecma_free_value (next); + ecma_free_value (iter); + ecma_deref_object (object_p); + return key; + } + + ecma_value_t value = ecma_op_object_get (next_object_p, ecma_new_ecma_string_from_uint32 (1)); + + if (ECMA_IS_VALUE_ERROR (value)) + { + // TODO close the iterator when generator function will be supported + ecma_free_value (next_value); + ecma_free_value (key); + ecma_free_value (next); + ecma_free_value (iter); + ecma_deref_object (object_p); + return value; + } + + result = ecma_op_container_set (set_value, key, value, is_set); + + ecma_free_value (key); + ecma_free_value (value); + } + + ecma_free_value (next_value); + ecma_free_value (next); + + if (ECMA_IS_VALUE_ERROR (result)) + { + // TODO close the iterator when generator function will be supported + ecma_free_value (iter); + ecma_deref_object (object_p); + return result; + } + + ecma_free_value (result); + } + + ecma_free_value (iter); + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ + + return set_value; +} /* ecma_op_container_create */ /** - * Get map object pointer + * Get map/set object pointer * * Note: * If the function returns with NULL, the error object has * already set, and the caller must return with ECMA_VALUE_ERROR * - * @return pointer to the map if this_arg is a valid map object + * @return pointer to the map/set if this_arg is a valid map/set object * NULL otherwise */ static ecma_map_object_t * -ecma_op_map_get_object (ecma_value_t this_arg) /**< this argument */ +ecma_op_container_get_object (ecma_value_t this_arg, /**< this argument */ + bool is_set) /**< true - to perform Set operations + * false - to perform Map operations */ { if (ecma_is_value_object (this_arg)) { ecma_map_object_t *map_object_p = (ecma_map_object_t *) ecma_get_object_from_value (this_arg); if (ecma_get_object_type (&map_object_p->header.object) == ECMA_OBJECT_TYPE_CLASS - && map_object_p->header.u.class_prop.class_id == LIT_MAGIC_STRING_MAP_UL) + && map_object_p->header.u.class_prop.class_id == (is_set ? LIT_MAGIC_STRING_SET_UL : LIT_MAGIC_STRING_MAP_UL)) { return map_object_p; } } - ecma_raise_type_error (ECMA_ERR_MSG ("Expected a Map object.")); + ecma_raise_type_error (ECMA_ERR_MSG (is_set ? "Expected a Set object." : "Expected a Map object.")); return NULL; -} /* ecma_op_map_get_object */ +} /* ecma_op_container_get_object */ /** * Creates a property key for the internal object from the given argument @@ -110,7 +234,7 @@ ecma_op_map_get_object (ecma_value_t this_arg) /**< this argument */ * @return property key */ static ecma_string_t * -ecma_op_map_to_key (ecma_value_t key_arg) /**< key argument */ +ecma_op_container_to_key (ecma_value_t key_arg) /**< key argument */ { if (ecma_is_value_prop_name (key_arg)) { @@ -156,17 +280,19 @@ ecma_op_map_to_key (ecma_value_t key_arg) /**< key argument */ } return ecma_new_map_key_string (key_arg); -} /* ecma_op_map_to_key */ +} /* ecma_op_container_to_key */ /** - * Returns with the size of the map object. + * Returns with the size of the map/set object. * - * @return size of the map object as ecma-value. + * @return size of the map/set object as ecma-value. */ ecma_value_t -ecma_op_map_size (ecma_value_t this_arg) /**< this argument */ +ecma_op_container_size (ecma_value_t this_arg, /**< this argument */ + bool is_set) /**< true - to perform Set operations + * false - to perform Map operations */ { - ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg); + ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, is_set); if (map_object_p == NULL) { @@ -174,7 +300,7 @@ ecma_op_map_size (ecma_value_t this_arg) /**< this argument */ } return ecma_make_uint32_value (map_object_p->size); -} /* ecma_op_map_size */ +} /* ecma_op_container_size */ /** * The generic map prototype object's 'get' routine @@ -183,10 +309,10 @@ ecma_op_map_size (ecma_value_t this_arg) /**< this argument */ * Returned value must be freed with ecma_free_value. */ ecma_value_t -ecma_op_map_get (ecma_value_t this_arg, /**< this argument */ - ecma_value_t key_arg) /**< key argument */ +ecma_op_container_get (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg) /**< key argument */ { - ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg); + ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, false); if (map_object_p == NULL) { @@ -200,7 +326,7 @@ ecma_op_map_get (ecma_value_t this_arg, /**< this argument */ ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); - ecma_string_t *prop_name_p = ecma_op_map_to_key (key_arg); + ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); ecma_property_t *property_p = ecma_find_named_property (internal_obj_p, prop_name_p); @@ -212,19 +338,21 @@ ecma_op_map_get (ecma_value_t this_arg, /**< this argument */ } return ecma_copy_value (ECMA_PROPERTY_VALUE_PTR (property_p)->value); -} /* ecma_op_map_get */ +} /* ecma_op_container_get */ /** - * The generic map prototype object's 'has' routine + * The generic map/set prototype object's 'has' routine * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t -ecma_op_map_has (ecma_value_t this_arg, /**< this argument */ - ecma_value_t key_arg) /**< key argument */ +ecma_op_container_has (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg, /**< key argument */ + bool is_set) /**< true - to perform Set operations + * false - to perform Map operations */ { - ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg); + ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, is_set); if (map_object_p == NULL) { @@ -238,27 +366,29 @@ ecma_op_map_has (ecma_value_t this_arg, /**< this argument */ ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); - ecma_string_t *prop_name_p = ecma_op_map_to_key (key_arg); + ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); ecma_property_t *property_p = ecma_find_named_property (internal_obj_p, prop_name_p); ecma_deref_ecma_string (prop_name_p); return ecma_make_boolean_value (property_p != NULL); -} /* ecma_op_map_has */ +} /* ecma_op_container_has */ /** - * The generic map prototype object's 'set' routine + * The generic map prototype object's 'set' and set prototype object's 'add' routine * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t -ecma_op_map_set (ecma_value_t this_arg, /**< this argument */ - ecma_value_t key_arg, /**< key argument */ - ecma_value_t value_arg) /**< value argument */ +ecma_op_container_set (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg, /**< key argument */ + ecma_value_t value_arg, /**< value argument */ + bool is_set) /**< true - to perform Set operations + * false - to perform Map operations */ { - ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg); + ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, is_set); if (map_object_p == NULL) { @@ -267,7 +397,7 @@ ecma_op_map_set (ecma_value_t this_arg, /**< this argument */ ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); - ecma_string_t *prop_name_p = ecma_op_map_to_key (key_arg); + ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); ecma_property_t *property_p = ecma_find_named_property (internal_obj_p, prop_name_p); @@ -288,13 +418,13 @@ ecma_op_map_set (ecma_value_t this_arg, /**< this argument */ ecma_deref_ecma_string (prop_name_p); ecma_ref_object ((ecma_object_t *) &map_object_p->header); return this_arg; -} /* ecma_op_map_set */ +} /* ecma_op_container_set */ /** - * Low-level function to clear all items from a map + * Low-level function to clear all items from a map/set */ void -ecma_op_map_clear_map (ecma_map_object_t *map_object_p) /**< map object */ +ecma_op_container_clear_map (ecma_map_object_t *map_object_p) /**< map object */ { ecma_object_t *object_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); @@ -336,21 +466,23 @@ ecma_op_map_clear_map (ecma_map_object_t *map_object_p) /**< map object */ } ecma_dealloc_object (object_p); -} /* ecma_op_map_clear_map */ +} /* ecma_op_container_clear_map */ /** - * The generic map prototype object's 'forEach' routine + * The generic map/set prototype object's 'forEach' routine * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t -ecma_op_map_foreach (ecma_value_t this_arg, /**< this argument */ - ecma_value_t predicate, /**< callback function */ - ecma_value_t predicate_this_arg) /**< this argument for - * invoke predicate */ +ecma_op_container_foreach (ecma_value_t this_arg, /**< this argument */ + ecma_value_t predicate, /**< callback function */ + ecma_value_t predicate_this_arg, /**< this argument for + * invoke predicate */ + bool is_set) /**< true - to perform Set operations + * false - to perform Map operations */ { - ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg); + ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, is_set); if (map_object_p == NULL) { @@ -404,7 +536,7 @@ ecma_op_map_foreach (ecma_value_t this_arg, /**< this argument */ } } - ecma_value_t call_args[] = { value, key_arg }; + ecma_value_t call_args[] = { value, is_set ? value : key_arg }; ecma_value_t call_value = ecma_op_function_call (func_object_p, predicate_this_arg, call_args, 2); @@ -422,43 +554,47 @@ ecma_op_map_foreach (ecma_value_t this_arg, /**< this argument */ ecma_free_values_collection (props_p, 0); return ret_value; -} /* ecma_op_map_foreach */ +} /* ecma_op_container_foreach */ /** - * The Map prototype object's 'clear' routine + * The Map/Set prototype object's 'clear' routine * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t -ecma_op_map_clear (ecma_value_t this_arg) /**< this argument */ +ecma_op_container_clear (ecma_value_t this_arg, /**< this argument */ + bool is_set) /**< true - to perform Set operations + * false - to perform Map operations */ { - ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg); + ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, is_set); if (map_object_p == NULL) { return ECMA_VALUE_ERROR; } - ecma_op_map_clear_map (map_object_p); + ecma_op_container_clear_map (map_object_p); - map_object_p->header.u.class_prop.u.value = ecma_op_map_create_internal_object (); + map_object_p->header.u.class_prop.u.value = ecma_op_container_create_internal_object (); map_object_p->size = 0; return ECMA_VALUE_UNDEFINED; -} /* ecma_op_map_clear */ +} /* ecma_op_container_clear */ /** - * The generic map prototype object's 'delete' routine + * The generic map/set prototype object's 'delete' routine * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t -ecma_op_map_delete (ecma_value_t this_arg, /**< this argument */ - ecma_value_t key_arg) /**< key argument */ +ecma_op_container_delete (ecma_value_t this_arg, /**< this argument */ + ecma_value_t key_arg, /**< key argument */ + bool is_set) /**< true - to perform Set operations + * false - to perform Map operations */ { - ecma_map_object_t *map_object_p = ecma_op_map_get_object (this_arg); + ecma_map_object_t *map_object_p = ecma_op_container_get_object (this_arg, is_set); if (map_object_p == NULL) { @@ -467,7 +603,7 @@ ecma_op_map_delete (ecma_value_t this_arg, /**< this argument */ ecma_object_t *internal_obj_p = ecma_get_object_from_value (map_object_p->header.u.class_prop.u.value); - ecma_string_t *prop_name_p = ecma_op_map_to_key (key_arg); + ecma_string_t *prop_name_p = ecma_op_container_to_key (key_arg); ecma_property_t *property_p = ecma_find_named_property (internal_obj_p, prop_name_p); @@ -482,7 +618,7 @@ ecma_op_map_delete (ecma_value_t this_arg, /**< this argument */ map_object_p->size--; return ECMA_VALUE_TRUE; -} /* ecma_op_map_delete */ +} /* ecma_op_container_delete */ /** * @} diff --git a/jerry-core/ecma/operations/ecma-container-object.h b/jerry-core/ecma/operations/ecma-container-object.h new file mode 100644 index 000000000..38e3a8130 --- /dev/null +++ b/jerry-core/ecma/operations/ecma-container-object.h @@ -0,0 +1,49 @@ +/* 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. + */ + +#ifndef ECMA_CONTAINER_OBJECT_H +#define ECMA_CONTAINER_OBJECT_H + +#include "ecma-globals.h" + +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) + +/** \addtogroup ecma ECMA + * @{ + * + * \addtogroup ecmamaphelpers ECMA builtin map/set helper functions + * @{ + */ + +ecma_value_t ecma_op_container_create (const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len, + bool is_set); +ecma_value_t ecma_op_container_size (ecma_value_t this_arg, bool is_set); +ecma_value_t ecma_op_container_get (ecma_value_t this_arg, ecma_value_t key_arg); +ecma_value_t ecma_op_container_foreach (ecma_value_t this_arg, ecma_value_t predicate, ecma_value_t predicate_this_arg, + bool is_set); +ecma_value_t ecma_op_container_has (ecma_value_t this_arg, ecma_value_t key_arg, bool is_set); +ecma_value_t ecma_op_container_set (ecma_value_t this_arg, ecma_value_t key_arg, ecma_value_t value_arg, bool is_set); +void ecma_op_container_clear_map (ecma_map_object_t *map_object_p); +ecma_value_t ecma_op_container_clear (ecma_value_t this_arg, bool is_set); +ecma_value_t ecma_op_container_delete (ecma_value_t this_arg, ecma_value_t key_arg, bool is_set); + +/** + * @} + * @} + */ + +#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ + +#endif /* !ECMA_CONTAINER_OBJECT_H */ diff --git a/jerry-core/ecma/operations/ecma-iterator-object.c b/jerry-core/ecma/operations/ecma-iterator-object.c index b11105367..88f48b83b 100644 --- a/jerry-core/ecma/operations/ecma-iterator-object.c +++ b/jerry-core/ecma/operations/ecma-iterator-object.c @@ -161,6 +161,241 @@ ecma_op_create_iterator_object (ecma_value_t iterated_value, /**< value from cre return ecma_make_object_value (object_p); } /* ecma_op_create_iterator_object */ +/** + * GetIterator operation + * + * See also: ECMA-262 v6, 7.4.1 + * + * Note: + * Returned value must be freed with ecma_free_value. + * + * @return iterator object - if success + * raised error - otherwise + */ +ecma_value_t +ecma_op_get_iterator (ecma_value_t value, /**< value to get iterator from */ + ecma_value_t method) /**< provided method argument */ +{ + /* 1. */ + if (ECMA_IS_VALUE_ERROR (value)) + { + return value; + } + + /* 2. */ + bool has_method = !ecma_is_value_empty (method); + + if (!has_method) + { + /* 2.a */ + method = ecma_op_get_method_by_symbol_id (value, LIT_MAGIC_STRING_ITERATOR); + + /* 2.b */ + if (ECMA_IS_VALUE_ERROR (method)) + { + return method; + } + } + + /* 3. */ + if (!ecma_is_value_object (method) || !ecma_op_is_callable (method)) + { + ecma_free_value (method); + return ecma_raise_type_error (ECMA_ERR_MSG ("object is not iterable")); + } + + ecma_object_t *method_obj_p = ecma_get_object_from_value (method); + ecma_value_t iterator = ecma_op_function_call (method_obj_p, value, NULL, 0); + + if (!has_method) + { + ecma_deref_object (method_obj_p); + } + + /* 4. */ + if (ECMA_IS_VALUE_ERROR (iterator)) + { + return iterator; + } + + /* 5. */ + if (!ecma_is_value_object (iterator)) + { + ecma_free_value (iterator); + return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator is not an object.")); + } + + /* 6. */ + return iterator; +} /* ecma_op_get_iterator */ + +/** + * IteratorNext operation + * + * See also: ECMA-262 v6, 7.4.2 + * + * Note: + * Returned value must be freed with ecma_free_value. + * + * @return iterator result object - if success + * raised error - otherwise + */ +static ecma_value_t +ecma_op_iterator_next (ecma_value_t iterator, /**< iterator value */ + ecma_value_t value) /**< the routines's value argument */ +{ + JERRY_ASSERT (ecma_is_value_object (iterator)); + + /* 1 - 2. */ + ecma_object_t *obj_p = ecma_get_object_from_value (iterator); + + ecma_value_t next = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_NEXT); + + if (ECMA_IS_VALUE_ERROR (next)) + { + return next; + } + + if (!ecma_is_value_object (next) || !ecma_op_is_callable (next)) + { + ecma_free_value (next); + return ecma_raise_type_error (ECMA_ERR_MSG ("Next is not callable.")); + } + + ecma_object_t *next_obj_p = ecma_get_object_from_value (next); + + bool has_value = !ecma_is_value_empty (value); + + ecma_value_t result; + if (has_value) + { + result = ecma_op_function_call (next_obj_p, iterator, &value, 1); + } + else + { + result = ecma_op_function_call (next_obj_p, iterator, NULL, 0); + } + + ecma_free_value (next); + + /* 3. */ + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + /* 4. */ + if (!ecma_is_value_object (result)) + { + ecma_free_value (result); + return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator result is not an object.")); + } + + /* 5. */ + return result; +} /* ecma_op_iterator_next */ + +/** + * IteratorComplete operation + * + * See also: ECMA-262 v6, 7.4.3 + * + * Note: + * Returned value must be freed with ecma_free_value. + * + * @return ECMA_VALUE_{FALSE, TRUE} - if success + * raised error - otherwise + */ +static ecma_value_t +ecma_op_iterator_complete (ecma_value_t iter_result) /**< iterator value */ +{ + /* 1. */ + JERRY_ASSERT (ecma_is_value_object (iter_result)); + + /* 2. */ + ecma_object_t *obj_p = ecma_get_object_from_value (iter_result); + + ecma_value_t done = ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_DONE); + + if (ECMA_IS_VALUE_ERROR (done)) + { + return done; + } + + bool is_done = ecma_op_to_boolean (done); + + ecma_free_value (done); + + return ecma_make_boolean_value (is_done); +} /* ecma_op_iterator_complete */ + +/** + * IteratorValue operation + * + * See also: ECMA-262 v6, 7.4.4 + * + * Note: + * Returned value must be freed with ecma_free_value. + * + * @return value of the iterator result object + */ +ecma_value_t +ecma_op_iterator_value (ecma_value_t iter_result) /**< iterator value */ +{ + /* 1. */ + JERRY_ASSERT (ecma_is_value_object (iter_result)); + + /* 2. */ + ecma_object_t *obj_p = ecma_get_object_from_value (iter_result); + return ecma_op_object_get_by_magic_id (obj_p, LIT_MAGIC_STRING_VALUE); +} /* ecma_op_iterator_value */ + +/** + * IteratorStep operation + * + * See also: ECMA-262 v6, 7.4.5 + * + * Note: + * Returned value must be freed with ecma_free_value. + * + * @return iterator object or ECMA_VALUE_FALSE - if success + * raised error - otherwise + */ +ecma_value_t +ecma_op_iterator_step (ecma_value_t iterator) /**< iterator value */ +{ + /* 1. */ + ecma_value_t result = ecma_op_iterator_next (iterator, ECMA_VALUE_EMPTY); + + /* 2. */ + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + /* 3. */ + ecma_value_t done = ecma_op_iterator_complete (result); + + /* 4. */ + if (ECMA_IS_VALUE_ERROR (done)) + { + ecma_free_value (result); + return done; + } + + ecma_free_value (done); + + /* 5. */ + if (ecma_is_value_true (done)) + { + ecma_free_value (result); + return ECMA_VALUE_FALSE; + } + + /* 6. */ + return result; +} /* ecma_op_iterator_step */ + #endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ /** * @} diff --git a/jerry-core/ecma/operations/ecma-iterator-object.h b/jerry-core/ecma/operations/ecma-iterator-object.h index 8afb022d3..d4b81e614 100644 --- a/jerry-core/ecma/operations/ecma-iterator-object.h +++ b/jerry-core/ecma/operations/ecma-iterator-object.h @@ -43,6 +43,15 @@ ecma_create_iter_result_object (ecma_value_t value, ecma_value_t done); ecma_value_t ecma_create_array_from_iter_element (ecma_value_t value, ecma_value_t index_value); +ecma_value_t +ecma_op_get_iterator (ecma_value_t value, ecma_value_t method); + +ecma_value_t +ecma_op_iterator_value (ecma_value_t iter_result); + +ecma_value_t +ecma_op_iterator_step (ecma_value_t iterator); + #endif /* ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) */ /** diff --git a/jerry-core/ecma/operations/ecma-map-object.h b/jerry-core/ecma/operations/ecma-map-object.h deleted file mode 100644 index 29ad9f366..000000000 --- a/jerry-core/ecma/operations/ecma-map-object.h +++ /dev/null @@ -1,47 +0,0 @@ -/* 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. - */ - -#ifndef ECMA_MAP_OBJECT_H -#define ECMA_MAP_OBJECT_H - -#include "ecma-globals.h" - -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) - -/** \addtogroup ecma ECMA - * @{ - * - * \addtogroup ecmamaphelpers ECMA builtin map helper functions - * @{ - */ - -ecma_value_t ecma_op_map_create (const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len); -ecma_value_t ecma_op_map_size (ecma_value_t this_arg); -ecma_value_t ecma_op_map_get (ecma_value_t this_arg, ecma_value_t key_arg); -ecma_value_t ecma_op_map_foreach (ecma_value_t this_arg, ecma_value_t predicate, ecma_value_t predicate_this_arg); -ecma_value_t ecma_op_map_has (ecma_value_t this_arg, ecma_value_t key_arg); -ecma_value_t ecma_op_map_set (ecma_value_t this_arg, ecma_value_t key_arg, ecma_value_t value_arg); -void ecma_op_map_clear_map (ecma_map_object_t *map_object_p); -ecma_value_t ecma_op_map_clear (ecma_value_t this_arg); -ecma_value_t ecma_op_map_delete (ecma_value_t this_arg, ecma_value_t key_arg); - -/** - * @} - * @} - */ - -#endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ - -#endif /* !ECMA_MAP_OBJECT_H */ diff --git a/jerry-core/ecma/operations/ecma-objects.c b/jerry-core/ecma/operations/ecma-objects.c index 0d63b0383..59010894f 100644 --- a/jerry-core/ecma/operations/ecma-objects.c +++ b/jerry-core/ecma/operations/ecma-objects.c @@ -756,6 +756,56 @@ ecma_op_object_get_by_symbol_id (ecma_object_t *object_p, /**< the object */ return ret_value; } /* ecma_op_object_get_by_symbol_id */ + +/** + * GetMethod operation the property is a well-known symbol + * + * See also: ECMA-262 v6, 7.3.9 + * + * Note: + * Returned value must be freed with ecma_free_value. + * + * @return iterator fucntion object - if success + * raised error - otherwise + */ +ecma_value_t +ecma_op_get_method_by_symbol_id (ecma_value_t value, /**< ecma value */ + lit_magic_string_id_t property_id) /**< property symbol id */ +{ + /* 2. */ + ecma_value_t obj_value = ecma_op_to_object (value); + + if (ECMA_IS_VALUE_ERROR (obj_value)) + { + return obj_value; + } + + ecma_object_t *obj_p = ecma_get_object_from_value (obj_value); + ecma_value_t func = ecma_op_object_get_by_symbol_id (obj_p, property_id); + ecma_deref_object (obj_p); + + /* 3. */ + if (ECMA_IS_VALUE_ERROR (func)) + { + return func; + } + + /* 4. */ + if (ecma_is_value_undefined (func) || ecma_is_value_null (func)) + { + return ECMA_VALUE_UNDEFINED; + } + + /* 5. */ + if (!ecma_op_is_callable (func)) + { + ecma_free_value (func); + return ecma_raise_type_error (ECMA_ERR_MSG ("Iterator is not callable.")); + } + + /* 6. */ + return func; +} /* ecma_op_get_method_by_symbol_id */ #endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ /** @@ -1838,6 +1888,9 @@ ecma_object_check_class_name_is_object (ecma_object_t *obj_p) /**< object */ #if ENABLED (JERRY_ES2015_BUILTIN_MAP) || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_MAP_PROTOTYPE) #endif /* ENABLED (JERRY_ES2015_BUILTIN_MAP) */ +#if ENABLED (JERRY_ES2015_BUILTIN_SET) + || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_SET_PROTOTYPE) +#endif /* ENABLED (JERRY_ES2015_BUILTIN_SET) */ #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) || ecma_builtin_is (obj_p, ECMA_BUILTIN_ID_SYMBOL_PROTOTYPE) #endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ diff --git a/jerry-core/ecma/operations/ecma-objects.h b/jerry-core/ecma/operations/ecma-objects.h index 01f0fb36b..d0c9ef72f 100644 --- a/jerry-core/ecma/operations/ecma-objects.h +++ b/jerry-core/ecma/operations/ecma-objects.h @@ -37,6 +37,7 @@ ecma_value_t ecma_op_object_get (ecma_object_t *object_p, ecma_string_t *propert ecma_value_t ecma_op_object_get_by_magic_id (ecma_object_t *object_p, lit_magic_string_id_t property_id); #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) ecma_value_t ecma_op_object_get_by_symbol_id (ecma_object_t *object_p, lit_magic_string_id_t property_id); +ecma_value_t ecma_op_get_method_by_symbol_id (ecma_value_t value, lit_magic_string_id_t property_id); #endif /* ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) */ 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); diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index 842c4ab83..2c56da9c7 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -48,12 +48,19 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_LN2_U, "LN2") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_MAP_UL, "Map") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_NAN, "NaN") +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) \ +|| ENABLED (JERRY_ES2015_BUILTIN_SET) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SET_UL, "Set") +#endif #if ENABLED (JERRY_BUILTIN_DATE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_UTC_U, "UTC") #endif #if ENABLED (JERRY_BUILTIN_MATH) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ABS, "abs") #endif +#if ENABLED (JERRY_ES2015_BUILTIN_SET) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ADD, "add") +#endif #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ALL, "all") #endif @@ -65,7 +72,8 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_EXP, "exp") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FOR, "for") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET, "get") -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) \ +|| ENABLED (JERRY_ES2015_BUILTIN_SET) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_HAS, "has") #endif #if ENABLED (JERRY_BUILTIN_MATH) @@ -149,7 +157,8 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PUSH, "push") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RACE, "race") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SEAL, "seal") -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) \ +|| ENABLED (JERRY_ES2015_BUILTIN_SET) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SIZE, "size") #endif #if ENABLED (JERRY_BUILTIN_ARRAY) \ @@ -183,7 +192,8 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ATAN2, "atan2") #if ENABLED (JERRY_ES2015_BUILTIN_PROMISE) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CATCH, "catch") #endif -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) \ +|| ENABLED (JERRY_ES2015_BUILTIN_SET) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CLEAR, "clear") #endif #if ENABLED (JERRY_BUILTIN_ARRAY) \ @@ -253,7 +263,8 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CHAR_AT_UL, "charAt") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CONCAT, "concat") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_CREATE, "create") -#if ENABLED (JERRY_ES2015_BUILTIN_MAP) +#if ENABLED (JERRY_ES2015_BUILTIN_MAP) \ +|| ENABLED (JERRY_ES2015_BUILTIN_SET) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DELETE, "delete") #endif #if ENABLED (JERRY_BUILTIN_ANNEXB) @@ -336,6 +347,7 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ENTRIES, "entries") #endif #if ENABLED (JERRY_BUILTIN_ARRAY) \ || ENABLED (JERRY_ES2015_BUILTIN_MAP) \ +|| ENABLED (JERRY_ES2015_BUILTIN_SET) \ || ENABLED (JERRY_ES2015_BUILTIN_TYPEDARRAY) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_FOR_EACH_UL, "forEach") #endif @@ -417,7 +429,8 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_GET_UINT8_UL, "getUint8") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS_FINITE, "isFinite") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS_FROZEN_UL, "isFrozen") LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_IS_SEALED_UL, "isSealed") -#if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) +#if ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) \ +|| ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ITERATOR, "iterator") #endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_PARSE_INT, "parseInt") diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index 60c82bc3b..596296646 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -37,8 +37,10 @@ LIT_MAGIC_STRING_OF = "of" LIT_MAGIC_STRING_LN2_U = "LN2" LIT_MAGIC_STRING_MAP_UL = "Map" LIT_MAGIC_STRING_NAN = "NaN" +LIT_MAGIC_STRING_SET_UL = "Set" LIT_MAGIC_STRING_UTC_U = "UTC" LIT_MAGIC_STRING_ABS = "abs" +LIT_MAGIC_STRING_ADD = "add" LIT_MAGIC_STRING_ALL = "all" LIT_MAGIC_STRING_COS = "cos" LIT_MAGIC_STRING_EXP = "exp" diff --git a/jerry-core/profiles/README.md b/jerry-core/profiles/README.md index db7cfd191..03e3d1b54 100644 --- a/jerry-core/profiles/README.md +++ b/jerry-core/profiles/README.md @@ -35,6 +35,7 @@ JERRY_ES2015_BUILTIN_DATAVIEW=0 JERRY_ES2015_BUILTIN_ITERATOR=0 JERRY_ES2015_BUILTIN_MAP=0 JERRY_ES2015_BUILTIN_PROMISE=0 +JERRY_ES2015_BUILTIN_SET=0 JERRY_ES2015_BUILTIN_SYMBOL=0 JERRY_ES2015_BUILTIN_TYPEDARRAY=0 JERRY_ES2015_CLASS=0 @@ -116,6 +117,8 @@ defined to `1`. Enables or disables the [Iterator](https://www.ecma-international.org/ecma-262/6.0/#sec-iterator-interface) built-in. * `JERRY_ES2015_BUILTIN_MAP`: Enables or disables the [Map](http://www.ecma-international.org/ecma-262/6.0/#sec-keyed-collection) built-ins. +* `JERRY_ES2015_BUILTIN_SET`: + Enables or disables the [SET](https://www.ecma-international.org/ecma-262/6.0/#sec-set-objects) built-in. * `JERRY_ES2015_BUILTIN_SYMBOL`: Enables or disables the [Symbol](https://www.ecma-international.org/ecma-262/6.0/#sec-symbol-objects) built-in. * `JERRY_ES2015_BUILTIN_PROMISE`: @@ -142,6 +145,7 @@ defined to `1`. * `JERRY_ES2015_BUILTIN_DATAVIEW` * `JERRY_ES2015_BUILTIN_ITERATOR` * `JERRY_ES2015_BUILTIN_MAP` + * `JERRY_ES2015_BUILTIN_SET` * `JERRY_ES2015_BUILTIN_PROMISE` * `JERRY_ES2015_BUILTIN_SYMBOL` * `JERRY_ES2015_BUILTIN_TYPEDARRAY` diff --git a/tests/jerry/es2015/map.js b/tests/jerry/es2015/map.js index 955e1ce1d..55b711e45 100644 --- a/tests/jerry/es2015/map.js +++ b/tests/jerry/es2015/map.js @@ -117,3 +117,9 @@ assert(mapNameDesc.enumerable === false); assert(mapNameDesc.configurable === true); assert(Map.prototype.name === undefined); + +m = new Map([{0: "foo", 1: 3}, {0 : "bar", 1 : 2}]); + +assert (m.size === 2); +assert (m.get("foo") === 3); +assert (m.get("bar") === 2); diff --git a/tests/jerry/es2015/set.js b/tests/jerry/es2015/set.js new file mode 100644 index 000000000..4c898401d --- /dev/null +++ b/tests/jerry/es2015/set.js @@ -0,0 +1,89 @@ +/* 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. + */ + +var set = new Set(); +var int = 1; +assert (set.size === 0); +assert (set.add (int) === set); +assert (set.has (int)); +assert (set.size === 1); + +var str = "foobar" +assert (set.add (str) === set); +assert (set.has (str)); +assert (set.size === 2); + +var number = 5.78; +assert (set.add (number) === set); +assert (set.has (number)); +assert (set.size === 3); + +var object = { a : 2, b : 4}; +assert (set.add (object) === set); +assert (set.has (object)); +assert (set.size === 4); + +var func = function () {}; +assert (set.add (func) === set); +assert (set.has (func)); +assert (set.size === 5); + +var symbol = Symbol ("foo"); +assert (set.add (symbol) === set); +assert (set.has (symbol)); +assert (set.size === 6); + +assert (!set.has(5)); +assert (!set.has("foo")); +assert (!set.has({ a : 2, b : 4})); +assert (!set.has(function () {})); +assert (!set.has(Symbol ("foo"))); + +var elements = [int, str, number, object, func, symbol]; + +var i = 0; +set.forEach (function (value, key) { + assert (key === elements[i]); + assert (value === elements[i]); + i++; +}); + +assert (set.delete (int)); +assert (set.size === 5); +assert (set.delete (str)); +assert (set.size === 4); +assert (set.delete (number)); +assert (set.size === 3); +assert (set.delete (object)); +assert (set.size === 2); +assert (set.delete (func)); +assert (set.size === 1); +assert (set.delete (symbol)); +assert (set.size === 0); + +set = new Set([1, 2, 3, 4]); +assert (set.has(1)); +assert (set.has(2)); +assert (set.has(3)); +assert (set.has(4)); + +assert (set.size === 4); +assert (set.add (2) === set); +assert (set.size === 4); +assert (set.delete (2)); +assert (set.size === 3); + +set.clear(); +assert(set.size === 0);