From bd1c4df9a608cc7193330944c857ca4f6294b993 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Fri, 15 May 2020 22:32:04 +0200 Subject: [PATCH] Fix keyword parsing after use strict. (#3740) JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/parser/js/js-parser-statm.c | 62 +++++++++++++------ jerry-core/parser/js/js-scanner-ops.c | 10 +++- tests/jerry/strict2.js | 82 ++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 21 deletions(-) create mode 100644 tests/jerry/strict2.js diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 38182f95f..0647a54ab 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -2592,6 +2592,16 @@ parser_parse_label (parser_context_t *context_p) /**< context */ parser_stack_iterator_init (context_p, &context_p->last_statement); } /* parser_parse_label */ +/** + * Strict mode types for statement parsing. + */ +typedef enum +{ + PARSER_USE_STRICT_NOT_FOUND = 0, /**< 'use strict' directive is not found */ + PARSER_USE_STRICT_FOUND = 1, /**< 'use strict' directive is found but strict mode has already been enabled */ + PARSER_USE_STRICT_SET = 2, /**< strict mode is enabled after 'use strict' directive is found */ +} parser_strict_mode_type_t; + /** * Parse statements. */ @@ -2627,7 +2637,7 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ && context_p->token.lit_location.type == LEXER_STRING_LITERAL) { lexer_lit_location_t lit_location; - bool is_use_strict = false; + parser_strict_mode_type_t strict_mode = PARSER_USE_STRICT_NOT_FOUND; JERRY_ASSERT (context_p->stack_depth == 0); #ifndef JERRY_NDEBUG @@ -2636,7 +2646,14 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ if (lexer_string_is_use_strict (context_p)) { - is_use_strict = true; + strict_mode = PARSER_USE_STRICT_FOUND; + + if (!(context_p->status_flags & PARSER_IS_STRICT)) + { + /* The next token should be parsed in strict mode. */ + context_p->status_flags |= PARSER_IS_STRICT; + strict_mode = PARSER_USE_STRICT_SET; + } } lit_location = context_p->token.lit_location; @@ -2645,6 +2662,11 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ if (!lexer_string_is_directive (context_p)) { /* The string is part of an expression statement. */ + if (strict_mode == PARSER_USE_STRICT_SET) + { + context_p->status_flags &= (uint32_t) ~PARSER_IS_STRICT; + } + #if ENABLED (JERRY_DEBUGGER) if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) { @@ -2670,24 +2692,20 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ break; } - if (is_use_strict) - { #if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) - if (context_p->is_show_opcodes - && !(context_p->status_flags & PARSER_IS_STRICT)) - { - JERRY_DEBUG_MSG (" Note: switch to strict mode\n\n"); - } -#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ -#if ENABLED (JERRY_ES2015) - if (context_p->status_flags & PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM) - { - parser_raise_error (context_p, PARSER_ERR_USE_STRICT_NOT_ALLOWED); - } -#endif /* ENABLED (JERRY_ES2015) */ - - context_p->status_flags |= PARSER_IS_STRICT; + if (strict_mode == PARSER_USE_STRICT_SET && context_p->is_show_opcodes) + { + JERRY_DEBUG_MSG (" Note: switch to strict mode\n\n"); } +#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ + +#if ENABLED (JERRY_ES2015) + if (strict_mode != PARSER_USE_STRICT_NOT_FOUND + && (context_p->status_flags & PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM)) + { + parser_raise_error (context_p, PARSER_ERR_USE_STRICT_NOT_ALLOWED); + } +#endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type == LEXER_SEMICOLON) { @@ -3048,7 +3066,13 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ scanner_release_next (context_p, sizeof (scanner_info_t)); } - parser_parse_expression_statement (context_p, PARSE_EXPR); + if (context_p->status_flags & PARSER_IS_FUNCTION) + { + parser_parse_expression_statement (context_p, PARSE_EXPR); + break; + } + + parser_parse_block_expression (context_p, PARSE_EXPR); break; } diff --git a/jerry-core/parser/js/js-scanner-ops.c b/jerry-core/parser/js/js-scanner-ops.c index 0270d0120..569be23f7 100644 --- a/jerry-core/parser/js/js-scanner-ops.c +++ b/jerry-core/parser/js/js-scanner-ops.c @@ -539,15 +539,22 @@ scanner_check_directives (parser_context_t *context_p, /**< context */ { bool is_use_strict = false; - if (lexer_string_is_use_strict (context_p)) + if (lexer_string_is_use_strict (context_p) + && !(context_p->status_flags & PARSER_IS_STRICT)) { is_use_strict = true; + context_p->status_flags |= PARSER_IS_STRICT; } lexer_next_token (context_p); if (!lexer_string_is_directive (context_p)) { + if (is_use_strict) + { + context_p->status_flags &= (uint32_t) ~PARSER_IS_STRICT; + } + /* The string is part of an expression statement. */ scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; break; @@ -555,7 +562,6 @@ scanner_check_directives (parser_context_t *context_p, /**< context */ if (is_use_strict) { - context_p->status_flags |= PARSER_IS_STRICT; scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_IS_STRICT; } diff --git a/tests/jerry/strict2.js b/tests/jerry/strict2.js new file mode 100644 index 000000000..37e2a8608 --- /dev/null +++ b/tests/jerry/strict2.js @@ -0,0 +1,82 @@ +// 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 (script) +{ + try + { + eval (script); + assert (false); + } + catch (e) + { + assert (e instanceof SyntaxError); + } +} + +var + implements = 0, + private = 1, + public = 2, + interface = 3, + package = 4, + protected = 5, + let = 6, + yield = 7, + static = 8; + +check_syntax_error("'use strict'\nimplements") +check_syntax_error("'use strict'\n\\u0069mplements") +assert(eval("'use stric'\nimplements") === 0) +assert(eval("'use stric'\n\\u0069mplements") === 0) + +check_syntax_error("'use strict'\nprivate") +check_syntax_error("'use strict'\n\\u0070rivate") +assert(eval("'use stric'\nprivate") === 1) +assert(eval("'use stric'\n\\u0070rivate") === 1) + +check_syntax_error("'use strict'\npublic") +check_syntax_error("'use strict'\n\\u0070ublic") +assert(eval("'use stric'\npublic") === 2) +assert(eval("'use stric'\n\\u0070ublic") === 2) + +check_syntax_error("'use strict'\ninterface") +check_syntax_error("'use strict'\n\\u0069nterface") +assert(eval("'use stric'\ninterface") === 3) +assert(eval("'use stric'\n\\u0069nterface") === 3) + +check_syntax_error("'use strict'\npackage") +check_syntax_error("'use strict'\n\\u0070ackage") +assert(eval("'use stric'\npackage") === 4) +assert(eval("'use stric'\n\\u0070ackage") === 4) + +check_syntax_error("'use strict'\nprotected") +check_syntax_error("'use strict'\n\\u0070rotected") +assert(eval("'use stric'\nprotected") === 5) +assert(eval("'use stric'\n\\u0070rotected") === 5) + +check_syntax_error("'use strict'\nlet") +check_syntax_error("'use strict'\n\\u006cet") +assert(eval("'use stric'\nlet") === 6) +assert(eval("'use stric'\n\\u006cet") === 6) + +check_syntax_error("'use strict'\nyield") +check_syntax_error("'use strict'\n\\u0079ield") +assert(eval("'use stric'\nyield") === 7) +assert(eval("'use stric'\n\\u0079ield") === 7) + +check_syntax_error("'use strict'\nstatic") +check_syntax_error("'use strict'\n\\u0073tatic") +assert(eval("'use stric'\nstatic") === 8) +assert(eval("'use stric'\n\\u0073tatic") === 8)