Skip to content

Commit 53b61c1

Browse files
authored
Implement ECMAScript 2022 class static block (#4841)
Co-authored-by: Martin Negyokru [email protected] JerryScript-DCO-1.0-Signed-off-by: Adam Szilagyi [email protected]
1 parent c51b268 commit 53b61c1

15 files changed

+381
-46
lines changed

jerry-core/parser/js/byte-code.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ JERRY_STATIC_ASSERT (offsetof (cbc_uint8_arguments_t, script_value) == offsetof
2828
* whenever new bytecodes are introduced or existing ones have been deleted.
2929
*/
3030
JERRY_STATIC_ASSERT (CBC_END == 238, number_of_cbc_opcodes_changed);
31-
JERRY_STATIC_ASSERT (CBC_EXT_END == 166, number_of_cbc_ext_opcodes_changed);
31+
JERRY_STATIC_ASSERT (CBC_EXT_END == 167, number_of_cbc_ext_opcodes_changed);
3232

3333
#if JERRY_PARSER || JERRY_PARSER_DUMP_BYTE_CODE
3434

jerry-core/parser/js/byte-code.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,10 @@
581581
VM_OC_PUSH_STATIC_FIELD_FUNC | VM_OC_GET_LITERAL) \
582582
CBC_OPCODE (CBC_EXT_ADD_COMPUTED_FIELD, CBC_NO_FLAG, -1, VM_OC_ADD_COMPUTED_FIELD | VM_OC_GET_STACK) \
583583
CBC_OPCODE (CBC_EXT_ADD_STATIC_COMPUTED_FIELD, CBC_NO_FLAG, -1, VM_OC_ADD_COMPUTED_FIELD | VM_OC_GET_STACK) \
584+
CBC_OPCODE (CBC_EXT_CLASS_CALL_STATIC_BLOCK, \
585+
CBC_HAS_LITERAL_ARG, \
586+
0, \
587+
VM_OC_CLASS_CALL_STATIC_BLOCK | VM_OC_GET_LITERAL) \
584588
/* Class private property related opcodes */ \
585589
CBC_OPCODE (CBC_EXT_PUSH_PRIVATE_PROP_LITERAL_REFERENCE, \
586590
CBC_HAS_LITERAL_ARG, \

jerry-core/parser/js/js-lexer.c

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,7 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */
781781
#if JERRY_ESNEXT
782782
if (JERRY_UNLIKELY (keyword_p->type == LEXER_KEYW_AWAIT))
783783
{
784-
if (!(context_p->status_flags & PARSER_IS_ASYNC_FUNCTION)
784+
if (!(context_p->status_flags & (PARSER_IS_ASYNC_FUNCTION | PARSER_IS_CLASS_STATIC_BLOCK))
785785
&& !(context_p->global_status_flags & ECMA_PARSE_MODULE))
786786
{
787787
break;
@@ -2833,6 +2833,33 @@ lexer_construct_function_object (parser_context_t *context_p, /**< context */
28332833
return result_index;
28342834
} /* lexer_construct_function_object */
28352835

2836+
#if JERRY_ESNEXT
2837+
/**
2838+
* Construct a class static block function literal object.
2839+
*
2840+
* @return function object literal index
2841+
*/
2842+
uint16_t
2843+
lexer_construct_class_static_block_function (parser_context_t *context_p) /**< context */
2844+
{
2845+
ecma_compiled_code_t *compiled_code_p;
2846+
lexer_literal_t *literal_p;
2847+
uint16_t result_index;
2848+
2849+
literal_p = lexer_construct_unused_literal (context_p);
2850+
result_index = context_p->literal_count;
2851+
context_p->literal_count++;
2852+
2853+
parser_flush_cbc (context_p);
2854+
compiled_code_p = parser_parse_class_static_block (context_p);
2855+
2856+
literal_p->u.bytecode_p = compiled_code_p;
2857+
literal_p->type = LEXER_FUNCTION_LITERAL;
2858+
2859+
return result_index;
2860+
} /* lexer_construct_class_static_block_function */
2861+
#endif /* JERRY_ESNEXT */
2862+
28362863
/**
28372864
* Construct a regular expression object.
28382865
*
@@ -3244,6 +3271,17 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */
32443271
break;
32453272
}
32463273
#endif /* JERRY_ESNEXT */
3274+
case LIT_CHAR_LEFT_BRACE:
3275+
{
3276+
if (ident_opts & (LEXER_OBJ_IDENT_CLASS_NO_STATIC | LEXER_OBJ_IDENT_CLASS_PRIVATE))
3277+
{
3278+
break;
3279+
}
3280+
3281+
context_p->token.type = LEXER_LEFT_BRACE;
3282+
lexer_consume_next_character (context_p);
3283+
return;
3284+
}
32473285
case LIT_CHAR_RIGHT_BRACE:
32483286
{
32493287
if (ident_opts & LEXER_OBJ_IDENT_ONLY_IDENTIFIERS)

jerry-core/parser/js/js-parser-expr.c

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -847,11 +847,13 @@ parser_parse_class_body (parser_context_t *context_p, /**< context */
847847
}
848848
}
849849

850+
bool is_static_block = context_p->token.type == LEXER_LEFT_BRACE;
851+
850852
if (context_p->token.type == LEXER_RIGHT_SQUARE)
851853
{
852854
is_computed = true;
853855
}
854-
else if (LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type))
856+
else if (!is_static_block && LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type))
855857
{
856858
if (is_static && !is_private)
857859
{
@@ -869,7 +871,7 @@ parser_parse_class_body (parser_context_t *context_p, /**< context */
869871

870872
if (!(status_flags & (PARSER_IS_ASYNC_FUNCTION | PARSER_IS_GENERATOR_FUNCTION)))
871873
{
872-
if (!lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
874+
if (is_static_block || !lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
873875
{
874876
/* Class field. */
875877
if (fields_size == 0)
@@ -889,7 +891,7 @@ parser_parse_class_body (parser_context_t *context_p, /**< context */
889891
parser_emit_cbc_ext_literal_from_token (context_p, field_opcode);
890892
}
891893

892-
if (is_static && parser_is_constructor_literal (context_p))
894+
if (is_static && !is_static_block && parser_is_constructor_literal (context_p))
893895
{
894896
parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIST_EXPECTED);
895897
}
@@ -925,7 +927,31 @@ parser_parse_class_body (parser_context_t *context_p, /**< context */
925927
}
926928
}
927929

928-
if (lexer_consume_assign (context_p))
930+
if (is_static_block)
931+
{
932+
class_field_type |= PARSER_CLASS_FIELD_STATIC_BLOCK;
933+
934+
if (context_p->next_scanner_info_p->type != SCANNER_TYPE_CLASS_STATIC_BLOCK_END)
935+
{
936+
parser_flush_cbc (context_p);
937+
parser_parse_class_static_block (context_p);
938+
}
939+
940+
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_CLASS_STATIC_BLOCK_END);
941+
942+
scanner_set_location (context_p, &((scanner_location_info_t *) context_p->next_scanner_info_p)->location);
943+
scanner_release_next (context_p, sizeof (scanner_location_info_t));
944+
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION);
945+
range.start_location.source_p = context_p->next_scanner_info_p->source_p - 1;
946+
947+
scanner_seek (context_p);
948+
949+
parser_stack_push (context_p, &range.start_location, sizeof (scanner_location_t));
950+
fields_size += sizeof (scanner_location_t);
951+
952+
lexer_consume_next_character (context_p);
953+
}
954+
else if (lexer_consume_assign (context_p))
929955
{
930956
class_field_type |= PARSER_CLASS_FIELD_INITIALIZED;
931957

@@ -1738,8 +1764,17 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */
17381764

17391765
if (!lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
17401766
{
1767+
#if JERRY_ESNEXT
1768+
/* The `await` keyword is interpreted as an IdentifierReference within function expressions */
1769+
context_p->status_flags &= (uint32_t) ~PARSER_IS_CLASS_STATIC_BLOCK;
1770+
#endif /* JERRY_ESNEXT */
1771+
17411772
lexer_next_token (context_p);
17421773

1774+
#if JERRY_ESNEXT
1775+
context_p->status_flags |= parent_status_flags & PARSER_IS_CLASS_STATIC_BLOCK;
1776+
#endif /* JERRY_ESNEXT */
1777+
17431778
if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
17441779
{
17451780
parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
@@ -2168,7 +2203,8 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
21682203
#endif /* JERRY_FUNCTION_TO_STRING */
21692204

21702205
uint32_t arrow_status_flags =
2171-
(PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION | (context_p->status_flags & PARSER_INSIDE_CLASS_FIELD));
2206+
(PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION
2207+
| (context_p->status_flags & (PARSER_INSIDE_CLASS_FIELD | PARSER_IS_CLASS_STATIC_BLOCK)));
21722208

21732209
if (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_ASYNC)
21742210
{
@@ -2425,7 +2461,8 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
24252461
#endif /* JERRY_FUNCTION_TO_STRING */
24262462

24272463
uint32_t arrow_status_flags =
2428-
(PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION | (context_p->status_flags & PARSER_INSIDE_CLASS_FIELD));
2464+
(PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION
2465+
| (context_p->status_flags & (PARSER_INSIDE_CLASS_FIELD | PARSER_IS_CLASS_STATIC_BLOCK)));
24292466
parser_parse_function_expression (context_p, arrow_status_flags);
24302467
return parser_abort_parsing_after_assignment_expression (context_p);
24312468
}

jerry-core/parser/js/js-parser-internal.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,13 @@ typedef enum
7676
PARSER_INSIDE_CLASS_FIELD = (1u << 23), /**< a class field is being parsed */
7777
PARSER_ALLOW_NEW_TARGET = (1u << 24), /**< allow new.target parsing in the current context */
7878
PARSER_IS_METHOD = (1u << 25), /**< method is parsed */
79+
PARSER_IS_CLASS_STATIC_BLOCK = (1u << 26), /**< a class static block is parsed */
7980
PARSER_PRIVATE_FUNCTION_NAME = PARSER_IS_FUNC_EXPRESSION, /**< represents private method for
8081
* parser_set_function_name*/
8182
#endif /* JERRY_ESNEXT */
8283
#if JERRY_MODULE_SYSTEM
83-
PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 26), /**< parsing a function or class default export */
84-
PARSER_MODULE_STORE_IDENT = (1u << 27), /**< store identifier of the current export statement */
84+
PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 27), /**< parsing a function or class default export */
85+
PARSER_MODULE_STORE_IDENT = (1u << 28), /**< store identifier of the current export statement */
8586
#endif /* JERRY_MODULE_SYSTEM */
8687
PARSER_HAS_LATE_LIT_INIT = (1u << 30), /**< there are identifier or string literals which construction
8788
* is postponed after the local parser data is freed */
@@ -144,6 +145,7 @@ typedef enum
144145
PARSER_CLASS_FIELD_NORMAL = (1u << 1), /**< normal (non-computed) class field */
145146
PARSER_CLASS_FIELD_INITIALIZED = (1u << 2), /**< class field is initialized */
146147
PARSER_CLASS_FIELD_STATIC = (1u << 3), /**< static class field */
148+
PARSER_CLASS_FIELD_STATIC_BLOCK = (1u << 4), /**< static class field */
147149
} parser_class_field_type_t;
148150

149151
#endif /* JERRY_ESNEXT */
@@ -798,6 +800,9 @@ void lexer_construct_literal_object (parser_context_t *context_p,
798800
bool lexer_construct_number_object (parser_context_t *context_p, bool is_expr, bool is_negative_number);
799801
void lexer_convert_push_number_to_push_literal (parser_context_t *context_p);
800802
uint16_t lexer_construct_function_object (parser_context_t *context_p, uint32_t extra_status_flags);
803+
#if JERRY_ESNEXT
804+
uint16_t lexer_construct_class_static_block_function (parser_context_t *context_p);
805+
#endif /* JERRY_ESNEXT */
801806
void lexer_construct_regexp_object (parser_context_t *context_p, bool parse_only);
802807
bool lexer_compare_identifier_to_string (const lexer_lit_location_t *left_p, const uint8_t *right_p, size_t size);
803808
bool lexer_compare_identifiers (parser_context_t *context_p,
@@ -931,6 +936,7 @@ uint8_t *parser_line_info_generate (parser_context_t *context_p);
931936

932937
ecma_compiled_code_t *parser_parse_function (parser_context_t *context_p, uint32_t status_flags);
933938
#if JERRY_ESNEXT
939+
ecma_compiled_code_t *parser_parse_class_static_block (parser_context_t *context_p);
934940
ecma_compiled_code_t *parser_parse_arrow_function (parser_context_t *context_p, uint32_t status_flags);
935941
ecma_compiled_code_t *parser_parse_class_fields (parser_context_t *context_p);
936942
void parser_set_function_name (parser_context_t *context_p,

jerry-core/parser/js/js-parser-statm.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3090,6 +3090,12 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
30903090
{
30913091
parser_raise_error (context_p, PARSER_ERR_INVALID_RETURN);
30923092
}
3093+
#if JERRY_ESNEXT
3094+
if (context_p->status_flags & PARSER_IS_CLASS_STATIC_BLOCK)
3095+
{
3096+
parser_raise_error (context_p, PARSER_ERR_INVALID_RETURN);
3097+
}
3098+
#endif /* JERRY_ESNEXT */
30933099

30943100
lexer_next_token (context_p);
30953101

jerry-core/parser/js/js-parser.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2793,6 +2793,46 @@ parser_parse_function (parser_context_t *context_p, /**< context */
27932793

27942794
#if JERRY_ESNEXT
27952795

2796+
/**
2797+
* Parse static class block code
2798+
*
2799+
* @return compiled code
2800+
*/
2801+
ecma_compiled_code_t *
2802+
parser_parse_class_static_block (parser_context_t *context_p) /**< context */
2803+
{
2804+
parser_saved_context_t saved_context;
2805+
ecma_compiled_code_t *compiled_code_p;
2806+
2807+
parser_save_context (context_p, &saved_context);
2808+
context_p->status_flags |= (PARSER_IS_CLASS_STATIC_BLOCK | PARSER_FUNCTION_CLOSURE | PARSER_ALLOW_SUPER
2809+
| PARSER_INSIDE_CLASS_FIELD | PARSER_ALLOW_NEW_TARGET | PARSER_DISALLOW_AWAIT_YIELD);
2810+
2811+
#if JERRY_PARSER_DUMP_BYTE_CODE
2812+
if (context_p->is_show_opcodes)
2813+
{
2814+
JERRY_DEBUG_MSG ("\n--- Static class block parsing start ---\n\n");
2815+
}
2816+
#endif /* JERRY_PARSER_DUMP_BYTE_CODE */
2817+
2818+
scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS);
2819+
lexer_next_token (context_p);
2820+
2821+
parser_parse_statements (context_p);
2822+
compiled_code_p = parser_post_processing (context_p);
2823+
2824+
#if JERRY_PARSER_DUMP_BYTE_CODE
2825+
if (context_p->is_show_opcodes)
2826+
{
2827+
JERRY_DEBUG_MSG ("\n--- Static class block parsing end ---\n\n");
2828+
}
2829+
#endif /* JERRY_PARSER_DUMP_BYTE_CODE */
2830+
2831+
parser_restore_context (context_p, &saved_context);
2832+
2833+
return compiled_code_p;
2834+
} /* parser_parse_class_static_block */
2835+
27962836
/**
27972837
* Parse arrow function code
27982838
*
@@ -2826,6 +2866,12 @@ parser_parse_arrow_function (parser_context_t *context_p, /**< context */
28262866
}
28272867
#endif /* JERRY_DEBUGGER */
28282868

2869+
/* The `await` keyword is disallowed in the IdentifierReference position */
2870+
if (status_flags & PARSER_IS_CLASS_STATIC_BLOCK)
2871+
{
2872+
context_p->status_flags |= PARSER_DISALLOW_AWAIT_YIELD;
2873+
}
2874+
28292875
if (context_p->token.type == LEXER_LEFT_PAREN)
28302876
{
28312877
lexer_next_token (context_p);
@@ -2837,6 +2883,12 @@ parser_parse_arrow_function (parser_context_t *context_p, /**< context */
28372883
parser_parse_function_arguments (context_p, LEXER_ARROW);
28382884
}
28392885

2886+
/* The `await` keyword is interpreted as an identifier within the body of arrow functions */
2887+
if (status_flags & PARSER_IS_CLASS_STATIC_BLOCK)
2888+
{
2889+
context_p->status_flags &= (uint32_t) ~(PARSER_DISALLOW_AWAIT_YIELD | PARSER_IS_CLASS_STATIC_BLOCK);
2890+
}
2891+
28402892
JERRY_ASSERT (context_p->token.type == LEXER_ARROW);
28412893

28422894
lexer_next_token (context_p);
@@ -2950,6 +3002,20 @@ parser_parse_class_fields (parser_context_t *context_p) /**< context */
29503002
if (class_field_type & PARSER_CLASS_FIELD_NORMAL)
29513003
{
29523004
scanner_set_location (context_p, &range.start_location);
3005+
3006+
if (class_field_type & PARSER_CLASS_FIELD_STATIC_BLOCK)
3007+
{
3008+
scanner_seek (context_p);
3009+
JERRY_ASSERT (context_p->source_p[1] == LIT_CHAR_LEFT_BRACE);
3010+
context_p->source_p += 2;
3011+
context_p->source_end_p = source_end_p;
3012+
3013+
uint16_t func_index = lexer_construct_class_static_block_function (context_p);
3014+
3015+
parser_emit_cbc_ext_literal (context_p, CBC_EXT_CLASS_CALL_STATIC_BLOCK, func_index);
3016+
continue;
3017+
}
3018+
29533019
uint32_t ident_opts = LEXER_OBJ_IDENT_ONLY_IDENTIFIERS;
29543020
is_private = context_p->source_p[-1] == LIT_CHAR_HASHMARK;
29553021

jerry-core/parser/js/js-scanner-internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ typedef enum
118118
SCAN_STACK_FUNCTION_PARAMETERS, /**< function parameter initializer */
119119
SCAN_STACK_FOR_START_PATTERN, /**< possible assignment pattern for "for" iterator */
120120
SCAN_STACK_USE_ASYNC, /**< an "async" identifier is used */
121+
SCAN_STACK_CLASS_STATIC_BLOCK, /**< class static block */
121122
#endif /* JERRY_ESNEXT */
122123
#if JERRY_MODULE_SYSTEM
123124
SCAN_STACK_EXPORT_DEFAULT, /**< scan primary expression after export default */

jerry-core/parser/js/js-scanner-util.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2083,6 +2083,7 @@ scanner_cleanup (parser_context_t *context_p) /**< context */
20832083
#if JERRY_ESNEXT
20842084
case SCANNER_TYPE_INITIALIZER:
20852085
case SCANNER_TYPE_CLASS_FIELD_INITIALIZER_END:
2086+
case SCANNER_TYPE_CLASS_STATIC_BLOCK_END:
20862087
#endif /* JERRY_ESNEXT */
20872088
{
20882089
size = sizeof (scanner_location_info_t);

0 commit comments

Comments
 (0)