diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c
index e2a26ce4d..398104465 100644
--- a/jerry-core/ecma/base/ecma-gc.c
+++ b/jerry-core/ecma/base/ecma-gc.c
@@ -192,7 +192,8 @@ ecma_gc_mark_properties (ecma_property_pair_t *property_pair_p) /**< property pa
case ECMA_PROPERTY_TYPE_INTERNAL:
{
JERRY_ASSERT (ECMA_PROPERTY_GET_NAME_TYPE (property) == ECMA_DIRECT_STRING_MAGIC
- && property_pair_p->names_cp[index] >= LIT_FIRST_INTERNAL_MAGIC_STRING);
+ && property_pair_p->names_cp[index] >= LIT_INTERNAL_MAGIC_STRING_FIRST_DATA
+ && property_pair_p->names_cp[index] < LIT_MAGIC_STRING__COUNT);
break;
}
default:
@@ -1054,33 +1055,51 @@ ecma_gc_free_properties (ecma_object_t *object_p) /**< object */
ecma_property_t *property_p = (ecma_property_t *) (prop_iter_p->types + i);
jmem_cpointer_t name_cp = prop_pair_p->names_cp[i];
- if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC)
+ if (ECMA_PROPERTY_GET_TYPE (*property_p) == ECMA_PROPERTY_TYPE_INTERNAL)
{
+ JERRY_ASSERT (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC);
+
/* Call the native's free callback. */
- if (JERRY_UNLIKELY (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER))
+ switch (name_cp)
{
- ecma_gc_free_native_pointer (property_p);
- }
#if ENABLED (JERRY_BUILTIN_WEAKMAP) || ENABLED (JERRY_BUILTIN_WEAKSET)
- else if (JERRY_UNLIKELY (name_cp == LIT_INTERNAL_MAGIC_STRING_WEAK_REFS))
- {
- ecma_collection_t *refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
- ECMA_PROPERTY_VALUE_PTR (property_p)->value);
- for (uint32_t j = 0; j < refs_p->item_count; j++)
+ case LIT_INTERNAL_MAGIC_STRING_WEAK_REFS:
{
- const ecma_value_t value = refs_p->buffer_p[j];
- if (!ecma_is_value_empty (value))
+ ecma_collection_t *refs_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t,
+ prop_pair_p->values[i].value);
+ for (uint32_t j = 0; j < refs_p->item_count; j++)
{
- ecma_object_t *container_p = ecma_get_object_from_value (value);
+ const ecma_value_t value = refs_p->buffer_p[j];
+ if (!ecma_is_value_empty (value))
+ {
+ ecma_object_t *container_p = ecma_get_object_from_value (value);
- ecma_op_container_remove_weak_entry (container_p,
- ecma_make_object_value (object_p));
+ ecma_op_container_remove_weak_entry (container_p,
+ ecma_make_object_value (object_p));
+ }
}
- }
- ecma_collection_destroy (refs_p);
- }
+ ecma_collection_destroy (refs_p);
+ break;
+ }
#endif /* ENABLED (JERRY_BUILTIN_WEAKMAP) || ENABLED (JERRY_BUILTIN_WEAKSET) */
+#if ENABLED (JERRY_ESNEXT)
+ case LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED:
+ {
+ ecma_value_t *compact_collection_p;
+ compact_collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_value_t,
+ prop_pair_p->values[i].value);
+ ecma_compact_collection_free (compact_collection_p);
+ break;
+ }
+#endif /* ENABLED (JERRY_ESNEXT) */
+ default:
+ {
+ JERRY_ASSERT (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER);
+ ecma_gc_free_native_pointer (property_p);
+ break;
+ }
+ }
}
if (prop_iter_p->types[i] != ECMA_PROPERTY_TYPE_DELETED)
diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h
index 92ad89d44..af4591697 100644
--- a/jerry-core/ecma/base/ecma-globals.h
+++ b/jerry-core/ecma/base/ecma-globals.h
@@ -113,17 +113,21 @@ typedef enum
ECMA_PARSE_DIRECT_EVAL = (1u << 3), /**< eval is called directly (ECMA-262 v5, 15.1.2.1.1) */
ECMA_PARSE_CLASS_CONSTRUCTOR = (1u << 4), /**< a class constructor is being parsed */
- /* These four status flags must be in this order. The first three are also parser status flags.
+ /* These five status flags must be in this order. The first four are also parser status flags.
* See PARSER_SAVE_STATUS_FLAGS / PARSER_RESTORE_STATUS_FLAGS. */
ECMA_PARSE_ALLOW_SUPER = (1u << 5), /**< allow super property access */
ECMA_PARSE_ALLOW_SUPER_CALL = (1u << 6), /**< allow super constructor call */
- ECMA_PARSE_ALLOW_NEW_TARGET = (1u << 7), /**< allow new.target access */
- ECMA_PARSE_FUNCTION_CONTEXT = (1u << 8), /**< function context is present (ECMA_PARSE_DIRECT_EVAL must be set) */
+ ECMA_PARSE_INSIDE_CLASS_FIELD = (1u << 7), /**< a class field is being parsed */
+ ECMA_PARSE_ALLOW_NEW_TARGET = (1u << 8), /**< allow new.target access */
+ ECMA_PARSE_FUNCTION_CONTEXT = (1u << 9), /**< function context is present (ECMA_PARSE_DIRECT_EVAL must be set) */
- ECMA_PARSE_GENERATOR_FUNCTION = (1u << 9), /**< generator function is parsed */
- ECMA_PARSE_ASYNC_FUNCTION = (1u << 10), /**< async function is parsed */
+ ECMA_PARSE_GENERATOR_FUNCTION = (1u << 10), /**< generator function is parsed */
+ ECMA_PARSE_ASYNC_FUNCTION = (1u << 11), /**< async function is parsed */
/* These flags are internally used by the parser. */
+#if ENABLED (JERRY_ESNEXT)
+ ECMA_PARSE_INTERNAL_PRE_SCANNING = (1u << 12),
+#endif /* ENABLED (JERRY_ESNEXT) */
#ifndef JERRY_NDEBUG
/**
* This flag represents an error in for in/of statements, which cannot be set
@@ -1439,6 +1443,17 @@ typedef struct
*/
#define ECMA_COLLECTION_INITIAL_SIZE ECMA_COLLECTION_ALLOCATED_SIZE (ECMA_COLLECTION_INITIAL_CAPACITY)
+/**
+ * Size shift of a compact collection
+ */
+#define ECMA_COMPACT_COLLECTION_SIZE_SHIFT 3
+
+/**
+ * Get the size of the compact collection
+ */
+#define ECMA_COMPACT_COLLECTION_GET_SIZE(compact_collection_p) \
+ ((compact_collection_p)[0] >> ECMA_COMPACT_COLLECTION_SIZE_SHIFT)
+
/**
* Direct string types (2 bit).
*/
diff --git a/jerry-core/ecma/base/ecma-helpers-collection.c b/jerry-core/ecma/base/ecma-helpers-collection.c
index 96ad4dadf..34a16a370 100644
--- a/jerry-core/ecma/base/ecma-helpers-collection.c
+++ b/jerry-core/ecma/base/ecma-helpers-collection.c
@@ -248,6 +248,134 @@ ecma_collection_has_string_value (ecma_collection_t *collection_p, /**< collecti
return false;
} /* ecma_collection_has_string_value */
+/**
+ * Initial capacity of an ecma-collection
+ */
+#define ECMA_COMPACT_COLLECTION_GROWTH 8
+
+/**
+ * Set the size of the compact collection
+ */
+#define ECMA_COMPACT_COLLECTION_SET_SIZE(compact_collection_p, item_count, unused_items) \
+ ((compact_collection_p)[0] = (((item_count) << ECMA_COMPACT_COLLECTION_SIZE_SHIFT) | (unused_items)))
+
+/**
+ * Set the size of the compact collection
+ */
+#define ECMA_COMPACT_COLLECTION_GET_UNUSED_ITEM_COUNT(compact_collection_p) \
+ ((compact_collection_p)[0] & ((1 << ECMA_COMPACT_COLLECTION_SIZE_SHIFT) - 1))
+
+/**
+ * Allocate a compact collection of ecma values
+ *
+ * @return pointer to the compact collection
+ */
+ecma_value_t *
+ecma_new_compact_collection (void)
+{
+ size_t size = (ECMA_COMPACT_COLLECTION_GROWTH / 2) * sizeof (ecma_value_t);
+ ecma_value_t *compact_collection_p = (ecma_value_t *) jmem_heap_alloc_block (size);
+
+ ECMA_COMPACT_COLLECTION_SET_SIZE (compact_collection_p,
+ ECMA_COMPACT_COLLECTION_GROWTH / 2,
+ (ECMA_COMPACT_COLLECTION_GROWTH / 2) - 1);
+ return compact_collection_p;
+} /* ecma_new_compact_collection */
+
+/**
+ * Append a value to the compact collection
+ *
+ * @return updated pointer to the compact collection
+ */
+ecma_value_t *
+ecma_compact_collection_push_back (ecma_value_t *compact_collection_p, /**< compact collection */
+ ecma_value_t value) /**< ecma value to append */
+{
+ ecma_value_t size = ECMA_COMPACT_COLLECTION_GET_SIZE (compact_collection_p);
+ ecma_value_t unused_items = ECMA_COMPACT_COLLECTION_GET_UNUSED_ITEM_COUNT (compact_collection_p);
+
+ if (unused_items > 0)
+ {
+ compact_collection_p[size - unused_items] = value;
+ (*compact_collection_p)--;
+ return compact_collection_p;
+ }
+
+ if (size == ECMA_COMPACT_COLLECTION_GROWTH / 2)
+ {
+ size_t old_size = (ECMA_COMPACT_COLLECTION_GROWTH / 2) * sizeof (ecma_value_t);
+ size_t new_size = ECMA_COMPACT_COLLECTION_GROWTH * sizeof (ecma_value_t);
+ compact_collection_p = jmem_heap_realloc_block (compact_collection_p, old_size, new_size);
+
+ compact_collection_p[ECMA_COMPACT_COLLECTION_GROWTH / 2] = value;
+
+ ECMA_COMPACT_COLLECTION_SET_SIZE (compact_collection_p,
+ ECMA_COMPACT_COLLECTION_GROWTH,
+ (ECMA_COMPACT_COLLECTION_GROWTH / 2) - 1);
+ return compact_collection_p;
+ }
+
+ size_t old_size = size * sizeof (ecma_value_t);
+ size_t new_size = old_size + (ECMA_COMPACT_COLLECTION_GROWTH * sizeof (ecma_value_t));
+
+ compact_collection_p = jmem_heap_realloc_block (compact_collection_p, old_size, new_size);
+ compact_collection_p[size] = value;
+
+ ECMA_COMPACT_COLLECTION_SET_SIZE (compact_collection_p,
+ size + ECMA_COMPACT_COLLECTION_GROWTH,
+ ECMA_COMPACT_COLLECTION_GROWTH - 1);
+ return compact_collection_p;
+} /* ecma_compact_collection_push_back */
+
+/**
+ * Discard the unused elements of a compact collection
+ *
+ * Note:
+ * further items should not be added after this call
+ *
+ * @return updated pointer to the compact collection
+ */
+ecma_value_t *
+ecma_compact_collection_shrink (ecma_value_t *compact_collection_p) /**< compact collection */
+{
+ ecma_value_t unused_items = ECMA_COMPACT_COLLECTION_GET_UNUSED_ITEM_COUNT (compact_collection_p);
+
+ if (unused_items == 0)
+ {
+ return compact_collection_p;
+ }
+
+ ecma_value_t size = ECMA_COMPACT_COLLECTION_GET_SIZE (compact_collection_p);
+
+ size_t old_size = size * sizeof (ecma_value_t);
+ size_t new_size = (size - unused_items) * sizeof (ecma_value_t);
+
+ compact_collection_p = jmem_heap_realloc_block (compact_collection_p, old_size, new_size);
+
+ ECMA_COMPACT_COLLECTION_SET_SIZE (compact_collection_p, size - unused_items, 0);
+ return compact_collection_p;
+} /* ecma_compact_collection_shrink */
+
+/**
+ * Free a compact collection
+ */
+void
+ecma_compact_collection_free (ecma_value_t *compact_collection_p) /**< compact collection */
+{
+ ecma_value_t size = ECMA_COMPACT_COLLECTION_GET_SIZE (compact_collection_p);
+ ecma_value_t unused_items = ECMA_COMPACT_COLLECTION_GET_UNUSED_ITEM_COUNT (compact_collection_p);
+
+ ecma_value_t *end_p = compact_collection_p + size - unused_items;
+ ecma_value_t *current_p = compact_collection_p + 1;
+
+ while (current_p < end_p)
+ {
+ ecma_free_value (*current_p++);
+ }
+
+ jmem_heap_free_block (compact_collection_p, size * sizeof (ecma_value_t));
+} /* ecma_compact_collection_free */
+
/**
* @}
* @}
diff --git a/jerry-core/ecma/base/ecma-helpers.c b/jerry-core/ecma/base/ecma-helpers.c
index cce126483..3f30ab366 100644
--- a/jerry-core/ecma/base/ecma-helpers.c
+++ b/jerry-core/ecma/base/ecma-helpers.c
@@ -784,7 +784,8 @@ ecma_free_property (ecma_object_t *object_p, /**< object the property belongs to
/* Must be a native pointer. */
JERRY_ASSERT (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC
- && name_cp >= LIT_FIRST_INTERNAL_MAGIC_STRING);
+ && name_cp >= LIT_INTERNAL_MAGIC_STRING_FIRST_DATA
+ && name_cp < LIT_MAGIC_STRING__COUNT);
break;
}
}
diff --git a/jerry-core/ecma/base/ecma-helpers.h b/jerry-core/ecma/base/ecma-helpers.h
index cdb350e42..03a83ebd4 100644
--- a/jerry-core/ecma/base/ecma-helpers.h
+++ b/jerry-core/ecma/base/ecma-helpers.h
@@ -464,6 +464,11 @@ void ecma_collection_free_objects (ecma_collection_t *collection_p);
bool ecma_collection_check_duplicated_entries (ecma_collection_t *collection_p);
bool ecma_collection_has_string_value (ecma_collection_t *collection_p, ecma_string_t *string_p);
+ecma_value_t *ecma_new_compact_collection (void);
+ecma_value_t *ecma_compact_collection_push_back (ecma_value_t *compact_collection_p, ecma_value_t value);
+ecma_value_t *ecma_compact_collection_shrink (ecma_value_t *compact_collection_p);
+void ecma_compact_collection_free (ecma_value_t *compact_collection_p);
+
/* ecma-helpers.c */
ecma_object_t *ecma_create_object (ecma_object_t *prototype_object_p, size_t ext_object_size, ecma_object_type_t type);
ecma_object_t *ecma_create_decl_lex_env (ecma_object_t *outer_lexical_environment_p);
diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h
index 9d50248d9..ddebbd73d 100644
--- a/jerry-core/jcontext/jcontext.h
+++ b/jerry-core/jcontext/jcontext.h
@@ -137,6 +137,9 @@ struct jerry_context_t
#endif /* ENABLED (JERRY_CPOINTER_32_BIT) */
const lit_utf8_byte_t * const *lit_magic_string_ex_array; /**< array of external magic strings */
const lit_utf8_size_t *lit_magic_string_ex_sizes; /**< external magic string lengths */
+#if ENABLED (JERRY_ESNEXT)
+ ecma_value_t *computed_class_fields_p; /**< names of the computed class fields */
+#endif /* ENABLED (JERRY_ESNEXT) */
jmem_cpointer_t string_list_first_cp; /**< first item of the literal string list */
#if ENABLED (JERRY_ESNEXT)
jmem_cpointer_t symbol_list_first_cp; /**< first item of the global symbol list */
diff --git a/jerry-core/lit/lit-magic-strings.h b/jerry-core/lit/lit-magic-strings.h
index 8baab1cce..db1420bb0 100644
--- a/jerry-core/lit/lit-magic-strings.h
+++ b/jerry-core/lit/lit-magic-strings.h
@@ -61,16 +61,16 @@ typedef enum
LIT_GLOBAL_SYMBOL_TO_STRING_TAG, /**< @@toStringTag well known symbol */
LIT_GLOBAL_SYMBOL_UNSCOPABLES, /**< @@unscopables well known symbol */
LIT_GLOBAL_SYMBOL__LAST = LIT_GLOBAL_SYMBOL_UNSCOPABLES, /**< last global symbol */
- LIT_GC_MARK_REQUIRED_MAGIC_STRING__COUNT, /**< number of internal magic strings which will be used as
- * property names, and their values need to be marked during gc. */
- LIT_INTERNAL_MAGIC_STRING_DELETED = LIT_GC_MARK_REQUIRED_MAGIC_STRING__COUNT, /**< special value for
- * deleted properties */
+
+ LIT_INTERNAL_MAGIC_STRING_DELETED, /**< special value for deleted properties */
+ LIT_INTERNAL_MAGIC_STRING_INTERNAL_OBJECT, /**< Internal object ID for internal properties */
+ LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_INIT, /**< function which initializes properties */
LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< native pointer info associated with an object */
- LIT_FIRST_INTERNAL_MAGIC_STRING = LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< first index of internal
- * magic strings */
+ LIT_INTERNAL_MAGIC_STRING_FIRST_DATA = LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< first index of special
+ * data properties */
LIT_INTERNAL_MAGIC_STRING_WEAK_REFS, /**< Weak references to the current object */
- LIT_INTERNAL_MAGIC_STRING_INTERNAL_OBJECT, /**< Internal object ID for internal properties */
+ LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED, /**< computed class field name list */
LIT_MAGIC_STRING__COUNT /**< number of magic strings */
} lit_magic_string_id_t;
diff --git a/jerry-core/parser/js/byte-code.c b/jerry-core/parser/js/byte-code.c
index 38b5bc205..36158a88f 100644
--- a/jerry-core/parser/js/byte-code.c
+++ b/jerry-core/parser/js/byte-code.c
@@ -27,7 +27,7 @@ JERRY_STATIC_ASSERT ((sizeof (cbc_uint16_arguments_t) % sizeof (jmem_cpointer_t)
*/
JERRY_STATIC_ASSERT (CBC_END == 238,
number_of_cbc_opcodes_changed);
-JERRY_STATIC_ASSERT (CBC_EXT_END == 135,
+JERRY_STATIC_ASSERT (CBC_EXT_END == 140,
number_of_cbc_ext_opcodes_changed);
#if ENABLED (JERRY_PARSER)
diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h
index ce6ff9fba..9f76efe48 100644
--- a/jerry-core/parser/js/byte-code.h
+++ b/jerry-core/parser/js/byte-code.h
@@ -634,6 +634,8 @@
VM_OC_SET_GETTER | VM_OC_NON_STATIC_FLAG | VM_OC_GET_STACK_STACK) \
CBC_OPCODE (CBC_EXT_SET_COMPUTED_SETTER, CBC_NO_FLAG, -2, \
VM_OC_SET_SETTER | VM_OC_NON_STATIC_FLAG | VM_OC_GET_STACK_STACK) \
+ CBC_OPCODE (CBC_EXT_SET_STATIC_PROPERTY, CBC_HAS_LITERAL_ARG, -1, \
+ VM_OC_SET_PROPERTY | VM_OC_GET_STACK_LITERAL) \
CBC_OPCODE (CBC_EXT_SET_STATIC_PROPERTY_LITERAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_SET_PROPERTY | VM_OC_GET_LITERAL_LITERAL) \
CBC_OPCODE (CBC_EXT_SET_STATIC_COMPUTED_PROPERTY, CBC_NO_FLAG, -2, \
@@ -648,6 +650,8 @@
VM_OC_SET_SETTER | VM_OC_GET_STACK_STACK) \
CBC_OPCODE (CBC_EXT_SET__PROTO__, CBC_NO_FLAG, -1, \
VM_OC_SET__PROTO__ | VM_OC_GET_STACK) \
+ CBC_OPCODE (CBC_EXT_ADD_COMPUTED_FIELD, CBC_NO_FLAG, -1, \
+ VM_OC_ADD_COMPUTED_FIELD | VM_OC_GET_STACK) \
\
/* Class related opcodes. */ \
CBC_OPCODE (CBC_EXT_PUSH_NAMED_CLASS_ENV, CBC_HAS_LITERAL_ARG, 1, \
@@ -664,6 +668,12 @@
VM_OC_FINALIZE_CLASS | VM_OC_GET_LITERAL) \
CBC_OPCODE (CBC_EXT_FINALIZE_ANONYMOUS_CLASS, CBC_NO_FLAG, -2, \
VM_OC_FINALIZE_CLASS) \
+ CBC_OPCODE (CBC_EXT_SET_CLASS_FIELD_INIT, CBC_HAS_LITERAL_ARG, 0, \
+ VM_OC_SET_CLASS_FIELD_INIT | VM_OC_GET_LITERAL) \
+ CBC_OPCODE (CBC_EXT_RUN_CLASS_FIELD_INIT, CBC_NO_FLAG, 0, \
+ VM_OC_RUN_CLASS_FIELD_INIT) \
+ CBC_OPCODE (CBC_EXT_SET_NEXT_COMPUTED_FIELD, CBC_NO_FLAG, -1, \
+ VM_OC_SET_NEXT_COMPUTED_FIELD | VM_OC_PUT_REFERENCE) \
CBC_OPCODE (CBC_EXT_PUSH_SUPER, CBC_NO_FLAG, 1, \
VM_OC_NONE) \
CBC_OPCODE (CBC_EXT_PUSH_SUPER_CONSTRUCTOR, CBC_NO_FLAG, 1, \
diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c
index e861ecda9..efcf9238a 100644
--- a/jerry-core/parser/js/js-lexer.c
+++ b/jerry-core/parser/js/js-lexer.c
@@ -433,6 +433,7 @@ lexer_skip_spaces (parser_context_t *context_p) /**< context */
} /* lexer_skip_spaces */
#if ENABLED (JERRY_ESNEXT)
+
/**
* Skip all the continuous empty statements.
*/
@@ -450,6 +451,22 @@ lexer_skip_empty_statements (parser_context_t *context_p) /**< context */
context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES);
} /* lexer_skip_empty_statements */
+
+#endif /* ENABLED (JERRY_ESNEXT) */
+
+#if ENABLED (JERRY_ESNEXT)
+/**
+ * Checks whether the keyword has escape sequences.
+ */
+#define LEXER_CHECK_INVALID_KEYWORD(ident_start_p, buffer_p) \
+ (JERRY_UNLIKELY ((ident_start_p) == (buffer_p)) \
+ && !(context_p->global_status_flags & ECMA_PARSE_INTERNAL_PRE_SCANNING))
+#else /* !ENABLED (JERRY_ESNEXT) */
+/**
+ * Checks whether the keyword has escape sequences.
+ */
+#define LEXER_CHECK_INVALID_KEYWORD(ident_start_p, buffer_p) \
+ (JERRY_UNLIKELY ((ident_start_p) == (buffer_p)))
#endif /* ENABLED (JERRY_ESNEXT) */
/**
@@ -807,7 +824,6 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
JERRY_ASSERT (length > 0);
context_p->token.type = LEXER_LITERAL;
- context_p->token.keyword_type = LEXER_EOS;
context_p->token.lit_location.type = LEXER_IDENT_LITERAL;
context_p->token.lit_location.has_escape = has_escape;
@@ -865,7 +881,7 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
if (context_p->status_flags & PARSER_DISALLOW_AWAIT_YIELD)
{
- if (ident_start_p == buffer_p)
+ if (LEXER_CHECK_INVALID_KEYWORD (ident_start_p, buffer_p))
{
parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD);
}
@@ -877,7 +893,7 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
}
#endif /* ENABLED (JERRY_ESNEXT) */
- if (ident_start_p == buffer_p)
+ if (LEXER_CHECK_INVALID_KEYWORD (ident_start_p, buffer_p))
{
/* Escape sequences are not allowed in a keyword. */
parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD);
@@ -890,7 +906,7 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
#if ENABLED (JERRY_ESNEXT)
if (keyword_p->type == LEXER_KEYW_LET && (context_p->status_flags & PARSER_IS_STRICT))
{
- if (ident_start_p == buffer_p)
+ if (LEXER_CHECK_INVALID_KEYWORD (ident_start_p, buffer_p))
{
parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD);
}
@@ -903,7 +919,7 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
{
if (context_p->status_flags & PARSER_DISALLOW_AWAIT_YIELD)
{
- if (ident_start_p == buffer_p)
+ if (LEXER_CHECK_INVALID_KEYWORD (ident_start_p, buffer_p))
{
parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD);
}
@@ -913,6 +929,11 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
context_p->token.type = (uint8_t) LEXER_KEYW_YIELD;
break;
}
+
+ if (keyword_p->type == LEXER_KEYW_ARGUMENTS && (context_p->status_flags & PARSER_INSIDE_CLASS_FIELD))
+ {
+ parser_raise_error (context_p, PARSER_ERR_ARGUMENTS_IN_CLASS_FIELD);
+ }
#endif /* ENABLED (JERRY_ESNEXT) */
if (keyword_p->type >= LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD
@@ -944,6 +965,8 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
return true;
} /* lexer_parse_identifier */
+#undef LEXER_CHECK_INVALID_KEYWORD
+
/**
* Parse string.
*/
@@ -1118,9 +1141,6 @@ lexer_parse_string (parser_context_t *context_p, /**< context */
uint32_t escape_length = (*source_p == LIT_CHAR_LOWERCASE_X) ? 3 : 5;
lit_code_point_t code_point = UINT32_MAX;
- context_p->token.line = line;
- context_p->token.column = (parser_line_counter_t) (column - 1);
-
#if ENABLED (JERRY_ESNEXT)
if (source_p + 4 <= source_end_p
&& source_p[0] == LIT_CHAR_LOWERCASE_U
@@ -1142,6 +1162,8 @@ lexer_parse_string (parser_context_t *context_p, /**< context */
if (code_point == UINT32_MAX)
{
+ context_p->token.line = line;
+ context_p->token.column = (parser_line_counter_t) (column - 1);
parser_raise_error (context_p, PARSER_ERR_INVALID_UNICODE_ESCAPE_SEQUENCE);
}
@@ -1312,7 +1334,6 @@ lexer_parse_number (parser_context_t *context_p) /**< context */
size_t length;
context_p->token.type = LEXER_LITERAL;
- context_p->token.keyword_type = LEXER_EOS;
context_p->token.extra_value = LEXER_NUMBER_DECIMAL;
context_p->token.lit_location.char_p = source_p;
context_p->token.lit_location.type = LEXER_NUMBER_LITERAL;
@@ -1571,6 +1592,7 @@ lexer_next_token (parser_context_t *context_p) /**< context */
lexer_skip_spaces (context_p);
+ context_p->token.keyword_type = LEXER_EOS;
context_p->token.line = context_p->line;
context_p->token.column = context_p->column;
@@ -2079,6 +2101,33 @@ lexer_consume_generator (parser_context_t *context_p) /**< context */
return true;
} /* lexer_consume_generator */
+/**
+ * Checks whether the next token is an equal sign and consumes it.
+ *
+ * @return true if the next token is an equal sign
+ */
+bool
+lexer_consume_assign (parser_context_t *context_p) /**< context */
+{
+ if (!(context_p->token.flags & LEXER_NO_SKIP_SPACES))
+ {
+ lexer_skip_spaces (context_p);
+ context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES);
+ }
+
+ if (context_p->source_p >= context_p->source_end_p
+ || context_p->source_p[0] != LIT_CHAR_EQUALS
+ || (context_p->source_p + 1 < context_p->source_end_p
+ && (context_p->source_p[1] == LIT_CHAR_EQUALS || context_p->source_p[1] == LIT_CHAR_GREATER_THAN)))
+ {
+ return false;
+ }
+
+ lexer_consume_next_character (context_p);
+ context_p->token.type = LEXER_ASSIGN;
+ return true;
+} /* lexer_consume_assign */
+
/**
* Update await / yield keywords after an arrow function with expression.
*/
@@ -2409,6 +2458,27 @@ lexer_convert_literal_to_chars (parser_context_t *context_p, /**< context */
return destination_start_p;
} /* lexer_convert_literal_to_chars */
+/**
+ * Construct an unused literal.
+ *
+ * @return a newly allocated literal
+ */
+lexer_literal_t *
+lexer_construct_unused_literal (parser_context_t *context_p) /**< context */
+{
+ lexer_literal_t *literal_p;
+
+ if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
+ {
+ parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
+ }
+
+ literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
+ literal_p->type = LEXER_UNUSED_LITERAL;
+ literal_p->status_flags = 0;
+ return literal_p;
+} /* lexer_construct_unused_literal */
+
/**
* Construct a literal object from an identifier.
*/
@@ -2755,34 +2825,32 @@ lexer_construct_function_object (parser_context_t *context_p, /**< context */
lexer_literal_t *literal_p;
uint16_t result_index;
- if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
- {
- parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
- }
-
- parser_flush_cbc (context_p);
-
if (context_p->status_flags & PARSER_INSIDE_WITH)
{
extra_status_flags |= PARSER_INSIDE_WITH;
}
- literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
- literal_p->type = LEXER_UNUSED_LITERAL;
- literal_p->status_flags = 0;
-
+ literal_p = lexer_construct_unused_literal (context_p);
result_index = context_p->literal_count;
context_p->literal_count++;
+ parser_flush_cbc (context_p);
+
#if ENABLED (JERRY_ESNEXT)
- if (!(extra_status_flags & PARSER_IS_ARROW_FUNCTION))
+ if (JERRY_LIKELY (!(extra_status_flags & PARSER_IS_ARROW_FUNCTION)))
{
compiled_code_p = parser_parse_function (context_p, extra_status_flags);
}
- else
+ else if (JERRY_LIKELY (!(extra_status_flags & PARSER_CLASS_CONSTRUCTOR)))
{
compiled_code_p = parser_parse_arrow_function (context_p, extra_status_flags);
}
+ else
+ {
+ /* Since PARSER_IS_ARROW_FUNCTION and PARSER_CLASS_CONSTRUCTOR bits cannot
+ * be set at the same time, this bit combination triggers class field parsing. */
+ compiled_code_p = parser_parse_class_fields (context_p);
+ }
#else /* !ENABLED (JERRY_ESNEXT) */
compiled_code_p = parser_parse_function (context_p, extra_status_flags);
#endif /* ENABLED (JERRY_ESNEXT) */
@@ -3031,14 +3099,12 @@ lexer_construct_regexp_object (parser_context_t *context_p, /**< context */
literal_p->type = literal_type;
literal_p->prop.length = (prop_length_t) length;
literal_p->status_flags = 0;
- context_p->literal_count++;
context_p->token.type = LEXER_LITERAL;
- context_p->token.keyword_type = LEXER_EOS;
context_p->token.lit_location.type = LEXER_REGEXP_LITERAL;
context_p->lit_object.literal_p = literal_p;
- context_p->lit_object.index = (uint16_t) (context_p->literal_count - 1);
+ context_p->lit_object.index = context_p->literal_count++;
#else /* !ENABLED (JERRY_BUILTIN_REGEXP) */
JERRY_UNUSED (parse_only);
parser_raise_error (context_p, PARSER_ERR_UNSUPPORTED_REGEXP);
@@ -3057,6 +3123,7 @@ lexer_expect_identifier (parser_context_t *context_p, /**< context */
|| literal_type == LEXER_NEW_IDENT_LITERAL);
lexer_skip_spaces (context_p);
+ context_p->token.keyword_type = LEXER_EOS;
context_p->token.line = context_p->line;
context_p->token.column = context_p->column;
@@ -3093,7 +3160,6 @@ lexer_expect_identifier (parser_context_t *context_p, /**< context */
/* When parsing default exports for modules, it is not required by functions or classes to have identifiers.
* In this case we use a synthetic name for them. */
context_p->token.type = LEXER_LITERAL;
- context_p->token.keyword_type = LEXER_EOS;
context_p->token.lit_location = lexer_default_literal;
lexer_construct_literal_object (context_p, &context_p->token.lit_location, literal_type);
context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_DEFAULT_CLASS_OR_FUNC);
@@ -3128,16 +3194,14 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
parser_raise_error (context_p, PARSER_ERR_PROPERTY_IDENTIFIER_EXPECTED);
}
-#if ENABLED (JERRY_ESNEXT)
- int is_class_method = ((ident_opts & LEXER_OBJ_IDENT_CLASS_METHOD)
- && !(ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS)
- && (context_p->token.type != LEXER_KEYW_STATIC));
-#endif /* ENABLED (JERRY_ESNEXT) */
-
+ context_p->token.keyword_type = LEXER_EOS;
context_p->token.line = context_p->line;
context_p->token.column = context_p->column;
bool create_literal_object = false;
+ JERRY_ASSERT ((ident_opts & LEXER_OBJ_IDENT_CLASS_IDENTIFIER)
+ || !(ident_opts & LEXER_OBJ_IDENT_CLASS_NO_STATIC));
+
if (lexer_parse_identifier (context_p, LEXER_PARSE_NO_OPTS))
{
if (!(ident_opts & (LEXER_OBJ_IDENT_ONLY_IDENTIFIERS | LEXER_OBJ_IDENT_OBJECT_PATTERN)))
@@ -3150,6 +3214,8 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
&& context_p->source_p[0] != LIT_CHAR_COMMA
&& context_p->source_p[0] != LIT_CHAR_RIGHT_BRACE
&& context_p->source_p[0] != LIT_CHAR_LEFT_PAREN
+ && context_p->source_p[0] != LIT_CHAR_SEMICOLON
+ && context_p->source_p[0] != LIT_CHAR_EQUALS
#endif /* ENABLED (JERRY_ESNEXT) */
&& context_p->source_p[0] != LIT_CHAR_COLON)
{
@@ -3171,18 +3237,19 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
context_p->token.type = LEXER_KEYW_ASYNC;
return;
}
+
+ if (ident_opts & LEXER_OBJ_IDENT_CLASS_NO_STATIC)
+ {
+ if (lexer_compare_literal_to_string (context_p, "static", 6))
+ {
+ context_p->token.type = LEXER_KEYW_STATIC;
+ }
+ return;
+ }
#endif /* ENABLED (JERRY_ESNEXT) */
}
}
-#if ENABLED (JERRY_ESNEXT)
- if (is_class_method && lexer_compare_literal_to_string (context_p, "static", 6))
- {
- context_p->token.type = LEXER_KEYW_STATIC;
- return;
- }
-#endif /* ENABLED (JERRY_ESNEXT) */
-
create_literal_object = true;
}
else
@@ -3263,7 +3330,11 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
&& char_p[0] <= LIT_CHAR_9)
{
lexer_parse_number (context_p);
- lexer_construct_number_object (context_p, false, false);
+
+ if (!(ident_opts & LEXER_OBJ_IDENT_CLASS_IDENTIFIER))
+ {
+ lexer_construct_number_object (context_p, false, false);
+ }
return;
}
break;
@@ -3274,10 +3345,8 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
if (create_literal_object)
{
#if ENABLED (JERRY_ESNEXT)
- if (is_class_method && lexer_compare_literal_to_string (context_p, "constructor", 11))
+ if (ident_opts & LEXER_OBJ_IDENT_CLASS_IDENTIFIER)
{
- context_p->token.type = LEXER_CLASS_CONSTRUCTOR;
- context_p->token.flags &= (uint8_t) ~LEXER_NO_SKIP_SPACES;
return;
}
#endif /* ENABLED (JERRY_ESNEXT) */
@@ -3300,6 +3369,7 @@ bool
lexer_scan_identifier (parser_context_t *context_p) /**< context */
{
lexer_skip_spaces (context_p);
+ context_p->token.keyword_type = LEXER_EOS;
context_p->token.line = context_p->line;
context_p->token.column = context_p->column;
@@ -3309,6 +3379,7 @@ lexer_scan_identifier (parser_context_t *context_p) /**< context */
return true;
}
+ context_p->token.flags |= LEXER_NO_SKIP_SPACES;
lexer_next_token (context_p);
return false;
} /* lexer_scan_identifier */
diff --git a/jerry-core/parser/js/js-lexer.h b/jerry-core/parser/js/js-lexer.h
index 6b6cd2c26..67760ec98 100644
--- a/jerry-core/parser/js/js-lexer.h
+++ b/jerry-core/parser/js/js-lexer.h
@@ -198,7 +198,6 @@ typedef enum
#if ENABLED (JERRY_ESNEXT)
LEXER_ASSIGN_GROUP_EXPR, /**< indetifier for the assignment is located in a group expression */
LEXER_ASSIGN_CONST, /**< a const binding is reassigned */
- LEXER_CLASS_CONSTRUCTOR, /**< special value for class constructor method */
LEXER_INVALID_PATTERN, /**< special value for invalid destructuring pattern */
#endif /* ENABLED (JERRY_ESNEXT) */
@@ -276,8 +275,9 @@ typedef enum
{
LEXER_OBJ_IDENT_NO_OPTS = (1u << 0), /**< no options */
LEXER_OBJ_IDENT_ONLY_IDENTIFIERS = (1u << 1), /**< only identifiers are accepted */
- LEXER_OBJ_IDENT_CLASS_METHOD = (1u << 2), /**< expect identifier inside a class body */
- LEXER_OBJ_IDENT_OBJECT_PATTERN = (1u << 3), /**< parse "get"/"set" as string literal in object pattern */
+ LEXER_OBJ_IDENT_CLASS_IDENTIFIER = (1u << 2), /**< expect identifier inside a class body */
+ LEXER_OBJ_IDENT_CLASS_NO_STATIC = (1u << 3), /**< static keyword was not present before the identifier */
+ LEXER_OBJ_IDENT_OBJECT_PATTERN = (1u << 4), /**< parse "get"/"set" as string literal in object pattern */
} lexer_obj_ident_opts_t;
/**
diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c
index fe817b745..926f287c7 100644
--- a/jerry-core/parser/js/js-parser-expr.c
+++ b/jerry-core/parser/js/js-parser-expr.c
@@ -491,22 +491,6 @@ parser_parse_array_initializer (parser_context_t *context_p, parser_pattern_flag
static void
parser_parse_object_initializer (parser_context_t *context_p, parser_pattern_flags_t flags);
-/**
- * Description of "get" literal string.
- */
-static const lexer_lit_location_t lexer_get_literal =
-{
- (const uint8_t *) "get", 3, LEXER_STRING_LITERAL, false
-};
-
-/**
- * Description of "set" literal string.
- */
-static const lexer_lit_location_t lexer_set_literal =
-{
- (const uint8_t *) "set", 3, LEXER_STRING_LITERAL, false
-};
-
/**
* Class literal parsing options.
*/
@@ -517,6 +501,18 @@ typedef enum
PARSER_CLASS_LITERAL_HERTIAGE_PRESENT = (1 << 1), /**< class heritage is present */
} parser_class_literal_opts_t;
+/**
+ * Checks whether the current string or identifier literal is constructor
+ *
+ * @return true, if constructor and false otherwise
+ */
+static inline bool JERRY_ATTR_ALWAYS_INLINE
+parser_is_constructor_literal (parser_context_t *context_p) /**< context */
+{
+ return (LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type)
+ && lexer_compare_literal_to_string (context_p, "constructor", 11));
+} /* parser_is_constructor_literal */
+
/**
* Parse class literal.
*/
@@ -526,20 +522,11 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
{
JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE);
- uint32_t status_flags = PARSER_FUNCTION_CLOSURE | PARSER_ALLOW_SUPER;
-
lexer_literal_t *ctor_literal_p = NULL;
if (opts & PARSER_CLASS_LITERAL_CTOR_PRESENT)
{
- if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
- {
- parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
- }
-
- ctor_literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
- ctor_literal_p->type = LEXER_UNUSED_LITERAL;
- ctor_literal_p->status_flags = 0;
+ ctor_literal_p = lexer_construct_unused_literal (context_p);
parser_emit_cbc_literal (context_p, CBC_PUSH_LITERAL, (uint16_t) (context_p->literal_count++));
}
else if (opts & PARSER_CLASS_LITERAL_HERTIAGE_PRESENT)
@@ -554,6 +541,7 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
parser_emit_cbc_ext (context_p, CBC_EXT_INIT_CLASS);
bool is_static = false;
+ size_t fields_size = 0;
while (true)
{
@@ -562,17 +550,56 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
lexer_skip_empty_statements (context_p);
}
- lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_CLASS_METHOD);
+ lexer_expect_object_literal_id (context_p, (LEXER_OBJ_IDENT_CLASS_IDENTIFIER
+ | (is_static ? 0 : LEXER_OBJ_IDENT_CLASS_NO_STATIC)));
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
- if (JERRY_UNLIKELY (is_static))
- {
- parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
- }
+ JERRY_ASSERT (!is_static);
break;
}
+ if (context_p->token.type == LEXER_KEYW_STATIC)
+ {
+ JERRY_ASSERT (!is_static);
+ is_static = true;
+ continue;
+ }
+
+ if (!is_static && context_p->token.type == LEXER_LITERAL && parser_is_constructor_literal (context_p))
+ {
+ JERRY_ASSERT (!is_static);
+ JERRY_ASSERT (opts & PARSER_CLASS_LITERAL_CTOR_PRESENT);
+ JERRY_ASSERT (ctor_literal_p != NULL);
+
+ if (ctor_literal_p->type == LEXER_FUNCTION_LITERAL)
+ {
+ /* 14.5.1 */
+ parser_raise_error (context_p, PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS);
+ }
+
+ uint32_t constructor_status_flags = (PARSER_FUNCTION_CLOSURE
+ | PARSER_ALLOW_SUPER
+ | PARSER_CLASS_CONSTRUCTOR
+ | PARSER_LEXICAL_ENV_NEEDED);
+
+ if (opts & PARSER_CLASS_LITERAL_HERTIAGE_PRESENT)
+ {
+ constructor_status_flags |= PARSER_ALLOW_SUPER_CALL;
+ }
+
+ if (context_p->status_flags & PARSER_INSIDE_WITH)
+ {
+ constructor_status_flags |= PARSER_INSIDE_WITH;
+ }
+
+ parser_flush_cbc (context_p);
+ ecma_compiled_code_t *compiled_code_p = parser_parse_function (context_p, constructor_status_flags);
+ ctor_literal_p->u.bytecode_p = compiled_code_p;
+ ctor_literal_p->type = LEXER_FUNCTION_LITERAL;
+ continue;
+ }
+
bool is_computed = false;
if (context_p->token.type == LEXER_PROPERTY_GETTER || context_p->token.type == LEXER_PROPERTY_SETTER)
@@ -580,28 +607,17 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
uint16_t literal_index, function_literal_index;
bool is_getter = (context_p->token.type == LEXER_PROPERTY_GETTER);
- if (lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
- {
- lexer_construct_literal_object (context_p,
- (is_getter ? (lexer_lit_location_t *) &lexer_get_literal
- : (lexer_lit_location_t *) &lexer_set_literal),
- LEXER_STRING_LITERAL);
- goto parse_class_method;
- }
-
- uint32_t accessor_status_flags = status_flags;
+ uint32_t accessor_status_flags = PARSER_FUNCTION_CLOSURE | PARSER_ALLOW_SUPER;
accessor_status_flags |= (is_getter ? PARSER_IS_PROPERTY_GETTER : PARSER_IS_PROPERTY_SETTER);
- lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_CLASS_METHOD | LEXER_OBJ_IDENT_ONLY_IDENTIFIERS);
+ lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS);
literal_index = context_p->lit_object.index;
if (context_p->token.type == LEXER_RIGHT_SQUARE)
{
is_computed = true;
}
- else if (!is_static
- && LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type)
- && lexer_compare_literal_to_string (context_p, "constructor", 11))
+ else if (!is_static && parser_is_constructor_literal (context_p))
{
parser_raise_error (context_p, PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR);
}
@@ -659,45 +675,7 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
continue;
}
- if (!is_static)
- {
- if (context_p->token.type == LEXER_KEYW_STATIC)
- {
- is_static = true;
- continue;
- }
-
- if (context_p->token.type == LEXER_CLASS_CONSTRUCTOR)
- {
- JERRY_ASSERT (opts & PARSER_CLASS_LITERAL_CTOR_PRESENT);
- JERRY_ASSERT (ctor_literal_p != NULL);
-
- if (ctor_literal_p->type == LEXER_FUNCTION_LITERAL)
- {
- /* 14.5.1 */
- parser_raise_error (context_p, PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS);
- }
-
- uint32_t constructor_status_flags = (status_flags
- | PARSER_CLASS_CONSTRUCTOR
- | PARSER_LEXICAL_ENV_NEEDED);
-
- if (opts & PARSER_CLASS_LITERAL_HERTIAGE_PRESENT)
- {
- constructor_status_flags |= PARSER_ALLOW_SUPER_CALL;
- }
-
- parser_flush_cbc (context_p);
- ecma_compiled_code_t *compiled_code_p = parser_parse_function (context_p, constructor_status_flags);
- ctor_literal_p->u.bytecode_p = compiled_code_p;
- ctor_literal_p->type = LEXER_FUNCTION_LITERAL;
- continue;
- }
- }
-
- status_flags &= (uint32_t) ~(PARSER_IS_GENERATOR_FUNCTION
- | PARSER_IS_ASYNC_FUNCTION
- | PARSER_DISALLOW_AWAIT_YIELD);
+ uint32_t status_flags = PARSER_FUNCTION_CLOSURE | PARSER_ALLOW_SUPER;
if (context_p->token.type == LEXER_KEYW_ASYNC)
{
@@ -728,15 +706,164 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */
parser_raise_error (context_p, PARSER_ERR_CLASS_STATIC_PROTOTYPE);
}
}
- else if ((status_flags & PARSER_IS_GENERATOR_FUNCTION)
+ else if ((status_flags & (PARSER_IS_ASYNC_FUNCTION | PARSER_IS_GENERATOR_FUNCTION))
&& lexer_compare_literal_to_string (context_p, "constructor", 11))
{
- parser_raise_error (context_p, PARSER_ERR_CLASS_CONSTRUCTOR_AS_GENERATOR);
+ parser_raise_error (context_p, PARSER_ERR_INVALID_CLASS_CONSTRUCTOR);
+ }
+ }
+
+ if (!(status_flags & (PARSER_IS_ASYNC_FUNCTION | PARSER_IS_GENERATOR_FUNCTION)))
+ {
+ if (!is_static && !lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
+ {
+ /* Class field. */
+ if (fields_size == 0)
+ {
+ parser_stack_push_uint8 (context_p, PARSER_CLASS_FIELD_END);
+ }
+
+ scanner_range_t range;
+ uint8_t class_field_type = 0;
+
+ if (!is_computed)
+ {
+ range.start_location.source_p = context_p->token.lit_location.char_p;
+ range.start_location.line = context_p->token.line;
+ range.start_location.column = context_p->token.column;
+ class_field_type = PARSER_CLASS_FIELD_NORMAL;
+
+ if (context_p->token.lit_location.type == LEXER_STRING_LITERAL)
+ {
+ range.start_location.source_p--;
+ }
+ }
+ else
+ {
+ parser_emit_cbc_ext (context_p, CBC_EXT_ADD_COMPUTED_FIELD);
+ }
+
+ if (lexer_consume_assign (context_p))
+ {
+ class_field_type |= PARSER_CLASS_FIELD_INITIALIZED;
+
+ if (context_p->next_scanner_info_p->source_p != context_p->source_p)
+ {
+ lexer_next_token (context_p);
+ parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
+ parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
+ }
+
+ if (is_computed)
+ {
+ scanner_get_location (&range.start_location, context_p);
+ }
+
+ JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_CLASS_FIELD_INITIALIZER_END);
+ range.source_end_p = ((scanner_location_info_t *) context_p->next_scanner_info_p)->location.source_p;
+
+ scanner_set_location (context_p, &((scanner_location_info_t *) context_p->next_scanner_info_p)->location);
+ scanner_release_next (context_p, sizeof (scanner_location_info_t));
+ scanner_seek (context_p);
+
+ parser_stack_push (context_p, &range, sizeof (scanner_range_t));
+ fields_size += sizeof (scanner_range_t);
+ }
+ else
+ {
+ if (!(context_p->token.flags & LEXER_WAS_NEWLINE)
+ && !lexer_check_next_characters (context_p, LIT_CHAR_SEMICOLON, LIT_CHAR_RIGHT_BRACE))
+ {
+ lexer_next_token (context_p);
+ parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
+ }
+
+ if (!is_computed)
+ {
+ parser_stack_push (context_p, &range.start_location, sizeof (scanner_location_t));
+ fields_size += sizeof (scanner_location_t);
+ }
+ }
+
+ parser_stack_push_uint8 (context_p, class_field_type);
+ fields_size++;
+ is_static = false;
+ continue;
+ }
+
+ if (!is_computed)
+ {
+ if (context_p->token.lit_location.type != LEXER_NUMBER_LITERAL)
+ {
+ JERRY_ASSERT (context_p->token.lit_location.type == LEXER_IDENT_LITERAL
+ || context_p->token.lit_location.type == LEXER_STRING_LITERAL);
+ lexer_construct_literal_object (context_p,
+ &context_p->token.lit_location,
+ LEXER_STRING_LITERAL);
+ }
+ else
+ {
+ lexer_construct_number_object (context_p, false, false);
+ }
+ }
+
+ if (is_static && !lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
+ {
+ if (!is_computed && parser_is_constructor_literal (context_p))
+ {
+ parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIST_EXPECTED);
+ }
+
+ uint16_t literal_index = context_p->lit_object.index;
+ context_p->status_flags |= PARSER_INSIDE_CLASS_FIELD;
+
+ if (lexer_consume_assign (context_p))
+ {
+ if (context_p->next_scanner_info_p->source_p != context_p->source_p)
+ {
+ lexer_next_token (context_p);
+ parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
+ parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
+ }
+
+ JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_CLASS_FIELD_INITIALIZER_END);
+
+ /* Changing the source_end_p prevents the lexer to process the name of the next class field
+ * as normal token which may cause issues if the name is also a keyword (e.g. var). */
+ const uint8_t *source_end_p = context_p->source_end_p;
+ context_p->source_end_p = ((scanner_location_info_t *) context_p->next_scanner_info_p)->location.source_p;
+ scanner_release_next (context_p, sizeof (scanner_location_info_t));
+
+ lexer_next_token (context_p);
+ parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
+
+ if (context_p->token.type != LEXER_EOS)
+ {
+ parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
+ }
+
+ context_p->source_end_p = source_end_p;
+ }
+ else
+ {
+ parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED);
+ }
+
+ if (!is_computed)
+ {
+ parser_emit_cbc_ext_literal (context_p, CBC_EXT_SET_STATIC_PROPERTY, literal_index);
+ }
+ else
+ {
+ parser_emit_cbc_ext (context_p, CBC_EXT_SET_STATIC_COMPUTED_PROPERTY);
+ }
+
+ context_p->status_flags &= (uint32_t) ~PARSER_INSIDE_CLASS_FIELD;
+ is_static = false;
+ continue;
}
}
-parse_class_method:
- ; /* Empty statement to make compiler happy. */
uint16_t literal_index = context_p->lit_object.index;
uint16_t function_literal_index = lexer_construct_function_object (context_p, status_flags | PARSER_IS_METHOD);
@@ -769,6 +896,17 @@ parse_class_method:
context_p->last_cbc_opcode = CBC_SET_LITERAL_PROPERTY;
}
}
+
+ if (fields_size > 0)
+ {
+ parser_reverse_class_fields (context_p, fields_size);
+
+ /* Since PARSER_IS_ARROW_FUNCTION and PARSER_CLASS_CONSTRUCTOR bits cannot
+ * be set at the same time, this bit combination triggers class field parsing. */
+ uint16_t function_literal_index = lexer_construct_function_object (context_p, (PARSER_IS_ARROW_FUNCTION
+ | PARSER_CLASS_CONSTRUCTOR));
+ parser_emit_cbc_ext_literal (context_p, CBC_EXT_SET_CLASS_FIELD_INIT, function_literal_index);
+ }
} /* parser_parse_class_literal */
/**
@@ -1813,7 +1951,9 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION);
- uint32_t arrow_status_flags = (PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION);
+ uint32_t arrow_status_flags = (PARSER_IS_FUNCTION
+ | PARSER_IS_ARROW_FUNCTION
+ | (context_p->status_flags & PARSER_INSIDE_CLASS_FIELD));
if (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_ASYNC)
{
@@ -2073,7 +2213,10 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
parser_check_assignment_expr (context_p);
- parser_parse_function_expression (context_p, PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION);
+ uint32_t arrow_status_flags = (PARSER_IS_FUNCTION
+ | PARSER_IS_ARROW_FUNCTION
+ | (context_p->status_flags & PARSER_INSIDE_CLASS_FIELD));
+ parser_parse_function_expression (context_p, arrow_status_flags);
return parser_abort_parsing_after_assignment_expression (context_p);
}
case LEXER_KEYW_YIELD:
@@ -3442,11 +3585,6 @@ parser_parse_object_initializer (parser_context_t *context_p, /**< context */
}
parser_reparse_as_common_identifier (context_p, start_line, start_column);
- lexer_next_token (context_p);
-
- JERRY_ASSERT (context_p->token.type == LEXER_RIGHT_BRACE
- || context_p->token.type == LEXER_ASSIGN
- || context_p->token.type == LEXER_COMMA);
if (flags & PARSER_PATTERN_ARGUMENTS)
{
@@ -3462,6 +3600,12 @@ parser_parse_object_initializer (parser_context_t *context_p, /**< context */
#endif /* ENABLED (JERRY_MODULE_SYSTEM) */
parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
+
+ lexer_next_token (context_p);
+ JERRY_ASSERT (context_p->token.type == LEXER_RIGHT_BRACE
+ || context_p->token.type == LEXER_ASSIGN
+ || context_p->token.type == LEXER_COMMA);
+
parser_pattern_form_assignment (context_p, flags, push_prop_opcode, prop_index, start_line);
}
diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h
index 888370495..d337c62da 100644
--- a/jerry-core/parser/js/js-parser-internal.h
+++ b/jerry-core/parser/js/js-parser-internal.h
@@ -69,16 +69,17 @@ typedef enum
PARSER_FUNCTION_HAS_REST_PARAM = (1u << 19), /**< function has rest parameter */
PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed
* Note: PARSER_ALLOW_SUPER must be present */
- /* These three status flags must be in this order. See PARSER_SAVED_FLAGS_OFFSET. */
+ /* These four status flags must be in this order. See PARSER_SAVED_FLAGS_OFFSET. */
PARSER_ALLOW_SUPER = (1u << 21), /**< allow super property access */
PARSER_ALLOW_SUPER_CALL = (1u << 22), /**< allow super constructor call
* Note: PARSER_CLASS_CONSTRUCTOR must be present */
- PARSER_ALLOW_NEW_TARGET = (1u << 23), /**< allow new.target parsing in the current context */
- PARSER_IS_METHOD = (1u << 24), /**< method is parsed */
+ PARSER_INSIDE_CLASS_FIELD = (1u << 23), /**< a class field is being parsed */
+ PARSER_ALLOW_NEW_TARGET = (1u << 24), /**< allow new.target parsing in the current context */
+ PARSER_IS_METHOD = (1u << 25), /**< method is parsed */
#endif /* ENABLED (JERRY_ESNEXT) */
#if ENABLED (JERRY_MODULE_SYSTEM)
- PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 25), /**< parsing a function or class default export */
- PARSER_MODULE_STORE_IDENT = (1u << 26), /**< store identifier of the current export statement */
+ PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 26), /**< parsing a function or class default export */
+ PARSER_MODULE_STORE_IDENT = (1u << 27), /**< store identifier of the current export statement */
#endif /* ENABLED (JERRY_MODULE_SYSTEM) */
PARSER_HAS_LATE_LIT_INIT = (1u << 30), /**< there are identifier or string literals which construction
* is postponed after the local parser data is freed */
@@ -129,6 +130,20 @@ typedef enum
#endif /* ENABLED (JERRY_ESNEXT) */
} parser_check_context_type_t;
+#if ENABLED (JERRY_ESNEXT)
+
+/**
+ * Class field bits.
+ */
+typedef enum
+{
+ PARSER_CLASS_FIELD_END = (1u << 0), /**< last class field */
+ PARSER_CLASS_FIELD_NORMAL = (1u << 1), /**< normal (non-computed) class field */
+ PARSER_CLASS_FIELD_INITIALIZED = (1u << 2), /**< class field is initialized */
+} parser_class_field_type_t;
+
+#endif /* ENABLED (JERRY_ESNEXT) */
+
/**
* Mask for strict mode code
*/
@@ -704,6 +719,10 @@ void parser_set_continues_to_current_position (parser_context_t *context_p, pars
#define parser_emit_cbc_ext_backward_branch(context_p, opcode, offset) \
parser_emit_cbc_backward_branch ((context_p), PARSER_TO_EXT_OPCODE (opcode), (offset))
+#if ENABLED (JERRY_ESNEXT)
+void parser_reverse_class_fields (parser_context_t *context_p, size_t fields_size);
+#endif /* ENABLED (JERRY_ESNEXT) */
+
/**
* @}
*
@@ -725,6 +744,7 @@ bool lexer_check_arrow (parser_context_t *context_p);
bool lexer_check_arrow_param (parser_context_t *context_p);
bool lexer_check_yield_no_arg (parser_context_t *context_p);
bool lexer_consume_generator (parser_context_t *context_p);
+bool lexer_consume_assign (parser_context_t *context_p);
void lexer_update_await_yield (parser_context_t *context_p, uint32_t status_flags);
#endif /* ENABLED (JERRY_ESNEXT) */
void lexer_parse_string (parser_context_t *context_p, lexer_string_options_t opts);
@@ -736,7 +756,7 @@ void lexer_convert_ident_to_cesu8 (uint8_t *destination_p, const uint8_t *source
const uint8_t *lexer_convert_literal_to_chars (parser_context_t *context_p, const lexer_lit_location_t *literal_p,
uint8_t *local_byte_array_p, lexer_string_options_t opts);
void lexer_expect_object_literal_id (parser_context_t *context_p, uint32_t ident_opts);
-uint16_t scanner_save_literal (parser_context_t *context_p, uint16_t ident_index);
+lexer_literal_t *lexer_construct_unused_literal (parser_context_t *context_p);
void lexer_construct_literal_object (parser_context_t *context_p, const lexer_lit_location_t *lit_location_p,
uint8_t literal_type);
bool lexer_construct_number_object (parser_context_t *context_p, bool is_expr, bool is_negative_number);
@@ -804,6 +824,7 @@ void scanner_get_location (scanner_location_t *location_p, parser_context_t *con
void scanner_set_location (parser_context_t *context_p, scanner_location_t *location_p);
uint16_t scanner_decode_map_to (parser_scope_stack_t *stack_item_p);
#if ENABLED (JERRY_ESNEXT)
+uint16_t scanner_save_literal (parser_context_t *context_p, uint16_t ident_index);
bool scanner_literal_is_const_reg (parser_context_t *context_p, uint16_t literal_index);
bool scanner_literal_is_created (parser_context_t *context_p, uint16_t literal_index);
#endif /* ENABLED (JERRY_ESNEXT) */
@@ -859,6 +880,7 @@ void parser_module_add_names_to_node (parser_context_t *context_p,
ecma_compiled_code_t *parser_parse_function (parser_context_t *context_p, uint32_t status_flags);
#if ENABLED (JERRY_ESNEXT)
ecma_compiled_code_t *parser_parse_arrow_function (parser_context_t *context_p, uint32_t status_flags);
+ecma_compiled_code_t *parser_parse_class_fields (parser_context_t *context_p);
void parser_set_function_name (parser_context_t *context_p, uint16_t function_literal_index, uint16_t name_index,
uint32_t status_flags);
void parser_compiled_code_set_function_name (parser_context_t *context_p, ecma_compiled_code_t *bytecode_p,
diff --git a/jerry-core/parser/js/js-parser-util.c b/jerry-core/parser/js/js-parser-util.c
index c4ee90b00..eea911caf 100644
--- a/jerry-core/parser/js/js-parser-util.c
+++ b/jerry-core/parser/js/js-parser-util.c
@@ -790,6 +790,78 @@ parser_set_continues_to_current_position (parser_context_t *context_p, /**< cont
}
} /* parser_set_continues_to_current_position */
+#if ENABLED (JERRY_ESNEXT)
+
+/**
+ * Reverse the field list of a class
+ */
+void
+parser_reverse_class_fields (parser_context_t *context_p, /**< context */
+ size_t fields_size) /**< size of consumed memory */
+{
+ uint8_t *data_p = (uint8_t *) parser_malloc (context_p, fields_size);
+ uint8_t *data_end_p = data_p + fields_size;
+ uint8_t *current_p = data_p;
+ parser_stack_iterator_t iterator;
+
+ parser_stack_iterator_init (context_p, &iterator);
+
+ do
+ {
+ uint8_t class_field_type = parser_stack_iterator_read_uint8 (&iterator);
+ parser_stack_iterator_skip (&iterator, 1);
+
+ if (class_field_type & PARSER_CLASS_FIELD_INITIALIZED)
+ {
+ parser_stack_iterator_read (&iterator, current_p, sizeof (scanner_range_t));
+ parser_stack_iterator_skip (&iterator, sizeof (scanner_range_t));
+ current_p += sizeof (scanner_range_t);
+ }
+ else if (class_field_type & PARSER_CLASS_FIELD_NORMAL)
+ {
+ parser_stack_iterator_read (&iterator, current_p, sizeof (scanner_location_t));
+ parser_stack_iterator_skip (&iterator, sizeof (scanner_location_t));
+ current_p += sizeof (scanner_location_t);
+ }
+
+ *current_p++ = class_field_type;
+ }
+ while (current_p < data_end_p);
+
+ parser_stack_iterator_init (context_p, &iterator);
+ current_p = data_end_p;
+ context_p->stack_top_uint8 = current_p[-1];
+
+ do
+ {
+ uint8_t class_field_type = current_p[-1];
+
+ if (class_field_type & PARSER_CLASS_FIELD_INITIALIZED)
+ {
+ current_p -= sizeof (scanner_range_t) + 1;
+ parser_stack_iterator_write (&iterator, current_p, sizeof (scanner_range_t) + 1);
+ parser_stack_iterator_skip (&iterator, sizeof (scanner_range_t) + 1);
+ }
+ else if (class_field_type & PARSER_CLASS_FIELD_NORMAL)
+ {
+ current_p -= sizeof (scanner_location_t) + 1;
+ parser_stack_iterator_write (&iterator, current_p, sizeof (scanner_location_t) + 1);
+ parser_stack_iterator_skip (&iterator, sizeof (scanner_location_t) + 1);
+ }
+ else
+ {
+ current_p--;
+ parser_stack_iterator_write (&iterator, current_p, 1);
+ parser_stack_iterator_skip (&iterator, 1);
+ }
+ }
+ while (current_p > data_p);
+
+ parser_free (data_p, fields_size);
+} /* parser_reverse_class_fields */
+
+#endif /* ENABLED (JERRY_ESNEXT) */
+
#if ENABLED (JERRY_ERROR_MESSAGES)
/**
* Returns with the string representation of the error
@@ -1170,9 +1242,9 @@ parser_error_to_string (parser_error_t error) /**< error code */
{
return "Class constructor may not be an accessor.";
}
- case PARSER_ERR_CLASS_CONSTRUCTOR_AS_GENERATOR:
+ case PARSER_ERR_INVALID_CLASS_CONSTRUCTOR:
{
- return "Class constructor may not be a generator.";
+ return "Class constructor may not be a generator or async function.";
}
case PARSER_ERR_CLASS_STATIC_PROTOTYPE:
{
@@ -1182,6 +1254,10 @@ parser_error_to_string (parser_error_t error) /**< error code */
{
return "Super is not allowed to be used here.";
}
+ case PARSER_ERR_ARGUMENTS_IN_CLASS_FIELD:
+ {
+ return "In class field declarations 'arguments' is not allowed.";
+ }
case PARSER_ERR_RIGHT_BRACE_EXPECTED:
{
return "Expected '}' token.";
diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c
index 6173e3c16..66a19b082 100644
--- a/jerry-core/parser/js/js-parser.c
+++ b/jerry-core/parser/js/js-parser.c
@@ -2578,6 +2578,13 @@ parser_parse_function (parser_context_t *context_p, /**< context */
parser_raise_error (context_p, PARSER_ERR_ONE_ARGUMENT_EXPECTED);
}
+#if ENABLED (JERRY_ESNEXT)
+ if ((context_p->status_flags & (PARSER_CLASS_CONSTRUCTOR | PARSER_ALLOW_SUPER_CALL)) == PARSER_CLASS_CONSTRUCTOR)
+ {
+ parser_emit_cbc_ext (context_p, CBC_EXT_RUN_CLASS_FIELD_INIT);
+ }
+#endif /* ENABLED (JERRY_ESNEXT) */
+
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
if (context_p->is_show_opcodes
&& (context_p->status_flags & PARSER_HAS_NON_STRICT_ARG))
@@ -2712,6 +2719,152 @@ parser_parse_arrow_function (parser_context_t *context_p, /**< context */
return compiled_code_p;
} /* parser_parse_arrow_function */
+/**
+ * Parse class fields
+ *
+ * @return compiled code
+ */
+ecma_compiled_code_t *
+parser_parse_class_fields (parser_context_t *context_p) /**< context */
+{
+ parser_saved_context_t saved_context;
+ ecma_compiled_code_t *compiled_code_p;
+
+ JERRY_ASSERT (context_p->token.type == LEXER_RIGHT_BRACE);
+ parser_save_context (context_p, &saved_context);
+ context_p->status_flags |= (PARSER_IS_FUNCTION
+ | PARSER_ALLOW_SUPER
+ | PARSER_INSIDE_CLASS_FIELD
+ | PARSER_ALLOW_NEW_TARGET);
+
+#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
+ if (context_p->is_show_opcodes)
+ {
+ JERRY_DEBUG_MSG ("\n--- Class fields parsing start ---\n\n");
+ }
+#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
+
+#if ENABLED (JERRY_DEBUGGER)
+ if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
+ {
+ jerry_debugger_send_parse_function (context_p->token.line, context_p->token.column);
+ }
+#endif /* ENABLED (JERRY_DEBUGGER) */
+
+ const uint8_t *source_end_p = context_p->source_end_p;
+ bool first_computed_class_field = true;
+ scanner_location_t end_location;
+ scanner_get_location (&end_location, context_p);
+
+ do
+ {
+ uint8_t class_field_type = context_p->stack_top_uint8;
+ parser_stack_pop_uint8 (context_p);
+
+ scanner_range_t range;
+
+ if (class_field_type & PARSER_CLASS_FIELD_INITIALIZED)
+ {
+ parser_stack_pop (context_p, &range, sizeof (scanner_range_t));
+ }
+ else if (class_field_type & PARSER_CLASS_FIELD_NORMAL)
+ {
+ parser_stack_pop (context_p, &range.start_location, sizeof (scanner_location_t));
+ }
+
+ uint16_t literal_index = 0;
+
+ if (class_field_type & PARSER_CLASS_FIELD_NORMAL)
+ {
+ scanner_set_location (context_p, &range.start_location);
+ context_p->source_end_p = source_end_p;
+ scanner_seek (context_p);
+
+ lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS);
+
+ literal_index = context_p->lit_object.index;
+
+ if (class_field_type & PARSER_CLASS_FIELD_INITIALIZED)
+ {
+ lexer_next_token (context_p);
+ JERRY_ASSERT (context_p->token.type == LEXER_ASSIGN);
+ }
+ }
+ else if (first_computed_class_field)
+ {
+ parser_emit_cbc (context_p, CBC_PUSH_NUMBER_0);
+ first_computed_class_field = false;
+ }
+
+ if (class_field_type & PARSER_CLASS_FIELD_INITIALIZED)
+ {
+ if (!(class_field_type & PARSER_CLASS_FIELD_NORMAL))
+ {
+ scanner_set_location (context_p, &range.start_location);
+ scanner_seek (context_p);
+ }
+
+ context_p->source_end_p = range.source_end_p;
+ lexer_next_token (context_p);
+ parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
+
+ if (context_p->token.type != LEXER_EOS)
+ {
+ parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
+ }
+ }
+ else
+ {
+ parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED);
+ }
+
+ if (class_field_type & PARSER_CLASS_FIELD_NORMAL)
+ {
+ parser_emit_cbc_literal (context_p, CBC_ASSIGN_PROP_THIS_LITERAL, literal_index);
+ }
+ else
+ {
+ parser_flush_cbc (context_p);
+
+ /* The next opcode pushes two more temporary values onto the stack */
+ if (context_p->stack_depth + 1 > context_p->stack_limit)
+ {
+ context_p->stack_limit = (uint16_t) (context_p->stack_depth + 1);
+ if (context_p->stack_limit > PARSER_MAXIMUM_STACK_LIMIT)
+ {
+ parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED);
+ }
+ }
+
+ parser_emit_cbc_ext (context_p, CBC_EXT_SET_NEXT_COMPUTED_FIELD);
+ }
+ }
+ while (context_p->stack_top_uint8 != PARSER_CLASS_FIELD_END);
+
+ if (!first_computed_class_field)
+ {
+ parser_emit_cbc (context_p, CBC_POP);
+ }
+
+ parser_stack_pop_uint8 (context_p);
+ parser_flush_cbc (context_p);
+ context_p->source_end_p = source_end_p;
+ scanner_set_location (context_p, &end_location);
+
+ compiled_code_p = parser_post_processing (context_p);
+
+#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
+ if (context_p->is_show_opcodes)
+ {
+ JERRY_DEBUG_MSG ("\n--- Class fields parsing end ---\n\n");
+ }
+#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
+
+ parser_restore_context (context_p, &saved_context);
+
+ return compiled_code_p;
+} /* parser_parse_class_fields */
+
/**
* Check whether the last emitted cbc opcode was an anonymous function declaration
*
diff --git a/jerry-core/parser/js/js-parser.h b/jerry-core/parser/js/js-parser.h
index 0f569e833..ad29469cd 100644
--- a/jerry-core/parser/js/js-parser.h
+++ b/jerry-core/parser/js/js-parser.h
@@ -142,9 +142,10 @@ typedef enum
PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS, /**< multiple class constructor */
PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR, /**< class constructor cannot be an accessor */
- PARSER_ERR_CLASS_CONSTRUCTOR_AS_GENERATOR, /**< class constructor cannot be a generator */
+ PARSER_ERR_INVALID_CLASS_CONSTRUCTOR, /**< class constructor cannot be a generator or async function */
PARSER_ERR_CLASS_STATIC_PROTOTYPE, /**< static method name 'prototype' is not allowed */
PARSER_ERR_UNEXPECTED_SUPER_KEYWORD, /**< unexpected super keyword */
+ PARSER_ERR_ARGUMENTS_IN_CLASS_FIELD, /**< arguments is not allowed in class fields */
PARSER_ERR_RIGHT_BRACE_EXPECTED, /**< right brace expected */
PARSER_ERR_OF_EXPECTED, /**< of keyword expected */
diff --git a/jerry-core/parser/js/js-scanner-internal.h b/jerry-core/parser/js/js-scanner-internal.h
index b9fffa099..ee7ca7014 100644
--- a/jerry-core/parser/js/js-scanner-internal.h
+++ b/jerry-core/parser/js/js-scanner-internal.h
@@ -45,7 +45,8 @@ typedef enum
SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS, /**< continue scanning function arguments */
SCAN_MODE_BINDING, /**< array or object binding */
SCAN_MODE_CLASS_DECLARATION, /**< scanning class declaration */
- SCAN_MODE_CLASS_METHOD, /**< scanning class method */
+ SCAN_MODE_CLASS_BODY, /**< scanning class body */
+ SCAN_MODE_CLASS_BODY_NO_SCAN, /**< scanning class body without calling lexer_scan_identifier */
#endif /* ENABLED (JERRY_ESNEXT) */
} scan_modes_t;
@@ -59,7 +60,7 @@ typedef enum
SCAN_STACK_BLOCK_STATEMENT, /**< block statement group */
SCAN_STACK_FUNCTION_STATEMENT, /**< function statement */
SCAN_STACK_FUNCTION_EXPRESSION, /**< function expression */
- SCAN_STACK_FUNCTION_PROPERTY, /**< function expression in an object literal or class */
+ SCAN_STACK_FUNCTION_PROPERTY, /**< function expression in an object literal */
#if ENABLED (JERRY_ESNEXT)
SCAN_STACK_FUNCTION_ARROW, /**< arrow function expression */
#endif /* ENABLED (JERRY_ESNEXT) */
@@ -113,6 +114,7 @@ typedef enum
SCAN_STACK_CLASS_STATEMENT, /**< class statement */
SCAN_STACK_CLASS_EXPRESSION, /**< class expression */
SCAN_STACK_CLASS_EXTENDS, /**< class extends expression */
+ SCAN_STACK_CLASS_FIELD_INITIALIZER, /**< class field initializer */
SCAN_STACK_FUNCTION_PARAMETERS, /**< function parameter initializer */
SCAN_STACK_FOR_START_PATTERN, /**< possible assignment pattern for "for" iterator */
SCAN_STACK_USE_ASYNC, /**< an "async" identifier is used */
@@ -387,6 +389,7 @@ void scanner_detect_eval_call (parser_context_t *context_p, scanner_context_t *s
#if ENABLED (JERRY_ESNEXT)
void scanner_push_class_declaration (parser_context_t *context_p, scanner_context_t *scanner_context_p,
uint8_t stack_mode);
+void scanner_push_class_field_initializer (parser_context_t *context_p, scanner_context_t *scanner_context_p);
void scanner_push_destructuring_pattern (parser_context_t *context_p, scanner_context_t *scanner_context_p,
uint8_t binding_type, bool is_nested);
void scanner_pop_binding_list (scanner_context_t *scanner_context_p);
diff --git a/jerry-core/parser/js/js-scanner-util.c b/jerry-core/parser/js/js-scanner-util.c
index 6ce91b5d1..0e03e5743 100644
--- a/jerry-core/parser/js/js-scanner-util.c
+++ b/jerry-core/parser/js/js-scanner-util.c
@@ -1494,6 +1494,21 @@ scanner_push_class_declaration (parser_context_t *context_p, /**< context */
lexer_next_token (context_p);
} /* scanner_push_class_declaration */
+/**
+ * Push the start of a class field initializer.
+ */
+void
+scanner_push_class_field_initializer (parser_context_t *context_p, /**< context */
+ scanner_context_t *scanner_context_p) /* scanner context */
+{
+ scanner_source_start_t source_start;
+ source_start.source_p = context_p->source_p;
+
+ parser_stack_push (context_p, &source_start, sizeof (scanner_source_start_t));
+ parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_FIELD_INITIALIZER);
+ scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
+} /* scanner_push_class_field_initializer */
+
/**
* Push the values required for destructuring assignment or binding parsing.
*/
@@ -1658,6 +1673,7 @@ scanner_cleanup (parser_context_t *context_p) /**< context */
case SCANNER_TYPE_CASE:
#if ENABLED (JERRY_ESNEXT)
case SCANNER_TYPE_INITIALIZER:
+ case SCANNER_TYPE_CLASS_FIELD_INITIALIZER_END:
#endif /* ENABLED (JERRY_ESNEXT) */
{
size = sizeof (scanner_location_info_t);
diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c
index 438a00bb9..bed7b0a81 100644
--- a/jerry-core/parser/js/js-scanner.c
+++ b/jerry-core/parser/js/js-scanner.c
@@ -430,6 +430,11 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
{
break;
}
+ case SCAN_STACK_CLASS_FIELD_INITIALIZER:
+ {
+ scanner_raise_error (context_p);
+ break;
+ }
case SCAN_STACK_FUNCTION_PARAMETERS:
{
scanner_context_p->mode = SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS;
@@ -962,7 +967,7 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
break;
}
- lexer_next_token (context_p);
+ lexer_scan_identifier (context_p);
parser_stack_pop_uint8 (context_p);
stack_top = (scan_stack_modes_t) context_p->stack_top_uint8;
@@ -970,11 +975,33 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
if (stack_top == SCAN_STACK_FUNCTION_PROPERTY)
{
scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
-
scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS;
return SCAN_KEEP_TOKEN;
}
+ if (stack_top == SCAN_STACK_EXPLICIT_CLASS_CONSTRUCTOR
+ || stack_top == SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR)
+ {
+ if (context_p->token.type == LEXER_LEFT_PAREN)
+ {
+ scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
+
+ parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
+ scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS;
+ return SCAN_KEEP_TOKEN;
+ }
+
+ if (context_p->token.type == LEXER_ASSIGN)
+ {
+ scanner_push_class_field_initializer (context_p, scanner_context_p);
+ return SCAN_NEXT_TOKEN;
+ }
+
+ scanner_context_p->mode = (context_p->token.type != LEXER_SEMICOLON ? SCAN_MODE_CLASS_BODY_NO_SCAN
+ : SCAN_MODE_CLASS_BODY);
+ return SCAN_KEEP_TOKEN;
+ }
+
JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL
|| stack_top == SCAN_STACK_OBJECT_LITERAL_WITH_SUPER);
@@ -1073,11 +1100,87 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
break;
}
- scanner_context_p->mode = SCAN_MODE_CLASS_METHOD;
+ scanner_context_p->mode = SCAN_MODE_CLASS_BODY;
parser_stack_pop_uint8 (context_p);
return SCAN_KEEP_TOKEN;
}
+ case SCAN_STACK_CLASS_FIELD_INITIALIZER:
+ {
+ scanner_source_start_t source_start;
+
+ parser_stack_pop_uint8 (context_p);
+ parser_stack_pop (context_p, &source_start, sizeof (scanner_source_start_t));
+
+ const uint8_t *source_p = NULL;
+
+ scanner_context_p->mode = SCAN_MODE_CLASS_BODY_NO_SCAN;
+
+ switch (type)
+ {
+ case LEXER_SEMICOLON:
+ {
+ source_p = context_p->source_p - 1;
+ scanner_context_p->mode = SCAN_MODE_CLASS_BODY;
+ break;
+ }
+ case LEXER_RIGHT_BRACE:
+ {
+ source_p = context_p->source_p - 1;
+ break;
+ }
+ default:
+ {
+ if (!(context_p->token.flags & LEXER_WAS_NEWLINE))
+ {
+ break;
+ }
+
+ if (type == LEXER_LEFT_SQUARE)
+ {
+ source_p = context_p->source_p - 1;
+ break;
+ }
+
+ if (type == LEXER_LITERAL)
+ {
+ if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL
+ || context_p->token.lit_location.type == LEXER_NUMBER_LITERAL)
+ {
+ source_p = context_p->token.lit_location.char_p;
+ }
+ else if (context_p->token.lit_location.type == LEXER_STRING_LITERAL)
+ {
+ source_p = context_p->token.lit_location.char_p - 1;
+ }
+ break;
+ }
+
+ if (type == context_p->token.keyword_type && type != LEXER_EOS)
+ {
+ /* Convert keyword to literal. */
+ source_p = context_p->token.lit_location.char_p;
+ context_p->token.type = LEXER_LITERAL;
+ }
+ break;
+ }
+ }
+
+ if (JERRY_UNLIKELY (source_p == NULL))
+ {
+ scanner_raise_error (context_p);
+ }
+
+ scanner_location_info_t *location_info_p;
+ location_info_p = (scanner_location_info_t *) scanner_insert_info (context_p,
+ source_start.source_p,
+ sizeof (scanner_location_info_t));
+ location_info_p->info.type = SCANNER_TYPE_CLASS_FIELD_INITIALIZER_END;
+ location_info_p->location.source_p = source_p;
+ location_info_p->location.line = context_p->token.line;
+ location_info_p->location.column = context_p->token.column;
+ return SCAN_KEEP_TOKEN;
+ }
case SCAN_STACK_FUNCTION_PARAMETERS:
{
parser_stack_pop_uint8 (context_p);
@@ -2027,7 +2130,7 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */
if (context_p->stack_top_uint8 == SCAN_STACK_EXPLICIT_CLASS_CONSTRUCTOR
|| context_p->stack_top_uint8 == SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR)
{
- scanner_context_p->mode = SCAN_MODE_CLASS_METHOD;
+ scanner_context_p->mode = SCAN_MODE_CLASS_BODY;
return SCAN_KEEP_TOKEN;
}
@@ -2337,6 +2440,9 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
/* This assignment must be here because of Apple compilers. */
context_p->u.scanner_context_p = &scanner_context;
+#if ENABLED (JERRY_ESNEXT)
+ context_p->global_status_flags |= ECMA_PARSE_INTERNAL_PRE_SCANNING;
+#endif /* ENABLED (JERRY_ESNEXT) */
parser_stack_init (context_p);
@@ -2437,18 +2543,20 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
scanner_raise_error (context_p);
}
- scanner_context.mode = SCAN_MODE_CLASS_METHOD;
+ scanner_context.mode = SCAN_MODE_CLASS_BODY;
/* FALLTHRU */
}
- case SCAN_MODE_CLASS_METHOD:
+ case SCAN_MODE_CLASS_BODY:
+ {
+ lexer_skip_empty_statements (context_p);
+ lexer_scan_identifier (context_p);
+ /* FALLTHRU */
+ }
+ case SCAN_MODE_CLASS_BODY_NO_SCAN:
{
JERRY_ASSERT (stack_top == SCAN_STACK_IMPLICIT_CLASS_CONSTRUCTOR
|| stack_top == SCAN_STACK_EXPLICIT_CLASS_CONSTRUCTOR);
- lexer_skip_empty_statements (context_p);
-
- lexer_scan_identifier (context_p);
-
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
scanner_source_start_t source_start;
@@ -2476,6 +2584,8 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
break;
}
+ bool identifier_found = false;
+
if (context_p->token.type == LEXER_LITERAL
&& LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type)
&& lexer_compare_literal_to_string (context_p, "constructor", 11))
@@ -2491,13 +2601,12 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
parser_stack_push_uint8 (context_p, SCAN_STACK_EXPLICIT_CLASS_CONSTRUCTOR);
}
}
-
- if (lexer_token_is_identifier (context_p, "static", 6))
+ else if (lexer_token_is_identifier (context_p, "static", 6))
{
lexer_scan_identifier (context_p);
+ identifier_found = true;
}
- parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS;
uint16_t literal_pool_flags = SCANNER_LITERAL_POOL_FUNCTION;
@@ -2506,9 +2615,11 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
|| lexer_token_is_identifier (context_p, "set", 3))
{
lexer_scan_identifier (context_p);
+ identifier_found = true;
if (context_p->token.type == LEXER_LEFT_PAREN)
{
+ parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION);
continue;
}
@@ -2516,19 +2627,24 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
else if (lexer_token_is_identifier (context_p, "async", 5))
{
lexer_scan_identifier (context_p);
+ identifier_found = true;
- if (context_p->token.type == LEXER_LEFT_PAREN)
+ if (!(context_p->token.flags & LEXER_WAS_NEWLINE))
{
- scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION);
- continue;
- }
+ if (context_p->token.type == LEXER_LEFT_PAREN)
+ {
+ parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
+ scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION);
+ continue;
+ }
- literal_pool_flags |= SCANNER_LITERAL_POOL_ASYNC;
+ literal_pool_flags |= SCANNER_LITERAL_POOL_ASYNC;
- if (context_p->token.type == LEXER_MULTIPLY)
- {
- lexer_scan_identifier (context_p);
- literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR;
+ if (context_p->token.type == LEXER_MULTIPLY)
+ {
+ lexer_scan_identifier (context_p);
+ literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR;
+ }
}
}
else if (context_p->token.type == LEXER_MULTIPLY)
@@ -2539,23 +2655,63 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
if (context_p->token.type == LEXER_LEFT_SQUARE)
{
+ if (literal_pool_flags != SCANNER_LITERAL_POOL_FUNCTION)
+ {
+ parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
+ }
+
parser_stack_push_uint8 (context_p, SCANNER_FROM_LITERAL_POOL_TO_COMPUTED (literal_pool_flags));
scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
- if (context_p->token.type != LEXER_LITERAL)
+ if (context_p->token.type == LEXER_LITERAL)
+ {
+ lexer_scan_identifier (context_p);
+ identifier_found = true;
+ }
+
+ if (!identifier_found)
{
scanner_raise_error (context_p);
}
- if (literal_pool_flags & SCANNER_LITERAL_POOL_GENERATOR)
+ if (context_p->token.type == LEXER_LEFT_PAREN)
{
- context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION;
+ if (literal_pool_flags & SCANNER_LITERAL_POOL_GENERATOR)
+ {
+ context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION;
+ }
+
+ parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
+ scanner_push_literal_pool (context_p, &scanner_context, literal_pool_flags);
+ continue;
}
- scanner_push_literal_pool (context_p, &scanner_context, literal_pool_flags);
- lexer_next_token (context_p);
+ if (literal_pool_flags != SCANNER_LITERAL_POOL_FUNCTION)
+ {
+ scanner_raise_error (context_p);
+ }
+
+ if (context_p->token.type == LEXER_ASSIGN)
+ {
+ scanner_push_class_field_initializer (context_p, &scanner_context);
+ break;
+ }
+
+ if (context_p->token.type == LEXER_SEMICOLON)
+ {
+ scanner_context.mode = SCAN_MODE_CLASS_BODY;
+ continue;
+ }
+
+ if (context_p->token.type != LEXER_RIGHT_BRACE
+ && !(context_p->token.flags & LEXER_WAS_NEWLINE))
+ {
+ scanner_raise_error (context_p);
+ }
+
+ scanner_context.mode = SCAN_MODE_CLASS_BODY_NO_SCAN;
continue;
}
#endif /* ENABLED (JERRY_ESNEXT) */
@@ -3299,6 +3455,9 @@ scan_completed:
PARSER_TRY_END
context_p->status_flags = scanner_context.context_status_flags;
+#if ENABLED (JERRY_ESNEXT)
+ context_p->global_status_flags &= (uint32_t) ~ECMA_PARSE_INTERNAL_PRE_SCANNING;
+#endif /* ENABLED (JERRY_ESNEXT) */
scanner_reverse_info_list (context_p);
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
@@ -3549,6 +3708,12 @@ scan_completed:
print_location = false;
break;
}
+ case SCANNER_TYPE_CLASS_FIELD_INITIALIZER_END:
+ {
+ name_p = "SCANNER_TYPE_CLASS_FIELD_INITIALIZER_END";
+ print_location = true;
+ break;
+ }
case SCANNER_TYPE_LET_EXPRESSION:
{
JERRY_DEBUG_MSG (" LET_EXPRESSION: source:%d\n",
diff --git a/jerry-core/parser/js/js-scanner.h b/jerry-core/parser/js/js-scanner.h
index fb24ac807..0ed07975b 100644
--- a/jerry-core/parser/js/js-scanner.h
+++ b/jerry-core/parser/js/js-scanner.h
@@ -48,6 +48,7 @@ typedef enum
SCANNER_TYPE_INITIALIZER, /**< destructuring binding or assignment pattern with initializer */
SCANNER_TYPE_FOR_PATTERN, /**< assignment pattern for for-in or for-of interators */
SCANNER_TYPE_CLASS_CONSTRUCTOR, /**< class constructor */
+ SCANNER_TYPE_CLASS_FIELD_INITIALIZER_END, /**< class field initializer end */
SCANNER_TYPE_LET_EXPRESSION, /**< let expression */
SCANNER_TYPE_ERR_REDECLARED, /**< syntax error: a variable is redeclared */
SCANNER_TYPE_ERR_ASYNC_FUNCTION, /**< an invalid async function follows */
@@ -65,6 +66,15 @@ typedef struct
parser_line_counter_t column; /**< token start column */
} scanner_location_t;
+/**
+ * Source code range with its start and end position.
+ */
+typedef struct
+{
+ const uint8_t *source_end_p; /**< end position */
+ scanner_location_t start_location; /**< start location */
+} scanner_range_t;
+
/**
* Scanner info blocks which provides information for the parser.
*/
diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c
index 6a56d468e..656f4fdf9 100644
--- a/jerry-core/vm/opcodes.c
+++ b/jerry-core/vm/opcodes.c
@@ -959,6 +959,105 @@ opfunc_async_create_and_await (vm_frame_ctx_t *frame_ctx_p, /**< frame context *
return result;
} /* opfunc_async_create_and_await */
+/**
+ * Initialize implicit class fields.
+ *
+ * @return ECMA_VALUE_ERROR - initialization fails
+ * ECMA_VALUE_UNDEFINED - otherwise
+ */
+ecma_value_t
+ecma_op_init_class_fields (ecma_value_t function_object, /**< the function itself */
+ ecma_value_t this_val) /**< this_arg of the function */
+{
+ JERRY_ASSERT (ecma_is_value_object (function_object));
+ JERRY_ASSERT (ecma_is_value_object (this_val));
+
+ ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_INIT);
+ ecma_object_t *function_object_p = ecma_get_object_from_value (function_object);
+
+ ecma_property_t *property_p = ecma_find_named_property (function_object_p, name_p);
+
+ if (property_p == NULL)
+ {
+ return ECMA_VALUE_UNDEFINED;
+ }
+
+ ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
+ ecma_value_t *computed_class_fields_p = NULL;
+
+ name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED);
+ ecma_property_t *class_field_property_p = ecma_find_named_property (function_object_p, name_p);
+
+ if (class_field_property_p != NULL)
+ {
+ ecma_property_value_t *class_field_property_value_p = ECMA_PROPERTY_VALUE_PTR (class_field_property_p);
+ computed_class_fields_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_value_t, class_field_property_value_p->value);
+ }
+
+ JERRY_ASSERT (ecma_op_is_callable (property_value_p->value));
+
+ ecma_extended_object_t *ext_function_p;
+ ext_function_p = (ecma_extended_object_t *) ecma_get_object_from_value (property_value_p->value);
+
+ ecma_object_t *scope_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t,
+ ext_function_p->u.function.scope_cp);
+ const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_function_p);
+
+ ecma_value_t *old_computed_class_fields_p = JERRY_CONTEXT (computed_class_fields_p);
+ JERRY_CONTEXT (computed_class_fields_p) = computed_class_fields_p;
+
+ ecma_value_t result = vm_run (bytecode_data_p, this_val, scope_p, NULL, 0);
+
+ JERRY_CONTEXT (computed_class_fields_p) = old_computed_class_fields_p;
+
+ JERRY_ASSERT (ECMA_IS_VALUE_ERROR (result) || result == ECMA_VALUE_UNDEFINED);
+ return result;
+} /* ecma_op_init_class_fields */
+
+ecma_value_t
+ecma_op_add_computed_field (ecma_value_t class_object, /**< class object */
+ ecma_value_t name) /**< name of the property */
+{
+ ecma_string_t *prop_name_p = ecma_op_to_property_key (name);
+
+ if (JERRY_UNLIKELY (prop_name_p == NULL))
+ {
+ return ECMA_VALUE_ERROR;
+ }
+
+ if (ecma_prop_name_is_symbol (prop_name_p))
+ {
+ name = ecma_make_symbol_value (prop_name_p);
+ }
+ else
+ {
+ name = ecma_make_string_value (prop_name_p);
+ }
+
+ ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED);
+ ecma_object_t *class_object_p = ecma_get_object_from_value (class_object);
+
+ ecma_property_t *property_p = ecma_find_named_property (class_object_p, name_p);
+ ecma_value_t *compact_collection_p;
+ ecma_property_value_t *property_value_p;
+
+ if (property_p == NULL)
+ {
+ property_value_p = ecma_create_named_data_property (class_object_p, name_p, ECMA_PROPERTY_FIXED, &property_p);
+ ECMA_CONVERT_DATA_PROPERTY_TO_INTERNAL_PROPERTY (property_p);
+ compact_collection_p = ecma_new_compact_collection ();
+ }
+ else
+ {
+ property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
+ compact_collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_value_t, property_value_p->value);
+ }
+
+ compact_collection_p = ecma_compact_collection_push_back (compact_collection_p, name);
+ ECMA_SET_INTERNAL_VALUE_POINTER (property_value_p->value, compact_collection_p);
+ return ECMA_VALUE_UNDEFINED;
+} /* ecma_op_add_computed_field */
+
/**
* Implicit class constructor handler when the classHeritage is not present.
*
@@ -973,14 +1072,14 @@ ecma_op_implicit_constructor_handler_cb (const ecma_value_t function_obj, /**< t
const ecma_value_t args_p[], /**< argument list */
const uint32_t args_count) /**< argument number */
{
- JERRY_UNUSED_4 (function_obj, this_val, args_p, args_count);
+ JERRY_UNUSED_2 (args_p, args_count);
if (JERRY_CONTEXT (current_new_target) == NULL)
{
return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'."));
}
- return ECMA_VALUE_UNDEFINED;
+ return ecma_op_init_class_fields (function_obj, this_val);
} /* ecma_op_implicit_constructor_handler_cb */
/**
@@ -997,7 +1096,7 @@ ecma_op_implicit_constructor_handler_heritage_cb (const ecma_value_t function_ob
const ecma_value_t args_p[], /**< argument list */
const uint32_t args_count) /**< argument number */
{
- JERRY_UNUSED_4 (function_obj, this_val, args_p, args_count);
+ JERRY_UNUSED (this_val);
if (JERRY_CONTEXT (current_new_target) == NULL)
{
@@ -1028,10 +1127,21 @@ ecma_op_implicit_constructor_handler_heritage_cb (const ecma_value_t function_ob
ecma_free_value (result);
result = ECMA_VALUE_ERROR;
}
- else if (ecma_is_value_object (proto_value))
+ else
{
- ECMA_SET_POINTER (ecma_get_object_from_value (result)->u2.prototype_cp,
- ecma_get_object_from_value (proto_value));
+ if (ecma_is_value_object (proto_value))
+ {
+ ECMA_SET_POINTER (ecma_get_object_from_value (result)->u2.prototype_cp,
+ ecma_get_object_from_value (proto_value));
+ }
+
+ ecma_value_t fields_value = ecma_op_init_class_fields (function_obj, result);
+
+ if (ECMA_IS_VALUE_ERROR (fields_value))
+ {
+ ecma_free_value (result);
+ result = ECMA_VALUE_ERROR;
+ }
}
ecma_free_value (proto_value);
}
@@ -1302,10 +1412,9 @@ opfunc_set_class_attributes (ecma_object_t *obj_p, /**< object */
}
else
{
- JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_SPECIAL);
-
- JERRY_ASSERT (property == ECMA_PROPERTY_TYPE_HASHMAP
- || property == ECMA_PROPERTY_TYPE_DELETED);
+ JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_SPECIAL
+ || (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_INTERNAL
+ && property_pair_p->names_cp[index] == LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED));
}
}
diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h
index 15c2d8540..068aa97df 100644
--- a/jerry-core/vm/opcodes.h
+++ b/jerry-core/vm/opcodes.h
@@ -146,6 +146,12 @@ opfunc_async_generator_yield (ecma_extended_object_t *async_generator_object_p,
ecma_value_t
opfunc_async_create_and_await (vm_frame_ctx_t *frame_ctx_p, ecma_value_t value, uint16_t extra_flags);
+ecma_value_t
+ecma_op_init_class_fields (ecma_value_t function_object, ecma_value_t this_val);
+
+ecma_value_t
+ecma_op_add_computed_field (ecma_value_t class_object, ecma_value_t name);
+
ecma_value_t
opfunc_create_implicit_class_constructor (uint8_t opcode);
diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c
index 2499a574e..e02e816b9 100644
--- a/jerry-core/vm/vm.c
+++ b/jerry-core/vm/vm.c
@@ -610,6 +610,18 @@ vm_super_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
ecma_collection_destroy (collection_p);
}
+ if (ecma_is_value_object (completion_value))
+ {
+ ecma_value_t current_function = ecma_make_object_value (JERRY_CONTEXT (current_function_obj_p));
+ ecma_value_t fields_value = ecma_op_init_class_fields (current_function, completion_value);
+
+ if (ECMA_IS_VALUE_ERROR (fields_value))
+ {
+ ecma_free_value (completion_value);
+ completion_value = ECMA_VALUE_ERROR;
+ }
+ }
+
ecma_free_value (func_value);
if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (completion_value)))
@@ -1787,6 +1799,16 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
}
goto free_left_value;
}
+ case VM_OC_ADD_COMPUTED_FIELD:
+ {
+ result = ecma_op_add_computed_field (stack_top_p[-2], left_value);
+
+ if (ECMA_IS_VALUE_ERROR (result))
+ {
+ goto error;
+ }
+ goto free_left_value;
+ }
case VM_OC_COPY_DATA_PROPERTIES:
{
result = *(--stack_top_p);
@@ -1991,6 +2013,56 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
opfunc_finalize_class (frame_ctx_p, &stack_top_p, left_value);
goto free_left_value;
}
+ case VM_OC_SET_CLASS_FIELD_INIT:
+ {
+ ecma_string_t *property_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_INIT);
+ ecma_object_t *object_p = ecma_get_object_from_value (stack_top_p[-2]);
+
+ ecma_property_value_t *property_value_p = ecma_create_named_data_property (object_p,
+ property_name_p,
+ ECMA_PROPERTY_FIXED,
+ NULL);
+ property_value_p->value = left_value;
+
+ property_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED);
+ ecma_property_t *property_p = ecma_find_named_property (object_p, property_name_p);
+
+ if (property_p != NULL)
+ {
+ property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
+ ecma_value_t *compact_collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_value_t,
+ property_value_p->value);
+ compact_collection_p = ecma_compact_collection_shrink (compact_collection_p);
+ ECMA_SET_INTERNAL_VALUE_POINTER (property_value_p->value, compact_collection_p);
+ }
+
+ goto free_left_value;
+ }
+ case VM_OC_RUN_CLASS_FIELD_INIT:
+ {
+ result = ecma_op_init_class_fields (ecma_make_object_value (JERRY_CONTEXT (current_function_obj_p)),
+ frame_ctx_p->this_binding);
+
+ if (ECMA_IS_VALUE_ERROR (result))
+ {
+ goto error;
+ }
+ continue;
+ }
+ case VM_OC_SET_NEXT_COMPUTED_FIELD:
+ {
+ ecma_integer_value_t next_index = ecma_get_integer_from_value (stack_top_p[-2]) + 1;
+ stack_top_p[-2] = ecma_make_integer_value (next_index);
+ stack_top_p++;
+
+ ecma_value_t *computed_class_fields_p = JERRY_CONTEXT (computed_class_fields_p);
+ JERRY_ASSERT ((ecma_value_t) next_index < ECMA_COMPACT_COLLECTION_GET_SIZE (computed_class_fields_p));
+
+ result = stack_top_p[-2];
+ stack_top_p[-1] = ecma_copy_value (computed_class_fields_p[next_index]);
+ stack_top_p[-2] = ecma_copy_value (frame_ctx_p->this_binding);
+ break;
+ }
case VM_OC_PUSH_SUPER_CONSTRUCTOR:
{
result = ecma_op_function_get_super_constructor (JERRY_CONTEXT (current_function_obj_p));
diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h
index 5ad9e1b83..998dbafe8 100644
--- a/jerry-core/vm/vm.h
+++ b/jerry-core/vm/vm.h
@@ -260,6 +260,9 @@ typedef enum
VM_OC_PUSH_IMPLICIT_CTOR, /**< create implicit class constructor */
VM_OC_INIT_CLASS, /**< initialize class */
VM_OC_FINALIZE_CLASS, /**< finalize class */
+ VM_OC_SET_CLASS_FIELD_INIT, /**< store the class field initializer function */
+ VM_OC_RUN_CLASS_FIELD_INIT, /**< run the class field initializer function */
+ VM_OC_SET_NEXT_COMPUTED_FIELD, /**< set the next computed field of a class */
VM_OC_PUSH_SUPER_CONSTRUCTOR, /**< getSuperConstructor operation */
VM_OC_RESOLVE_LEXICAL_THIS, /**< resolve this_binding from from the lexical environment */
VM_OC_SUPER_REFERENCE, /**< push super reference */
@@ -289,7 +292,8 @@ typedef enum
VM_OC_PUSH_NEW_TARGET, /**< push new.target onto the stack */
VM_OC_REQUIRE_OBJECT_COERCIBLE,/**< RequireObjectCoercible opretaion */
VM_OC_ASSIGN_SUPER, /**< assign super reference */
- VM_OC_SET__PROTO__, /**< set prototpe when __proto__: form is used */
+ VM_OC_SET__PROTO__, /**< set prototype when __proto__: form is used */
+ VM_OC_ADD_COMPUTED_FIELD, /**< add computed field name */
#endif /* ENABLED (JERRY_ESNEXT) */
VM_OC_NONE, /**< a special opcode for unsupported byte codes */
} vm_oc_types;
@@ -337,6 +341,9 @@ typedef enum
VM_OC_PUSH_IMPLICIT_CTOR = VM_OC_NONE, /**< create implicit class constructor */
VM_OC_INIT_CLASS = VM_OC_NONE, /**< initialize class */
VM_OC_FINALIZE_CLASS = VM_OC_NONE, /**< finalize class */
+ VM_OC_SET_CLASS_FIELD_INIT = VM_OC_NONE, /**< store the class field initializer function */
+ VM_OC_RUN_CLASS_FIELD_INIT = VM_OC_NONE, /**< run the class field initializer function */
+ VM_OC_SET_NEXT_COMPUTED_FIELD = VM_OC_NONE, /**< set the next computed field of a class */
VM_OC_PUSH_SUPER_CONSTRUCTOR = VM_OC_NONE, /**< getSuperConstructor operation */
VM_OC_RESOLVE_LEXICAL_THIS = VM_OC_NONE, /**< resolve this_binding from from the lexical environment */
VM_OC_SUPER_REFERENCE = VM_OC_NONE, /**< push super reference */
@@ -366,7 +373,8 @@ typedef enum
VM_OC_PUSH_NEW_TARGET = VM_OC_NONE, /**< push new.target onto the stack */
VM_OC_REQUIRE_OBJECT_COERCIBLE = VM_OC_NONE,/**< RequireObjectCoercible opretaion */
VM_OC_ASSIGN_SUPER = VM_OC_NONE, /**< assign super reference */
- VM_OC_SET__PROTO__ = VM_OC_NONE, /**< set prototpe when __proto__: form is used */
+ VM_OC_SET__PROTO__ = VM_OC_NONE, /**< set prototype when __proto__: form is used */
+ VM_OC_ADD_COMPUTED_FIELD = VM_OC_NONE, /**< add computed field name */
#endif /* !ENABLED (JERRY_ESNEXT) */
VM_OC_UNUSED = VM_OC_NONE /**< placeholder if the list is empty */
diff --git a/tests/jerry/es.next/class-fields1.js b/tests/jerry/es.next/class-fields1.js
new file mode 100644
index 000000000..2b0817788
--- /dev/null
+++ b/tests/jerry/es.next/class-fields1.js
@@ -0,0 +1,182 @@
+// 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.
+
+function check_syntax_error(code)
+{
+ try {
+ eval(code)
+ assert(false)
+ } catch (e) {
+ assert(e instanceof SyntaxError)
+ }
+}
+
+function check_property(obj, name, value)
+{
+ property = Object.getOwnPropertyDescriptor(obj, name)
+ assert(typeof property === "object")
+ assert(property.value === value)
+}
+
+check_syntax_error("class C { get a = 5 }");
+check_syntax_error("class C { id1 id2 }");
+check_syntax_error("class C { a = 5,6 }");
+check_syntax_error("class C { set\na = 6 }");
+check_syntax_error("class C { constructor }");
+check_syntax_error("class C { static constructor }");
+check_syntax_error("class C { constructor = 1 }");
+check_syntax_error("class C { static constructor = 1 }");
+check_syntax_error("class C { f = arguments }");
+check_syntax_error("class C { static f = a\\u0072guments }");
+check_syntax_error("class C { f = () => arguments }");
+check_syntax_error("class C { f = arguments => 1 }");
+check_syntax_error("class C { f = ([arguments]) => 1 }");
+check_syntax_error("new class { f = eval('arguments') }");
+check_syntax_error("new class { f = eval('arguments => 1') }");
+
+var res = 10
+var counter = 0
+
+function f1() {
+ counter++
+ return 5
+}
+
+var C1 = class {
+ get = "a" + f1()
+ static; set; a = () => Math.cos(0)
+ v\u0061r
+ f\u006fr = () => this
+ arguments = this
+}
+
+res = new C1
+check_property(res, "get", "a5")
+check_property(res, "static", undefined)
+check_property(res, "set", undefined)
+assert(res.a() === 1)
+check_property(res, "var", undefined)
+assert(res.for() === res)
+assert(res.arguments === res)
+
+class C2 {
+ constructor(a = this.x, b = this.y) {
+ assert(a === undefined)
+ assert(b === undefined)
+ check_property(this, 'x', 11)
+ check_property(this, 'y', "ab")
+ }
+ x = 5 + 6
+ y = "a" + 'b'
+}
+
+res = new C2
+
+class C3 {
+ constructor() {
+ assert(this.x === 1)
+ return { z:"zz" }
+ }
+ x = 1
+}
+
+class C4 extends C3 {
+ constructor() {
+ super()
+ assert(Object.getOwnPropertyDescriptor(this, "x") === undefined)
+ check_property(this, "y", 2)
+ check_property(this, "z", "zz")
+ }
+ y = 2
+}
+new C4
+
+var o = {}
+class C5 extends C3 {
+ 'pr op' = o
+ 3 = true
+}
+res = new C5
+assert(Object.getOwnPropertyDescriptor(res, "x") === undefined)
+check_property(res, "pr op", o)
+check_property(res, "3", true)
+check_property(res, "z", "zz")
+
+class C6 {
+ a= () => this
+ b= this
+}
+
+class C7 extends C6 {
+ c= () => this
+ d= this
+}
+
+count = 0
+class C8 extends C7 {
+ constructor() {
+ count++
+ super()
+ }
+
+ e= () => this
+ f= this
+}
+
+var res = new C8
+assert(res.a() === res)
+assert(res.b === res)
+assert(res.c() === res)
+assert(res.d === res)
+assert(res.e() === res)
+assert(res.f === res)
+
+count = 0
+class C9 {
+ a=assert(++count === 5)
+ a=assert(++count === 6)
+ a=assert(++count === 7)
+ a=assert(++count === 8)
+ static a=assert(++count === 1)
+ static a=assert(++count === 2)
+ static a=assert(++count === 3)
+ static a=assert(++count === 4)
+}
+
+assert(count === 4)
+new C9
+assert(count === 8)
+
+count = 0
+class C10 {
+ [(assert(++count == 1), "aa")] = assert(++count == 5);
+ [(assert(++count == 2), "bb")] = assert(++count == 6);
+ cc = assert(++count == 7);
+ [(assert(++count == 3), "aa")] = assert(++count == 8);
+ [(assert(++count == 4), "bb")] = assert(++count == 9);
+}
+
+assert(count == 4)
+assert(Reflect.ownKeys(new C10).toString() === "aa,bb,cc");
+assert(count == 9)
+
+res = "p"
+class C11 {
+ p1 = assert(Reflect.ownKeys(this).toString() === "");
+ [res + 2] = assert(Reflect.ownKeys(this).toString() === "p1");
+ [res + 1] = assert(Reflect.ownKeys(this).toString() === "p1,p2");
+ p3 = assert(Reflect.ownKeys(this).toString() === "p1,p2");
+ [res + 4] = assert(Reflect.ownKeys(this).toString() === "p1,p2,p3");
+}
+new C11
diff --git a/tests/jerry/es.next/class-fields2.js b/tests/jerry/es.next/class-fields2.js
new file mode 100644
index 000000000..626fc55e0
--- /dev/null
+++ b/tests/jerry/es.next/class-fields2.js
@@ -0,0 +1,139 @@
+// 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 count = 0
+class C1 {
+ error = assert(++count === 1)
+ error = function() { throw 40.5 }()
+}
+
+try {
+ new C1
+ assert(false)
+} catch(e) {
+ assert(e === 40.5)
+ assert(count === 1)
+}
+
+count = 0
+class C2 {
+ constructor(a = assert(++count === 1)) {}
+ error = function() { throw "Err" }()
+ error = assert(false)
+}
+
+try {
+ new C2
+ assert(false)
+} catch(e) {
+ assert(e === "Err")
+ assert(count === 1)
+}
+
+count = 0
+var o = {}
+
+class C3 extends class {
+ error = function() { throw o }()
+} {
+ constructor() {
+ assert(++count === 1)
+ super()
+ assert(false)
+ }
+}
+
+try {
+ new C3
+ assert(false)
+} catch (e) {
+ assert(e === o)
+ assert(count === 1)
+}
+
+count = 0
+class C4 {
+ constructor() {
+ assert(++count === 2)
+ }
+ a = assert(++count === 1)
+}
+
+class C5 extends C4 {
+ ok = assert(++count === 3)
+ error = function() { assert(++count === 4); throw "Except" }()
+ never = assert(false)
+}
+
+try {
+ new C5
+ assert(false)
+} catch (e) {
+ assert(e === "Except")
+ assert(count === 4)
+}
+
+count = 0
+o = []
+class C6 {
+ a = assert(++count === 2)
+}
+
+class C7 extends C6 {
+ constructor() {
+ assert(++count === 1)
+ eval('super()')
+ assert(false)
+ }
+ ok = assert(++count === 3)
+ error = function() { assert(++count === 4); throw o }()
+ never = assert(false)
+}
+
+try {
+ new C7
+ assert(false)
+} catch (e) {
+ assert(e === o)
+ assert(count === 4)
+}
+
+var res
+class C8 {
+ /* Create a non-configurable accessor */
+ a = (res = this, Object.defineProperty(this, "b", { get() {} }));
+ b = 6
+}
+
+try {
+ new C8
+ assert(false)
+} catch(e) {
+ assert(e instanceof TypeError)
+ assert(Reflect.ownKeys(res).toString() === "b,a")
+}
+
+class C9 {
+ ["p" + 1]
+ ["p" + 2] = (res = this, Object.freeze(this));
+ p3
+}
+
+try {
+ new C9
+ assert(false)
+} catch(e) {
+ assert(e instanceof TypeError)
+ assert(Reflect.ownKeys(res).toString() === "p1")
+}
diff --git a/tests/jerry/es.next/class-fields3.js b/tests/jerry/es.next/class-fields3.js
new file mode 100644
index 000000000..29c9909a5
--- /dev/null
+++ b/tests/jerry/es.next/class-fields3.js
@@ -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.
+
+function check_property(obj, name, value)
+{
+ property = Object.getOwnPropertyDescriptor(obj, name)
+ assert(typeof property === "object")
+ assert(property.value === value)
+}
+
+var o = {}
+var name = "Pro"
+var res = 0
+var counter = 0
+
+function f1() {
+ counter++
+}
+
+class C1 {
+ static
+ v\u0061r
+ static Prop =
+ res
+ =
+ "msg"
+ static
+ Prop
+ =
+ f1()
+ static [name + "p"] = (f1(), o)
+ static 22 = 3 * 4 ;static 23 = 5 + 6
+ static 'a b'
+}
+
+check_property(C1, "var", undefined)
+check_property(C1, "Prop", o)
+check_property(C1, 22, 12)
+check_property(C1, 23, 11)
+check_property(C1, "a b", undefined)
+assert(res === "msg")
+assert(counter === 2)
diff --git a/tests/jerry/es.next/class-with.js b/tests/jerry/es.next/class-with.js
new file mode 100644
index 000000000..a271bf034
--- /dev/null
+++ b/tests/jerry/es.next/class-with.js
@@ -0,0 +1,31 @@
+/* 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 called = false
+var obj = { f() { assert(this === obj); called = true } }
+
+function f() {
+ assert(false)
+}
+
+with (obj) {
+ new class {
+ constructor() {
+ f()
+ }
+ }
+}
+
+assert(called)
diff --git a/tests/jerry/es.next/regression-test-issue-4055.js b/tests/jerry/es.next/regression-test-issue-4055.js
deleted file mode 100644
index 08c1631ba..000000000
--- a/tests/jerry/es.next/regression-test-issue-4055.js
+++ /dev/null
@@ -1,20 +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.
-
-try {
- eval("class cla { static }");
- assert(false);
-} catch (e) {
- assert(e instanceof SyntaxError);
-}
diff --git a/tests/test262-esnext-excludelist.xml b/tests/test262-esnext-excludelist.xml
index 79c70b116..f94d46b07 100644
--- a/tests/test262-esnext-excludelist.xml
+++ b/tests/test262-esnext-excludelist.xml
@@ -3238,7 +3238,6 @@
-
@@ -4204,7 +4203,6 @@
-
@@ -5784,17 +5782,11 @@
-
-
-
-
-
-
@@ -5823,18 +5815,11 @@
-
-
-
-
-
-
-
@@ -5863,18 +5848,11 @@
-
-
-
-
-
-
-
@@ -5903,18 +5881,11 @@
-
-
-
-
-
-
-
@@ -5943,18 +5914,11 @@
-
-
-
-
-
-
-
@@ -5983,18 +5947,11 @@
-
-
-
-
-
-
-
@@ -6023,7 +5980,6 @@
-
@@ -6158,33 +6114,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -6194,23 +6127,12 @@
-
-
-
-
-
-
-
-
-
-
-
@@ -6239,18 +6161,11 @@
-
-
-
-
-
-
-
@@ -6279,18 +6194,11 @@
-
-
-
-
-
-
-
@@ -6319,18 +6227,11 @@
-
-
-
-
-
-
-
@@ -6359,18 +6260,11 @@
-
-
-
-
-
-
-
@@ -6399,7 +6293,6 @@
-
@@ -6500,19 +6393,11 @@
-
-
-
-
-
-
-
-
@@ -6541,18 +6426,11 @@
-
-
-
-
-
-
-
@@ -6581,18 +6459,11 @@
-
-
-
-
-
-
-
@@ -6621,18 +6492,11 @@
-
-
-
-
-
-
-
@@ -6661,18 +6525,11 @@
-
-
-
-
-
-
-
@@ -6701,14 +6558,8 @@
-
-
-
-
-
-
@@ -6727,11 +6578,6 @@
-
-
-
-
-
@@ -6743,17 +6589,11 @@
-
-
-
-
-
-
@@ -6782,7 +6622,6 @@
-
@@ -6822,7 +6661,6 @@
-
@@ -7555,18 +7393,11 @@
-
-
-
-
-
-
-
@@ -7595,18 +7426,11 @@
-
-
-
-
-
-
-
@@ -7635,18 +7459,11 @@
-
-
-
-
-
-
-
@@ -7675,18 +7492,11 @@
-
-
-
-
-
-
-
@@ -7715,18 +7525,11 @@
-
-
-
-
-
-
-
@@ -7755,18 +7558,11 @@
-
-
-
-
-
-
-
@@ -7795,7 +7591,6 @@
-
@@ -7926,42 +7721,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -7971,23 +7734,12 @@
-
-
-
-
-
-
-
-
-
-
-
@@ -8016,18 +7768,11 @@
-
-
-
-
-
-
-
@@ -8056,18 +7801,11 @@
-
-
-
-
-
-
-
@@ -8096,18 +7834,11 @@
-
-
-
-
-
-
-
@@ -8136,18 +7867,11 @@
-
-
-
-
-
-
-
@@ -8176,7 +7900,6 @@
-
@@ -8322,7 +8045,6 @@
-
@@ -8332,21 +8054,12 @@
-
-
-
-
-
-
-
-
-
@@ -8375,18 +8088,11 @@
-
-
-
-
-
-
-
@@ -8415,18 +8121,11 @@
-
-
-
-
-
-
-
@@ -8455,18 +8154,11 @@
-
-
-
-
-
-
-
@@ -8495,18 +8187,11 @@
-
-
-
-
-
-
-
@@ -8535,23 +8220,15 @@
-
-
-
-
-
-
-
-
@@ -8569,12 +8246,6 @@
-
-
-
-
-
-
@@ -8586,17 +8257,11 @@
-
-
-
-
-
-
@@ -8625,8 +8290,6 @@
-
-