From 84bc1e03fbed8ffc7296e774a40132d82bf8b0cf Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Mon, 24 Aug 2020 14:47:10 +0200 Subject: [PATCH] Detect assignment pattern for for-in/of (#4140) Furthermore do not allow default value for rest parameter JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/parser/js/js-parser-expr.c | 24 +- jerry-core/parser/js/js-parser-statm.c | 24 ++ jerry-core/parser/js/js-scanner-internal.h | 1 + jerry-core/parser/js/js-scanner-util.c | 1 + jerry-core/parser/js/js-scanner.c | 33 +- jerry-core/parser/js/js-scanner.h | 1 + tests/jerry/es.next/array-pattern.js | 3 + tests/jerry/es.next/for-pattern.js | 52 ++- tests/test262-es6-excludelist.xml | 3 - tests/test262-esnext-excludelist.xml | 427 --------------------- 10 files changed, 123 insertions(+), 446 deletions(-) diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index aa1105517..816a1614b 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -3091,10 +3091,7 @@ parser_pattern_get_target (parser_context_t *context_p, /**< context */ } else { - if (context_p->next_scanner_info_p->type != SCANNER_TYPE_INITIALIZER) - { - parser_raise_error (context_p, PARSER_ERR_INVALID_DESTRUCTURING_PATTERN); - } + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER); scanner_get_location (&start_location, context_p); scanner_set_location (context_p, &((scanner_location_info_t *) context_p->next_scanner_info_p)->location); @@ -3205,7 +3202,7 @@ parser_pattern_form_assignment (parser_context_t *context_p, /**< context */ parser_pattern_emit_rhs (context_p, rhs_opcode, literal_index); - if (context_p->token.type == LEXER_ASSIGN) + if (context_p->token.type == LEXER_ASSIGN && !(flags & PARSER_PATTERN_REST_ELEMENT)) { parser_branch_t skip_init; lexer_next_token (context_p); @@ -3273,12 +3270,23 @@ parser_pattern_process_nested_pattern (parser_context_t *context_p, /**< context | PARSER_PATTERN_LET | PARSER_PATTERN_CONST | PARSER_PATTERN_LOCAL - | PARSER_PATTERN_REST_ELEMENT | PARSER_PATTERN_ARGUMENTS))); - if (context_p->next_scanner_info_p->source_p == context_p->source_p) + JERRY_ASSERT (context_p->next_scanner_info_p->source_p != context_p->source_p + || context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER + || context_p->next_scanner_info_p->type == SCANNER_TYPE_OBJECT_LITERAL_WITH_SUPER); + + if (context_p->next_scanner_info_p->source_p == context_p->source_p + && context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER) { - options |= PARSER_PATTERN_TARGET_DEFAULT; + if (!(flags & PARSER_PATTERN_REST_ELEMENT)) + { + options |= PARSER_PATTERN_TARGET_DEFAULT; + } + else + { + scanner_release_next (context_p, sizeof (scanner_location_info_t)); + } } parser_pattern_emit_rhs (context_p, rhs_opcode, literal_index); diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 9d3d142a2..8f3774e0d 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -1324,6 +1324,11 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ if (token_type == LEXER_EOS) { lexer_next_token (context_p); + + if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE) + { + token_type = context_p->token.type; + } } #else /* !ENABLED (JERRY_ESNEXT) */ lexer_next_token (context_p); @@ -1411,6 +1416,25 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ #endif /* ENABLED (JERRY_ESNEXT) */ break; } +#if ENABLED (JERRY_ESNEXT) + case LEXER_LEFT_BRACE: + case LEXER_LEFT_SQUARE: + { + if (context_p->next_scanner_info_p->source_p == context_p->source_p + && context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_PATTERN) + { + parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT + : CBC_EXT_FOR_OF_GET_NEXT); + + scanner_release_next (context_p, sizeof (scanner_info_t)); + parser_parse_initializer (context_p, PARSER_PATTERN_TARGET_ON_STACK); + /* Pop the value returned by GET_NEXT. */ + parser_emit_cbc (context_p, CBC_POP); + break; + } + /* FALLTHRU */ + } +#endif /* ENABLED (JERRY_ESNEXT) */ default: { uint16_t opcode; diff --git a/jerry-core/parser/js/js-scanner-internal.h b/jerry-core/parser/js/js-scanner-internal.h index 77cef99c1..b9fffa099 100644 --- a/jerry-core/parser/js/js-scanner-internal.h +++ b/jerry-core/parser/js/js-scanner-internal.h @@ -114,6 +114,7 @@ typedef enum SCAN_STACK_CLASS_EXPRESSION, /**< class expression */ SCAN_STACK_CLASS_EXTENDS, /**< class extends expression */ 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 */ SCAN_STACK_OBJECT_LITERAL_WITH_SUPER, /**< object literal with inner super reference */ #endif /* ENABLED (JERRY_ESNEXT) */ diff --git a/jerry-core/parser/js/js-scanner-util.c b/jerry-core/parser/js/js-scanner-util.c index 01e992585..6ce91b5d1 100644 --- a/jerry-core/parser/js/js-scanner-util.c +++ b/jerry-core/parser/js/js-scanner-util.c @@ -1679,6 +1679,7 @@ scanner_cleanup (parser_context_t *context_p) /**< context */ #if ENABLED (JERRY_ESNEXT) JERRY_ASSERT (scanner_info_p->type == SCANNER_TYPE_END_ARGUMENTS || scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION + || scanner_info_p->type == SCANNER_TYPE_FOR_PATTERN || scanner_info_p->type == SCANNER_TYPE_CLASS_CONSTRUCTOR || scanner_info_p->type == SCANNER_TYPE_OBJECT_LITERAL_WITH_SUPER || scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index bd371933b..438a00bb9 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -873,6 +873,20 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * return SCAN_NEXT_TOKEN; } + if (context_p->stack_top_uint8 == SCAN_STACK_FOR_START_PATTERN) + { + JERRY_ASSERT (binding_type == SCANNER_BINDING_NONE); + + parser_stack_change_last_uint8 (context_p, SCAN_STACK_FOR_START); + + if (context_p->token.type == LEXER_KEYW_IN || SCANNER_IDENTIFIER_IS_OF ()) + { + scanner_info_t *info_p = scanner_insert_info (context_p, source_start.source_p, sizeof (scanner_info_t)); + info_p->type = SCANNER_TYPE_FOR_PATTERN; + return SCAN_KEEP_TOKEN; + } + } + if (context_p->token.type != LEXER_ASSIGN) { if (SCANNER_NEEDS_BINDING_LIST (binding_type)) @@ -1243,6 +1257,12 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ break; } #if ENABLED (JERRY_ESNEXT) + case LEXER_LEFT_BRACE: + case LEXER_LEFT_SQUARE: + { + stack_mode = SCAN_STACK_FOR_START_PATTERN; + break; + } case LEXER_LITERAL: { if (!lexer_token_is_let (context_p)) @@ -3515,16 +3535,16 @@ scan_completed: print_location = true; break; } - case SCANNER_TYPE_OBJECT_LITERAL_WITH_SUPER: + case SCANNER_TYPE_FOR_PATTERN: { - JERRY_DEBUG_MSG (" OBJECT-LITERAL-WITH-SUPER: source:%d\n", + JERRY_DEBUG_MSG (" SCANNER_TYPE_FOR_PATTERN: source:%d\n", (int) (info_p->source_p - source_start_p)); print_location = false; break; } case SCANNER_TYPE_CLASS_CONSTRUCTOR: { - JERRY_DEBUG_MSG (" CLASS-CONSTRUCTOR: source:%d\n", + JERRY_DEBUG_MSG (" CLASS_CONSTRUCTOR: source:%d\n", (int) (info_p->source_p - source_start_p)); print_location = false; break; @@ -3547,6 +3567,13 @@ scan_completed: (int) (info_p->source_p - source_start_p)); break; } + case SCANNER_TYPE_OBJECT_LITERAL_WITH_SUPER: + { + JERRY_DEBUG_MSG (" OBJECT_LITERAL_WITH_SUPER: source:%d\n", + (int) (info_p->source_p - source_start_p)); + print_location = false; + break; + } #endif /* ENABLED (JERRY_ESNEXT) */ } diff --git a/jerry-core/parser/js/js-scanner.h b/jerry-core/parser/js/js-scanner.h index 298f645fc..fb24ac807 100644 --- a/jerry-core/parser/js/js-scanner.h +++ b/jerry-core/parser/js/js-scanner.h @@ -46,6 +46,7 @@ typedef enum SCANNER_TYPE_CASE, /**< case statement */ #if ENABLED (JERRY_ESNEXT) 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_LET_EXPRESSION, /**< let expression */ SCANNER_TYPE_ERR_REDECLARED, /**< syntax error: a variable is redeclared */ diff --git a/tests/jerry/es.next/array-pattern.js b/tests/jerry/es.next/array-pattern.js index ff7a75d52..86b1969be 100644 --- a/tests/jerry/es.next/array-pattern.js +++ b/tests/jerry/es.next/array-pattern.js @@ -60,6 +60,9 @@ checkSyntax ("[()] = []"); checkSyntax ("try { let [$] = $;"); checkSyntax ("let a, [ b.c ] = [6];"); checkSyntax ("let [(a)] = [1]"); +checkSyntax ("[...a = []] = [1]"); +checkSyntax ("[...[a] = []] = [1]"); +checkSyntax ("[...[a, [...b] = []] = []] = [1]"); mustThrow ("var [a] = 4"); mustThrow ("var [a] = 5"); diff --git a/tests/jerry/es.next/for-pattern.js b/tests/jerry/es.next/for-pattern.js index bbcb4da75..f08ab959c 100644 --- a/tests/jerry/es.next/for-pattern.js +++ b/tests/jerry/es.next/for-pattern.js @@ -12,6 +12,16 @@ // 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) + } +} + var idx = 0; for (var [a,b] of [[1,2], [3,4]]) { @@ -69,9 +79,41 @@ for (let [a,b] of [[11,12], [13,14]]) assert(a === 3); assert(b === 4); -try { - eval("for (let [a,b] = [1,2] of [[3,4]]) {}"); - assert(false); -} catch (e) { - assert(e instanceof SyntaxError); +check_syntax_error("for (let [a,b] = [1,2] of [[3,4]]) {}") + +idx = 0; +for ([a,b] of [[10,true], ["x",null]]) +{ + if (idx == 0) + { + assert(a === 10); + assert(b === true); + idx = 1; + } + else + { + assert(a === "x"); + assert(b === null); + } } + +assert(a === "x"); +assert(b === null); + +check_syntax_error("for ([a,b] = [1,2] of [[3,4]]) {}") + +var o = {} +for ([a, b] = [o,false]; false; ) +{ + assert(false); +} + +assert(a === o); +assert(b === false); + +for ([a, b] + [a, b]; false; ) +{ + assert(false); +} + +check_syntax_error("for ([a,b] + 1 of [[3,4]]) {}") diff --git a/tests/test262-es6-excludelist.xml b/tests/test262-es6-excludelist.xml index e59d6dbad..8fdcc9345 100644 --- a/tests/test262-es6-excludelist.xml +++ b/tests/test262-es6-excludelist.xml @@ -256,7 +256,6 @@ No longer a SyntaxError in ES11 - @@ -330,8 +329,6 @@ - - ES2018 change: next method must be cached diff --git a/tests/test262-esnext-excludelist.xml b/tests/test262-esnext-excludelist.xml index 3fc3ef330..54f814cbf 100644 --- a/tests/test262-esnext-excludelist.xml +++ b/tests/test262-esnext-excludelist.xml @@ -3980,9 +3980,7 @@ - - @@ -4030,7 +4028,6 @@ - @@ -4508,9 +4505,7 @@ - - @@ -4518,9 +4513,7 @@ - - @@ -4528,9 +4521,7 @@ - - @@ -4538,9 +4529,7 @@ - - @@ -6499,9 +6488,7 @@ - - @@ -6515,9 +6502,7 @@ - - @@ -6606,9 +6591,7 @@ - - @@ -6616,9 +6599,7 @@ - - @@ -7576,9 +7557,7 @@ - - @@ -7586,9 +7565,7 @@ - - @@ -7596,9 +7573,7 @@ - - @@ -7606,9 +7581,7 @@ - - @@ -9180,7 +9153,6 @@ - @@ -9191,123 +9163,19 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -9430,134 +9298,35 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -9702,244 +9471,59 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -9959,7 +9543,6 @@ - @@ -9980,17 +9563,14 @@ - - - @@ -10007,9 +9587,7 @@ - - @@ -10022,9 +9600,7 @@ - - @@ -10056,7 +9632,6 @@ - @@ -10105,7 +9680,6 @@ - @@ -10115,7 +9689,6 @@ -