From fbde788d1f334510e924a5f5c2a6395564265224 Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Wed, 11 Sep 2019 11:15:46 +0200 Subject: [PATCH] Scanner rework. (#3038) The scanner was an on-demand tool of the parser, which was triggered by certain statements. After the rework, the scanner runs only once, and collects all information. This information is passed to the parser. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- jerry-core/parser/js/js-lexer.c | 46 +- jerry-core/parser/js/js-lexer.h | 10 + jerry-core/parser/js/js-parser-expr.c | 130 +- jerry-core/parser/js/js-parser-internal.h | 26 +- jerry-core/parser/js/js-parser-mem.c | 5 +- jerry-core/parser/js/js-parser-scanner.c | 1030 ------------- jerry-core/parser/js/js-parser-statm.c | 523 +++---- jerry-core/parser/js/js-parser.c | 66 +- jerry-core/parser/js/js-scanner-util.c | 290 ++++ jerry-core/parser/js/js-scanner.c | 1702 +++++++++++++++++++++ jerry-core/parser/js/js-scanner.h | 111 ++ tests/jerry/es2015/arrow-function.js | 8 + tests/jerry/es2015/module-export-01.js | 3 + tests/jerry/es2015/module-export-02.js | 3 + tests/jerry/es2015/module-export-03.js | 3 + tests/jerry/es2015/module-export-04.js | 3 + tests/jerry/es2015/module-export-05.js | 3 + tests/jerry/es2015/module-export-06.js | 3 + tests/jerry/es2015/module-export-07.js | 3 + tests/jerry/es2015/module-import-01.js | 3 + tests/jerry/es2015/module-import-02.js | 3 + tests/jerry/es2015/module-import-03.js | 3 + tests/jerry/es2015/module-import-04.js | 3 + tests/jerry/regression-test-issue-1555.js | 2 +- 24 files changed, 2511 insertions(+), 1471 deletions(-) delete mode 100644 jerry-core/parser/js/js-parser-scanner.c create mode 100644 jerry-core/parser/js/js-scanner-util.c create mode 100644 jerry-core/parser/js/js-scanner.c create mode 100644 jerry-core/parser/js/js-scanner.h diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c index f7b1c68c8..816d3c1bb 100644 --- a/jerry-core/parser/js/js-lexer.c +++ b/jerry-core/parser/js/js-lexer.c @@ -1373,45 +1373,19 @@ lexer_check_next_character (parser_context_t *context_p, /**< context */ /** * Checks whether the next token is a type used for detecting arrow functions. * - * @return identified token type + * @return true if the next token is an arrow token */ -lexer_token_type_t +bool lexer_check_arrow (parser_context_t *context_p) /**< context */ { 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) - { - switch (context_p->source_p[0]) - { - case LIT_CHAR_COMMA: - { - return LEXER_COMMA; - } - case LIT_CHAR_RIGHT_PAREN: - { - return LEXER_RIGHT_PAREN; - } - case LIT_CHAR_EQUALS: - { - if (!(context_p->token.flags & LEXER_WAS_NEWLINE) - && context_p->source_p + 1 < context_p->source_end_p - && context_p->source_p[1] == (uint8_t) LIT_CHAR_GREATER_THAN) - { - return LEXER_ARROW; - } - break; - } - default: - { - break; - } - } - } - - return LEXER_EOS; + return (!(context_p->token.flags & LEXER_WAS_NEWLINE) + && context_p->source_p + 2 <= context_p->source_end_p + && context_p->source_p[0] == (uint8_t) LIT_CHAR_EQUALS + && context_p->source_p[1] == (uint8_t) LIT_CHAR_GREATER_THAN); } /* lexer_check_arrow */ #endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ @@ -2427,7 +2401,7 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */ */ void lexer_scan_identifier (parser_context_t *context_p, /**< context */ - bool property_name) /**< property name */ + uint32_t ident_opts) /**< lexer_scan_ident_opts_t option bits */ { lexer_skip_spaces (context_p); context_p->token.line = context_p->line; @@ -2438,7 +2412,9 @@ lexer_scan_identifier (parser_context_t *context_p, /**< context */ { lexer_parse_identifier (context_p, false); - if (property_name && context_p->token.lit_location.length == 3) + if ((ident_opts & LEXER_SCAN_IDENT_PROPERTY) + && !(ident_opts & LEXER_SCAN_IDENT_NO_KEYW) + && context_p->token.lit_location.length == 3) { lexer_skip_spaces (context_p); @@ -2458,7 +2434,7 @@ lexer_scan_identifier (parser_context_t *context_p, /**< context */ return; } - if (property_name) + if (ident_opts & LEXER_SCAN_IDENT_PROPERTY) { lexer_next_token (context_p); diff --git a/jerry-core/parser/js/js-lexer.h b/jerry-core/parser/js/js-lexer.h index 3316b4547..1dfd0a9f1 100644 --- a/jerry-core/parser/js/js-lexer.h +++ b/jerry-core/parser/js/js-lexer.h @@ -255,6 +255,16 @@ typedef enum LEXER_OBJ_IDENT_CLASS_METHOD = (1u << 2), /**< expect identifier inside a class body */ } lexer_obj_ident_opts_t; +/** + * Lexer scan identifier parse options. + */ +typedef enum +{ + LEXER_SCAN_IDENT_NO_OPTS = (1u << 0), /**< no options */ + LEXER_SCAN_IDENT_PROPERTY = (1u << 1), /**< scan valid property names */ + LEXER_SCAN_IDENT_NO_KEYW = (1u << 2), /**< don\t scan keywords (e.g. get/set) */ +} lexer_scan_ident_opts_t; + /** * Lexer literal object types. */ diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index e4b62f2c4..23455800b 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -1041,79 +1041,6 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */ context_p->last_cbc.literal_object_type = LEXER_LITERAL_OBJECT_ANY; } /* parser_parse_function_expression */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - -/** - * Checks whether the bracketed expression is an argument list of an arrow function. - * - * @return true - if an arrow function is found - * false - otherwise - */ -static bool -parser_check_arrow_function (parser_context_t *context_p) /**< context */ -{ - lexer_range_t range; - - range.source_p = context_p->token.lit_location.char_p; - range.line = context_p->token.line; - range.column = context_p->token.column; - - lexer_next_token (context_p); - - bool is_arrow_function = true; - - while (true) - { - if (context_p->token.type == LEXER_RIGHT_PAREN) - { - break; - } - - if (context_p->token.type == LEXER_COMMA) - { - lexer_next_token (context_p); - - if (context_p->token.type == LEXER_LITERAL - && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) - { - lexer_next_token (context_p); - continue; - } - } - - is_arrow_function = false; - break; - } - - if (is_arrow_function) - { - lexer_next_token (context_p); - - if (context_p->token.type != LEXER_ARROW) - { - is_arrow_function = false; - } - } - - context_p->source_p = range.source_p; - context_p->line = range.line; - context_p->column = range.column; - - /* Re-parse the original identifier. */ - lexer_next_token (context_p); - - if (is_arrow_function) - { - parser_parse_function_expression (context_p, - PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION | PARSER_ARROW_PARSE_ARGS); - return true; - } - - return false; -} /* parser_check_arrow_function */ - -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - #if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) /** @@ -1247,6 +1174,13 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ * they are processed when their closing paren is reached. */ if (context_p->token.type == LEXER_LEFT_PAREN) { +#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ARROW); + break; + } +#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ (*grouping_level_p)++; new_was_seen = 0; } @@ -1283,33 +1217,12 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ case LEXER_LITERAL: { #if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL) + if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL + && lexer_check_arrow (context_p)) { - switch (lexer_check_arrow (context_p)) - { - case LEXER_COMMA: - case LEXER_RIGHT_PAREN: - { - if (context_p->stack_top_uint8 == LEXER_LEFT_PAREN - && parser_check_arrow_function (context_p)) - { - (*grouping_level_p)--; - parser_stack_pop_uint8 (context_p); - return; - } - break; - } - case LEXER_ARROW: - { - parser_parse_function_expression (context_p, - PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION); - return; - } - default: - { - break; - } - } + parser_parse_function_expression (context_p, + PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION); + return; } #endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ @@ -1510,19 +1423,16 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ } #endif /* ENABLED (JERRY_ES2015_CLASS) */ #if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - case LEXER_RIGHT_PAREN: + case LEXER_LEFT_PAREN: { - if (context_p->stack_top_uint8 == LEXER_LEFT_PAREN - && lexer_check_arrow (context_p) == LEXER_ARROW) - { - parser_parse_function_expression (context_p, - PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION | PARSER_ARROW_PARSE_ARGS); + JERRY_ASSERT (context_p->next_scanner_info_p->source_p == context_p->source_p + && context_p->next_scanner_info_p->type == SCANNER_TYPE_ARROW); + scanner_release_next (context_p, sizeof (scanner_info_t)); - (*grouping_level_p)--; - parser_stack_pop_uint8 (context_p); - return; - } - /* FALLTHRU */ + lexer_next_token (context_p); + parser_parse_function_expression (context_p, + PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION | PARSER_ARROW_PARSE_ARGS); + return; } #endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ default: diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index 1fd81e11f..6c2af6d40 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -23,6 +23,7 @@ #include "js-parser.h" #include "js-parser-limits.h" #include "js-lexer.h" +#include "js-scanner.h" #include "ecma-module.h" @@ -362,6 +363,10 @@ typedef struct parser_line_counter_t line; /**< current line */ parser_line_counter_t column; /**< current column */ + /* Scanner members. */ + scanner_info_t *next_scanner_info_p; /**< next scanner info block */ + scanner_info_t *active_scanner_info_p; /**< currently active scanner info block */ + /* Compact byte code members. */ cbc_argument_t last_cbc; /**< argument of the last cbc */ uint16_t last_cbc_opcode; /**< opcode of the last cbc */ @@ -507,11 +512,11 @@ bool lexer_check_next_character (parser_context_t *context_p, lit_utf8_byte_t ch void lexer_skip_empty_statements (parser_context_t *context_p); #endif /* ENABLED (JERRY_ES2015_CLASS) */ #if ENABLED (JERRY_ES2015_ARROW_FUNCTION) -lexer_token_type_t lexer_check_arrow (parser_context_t *context_p); +bool lexer_check_arrow (parser_context_t *context_p); #endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ void lexer_parse_string (parser_context_t *context_p); void lexer_expect_identifier (parser_context_t *context_p, uint8_t literal_type); -void lexer_scan_identifier (parser_context_t *context_p, bool property_name); +void lexer_scan_identifier (parser_context_t *context_p, uint32_t ident_opts); ecma_char_t lexer_hex_to_character (parser_context_t *context_p, const uint8_t *source_p, int length); void lexer_expect_object_literal_id (parser_context_t *context_p, uint32_t ident_opts); void lexer_construct_literal_object (parser_context_t *context_p, lexer_lit_location_t *literal_p, @@ -549,7 +554,22 @@ void parser_parse_super_class_context_end (parser_context_t *context_p, bool is_ * @{ */ -void parser_scan_until (parser_context_t *context_p, lexer_range_t *range_p, lexer_token_type_t end_type); +void scanner_raise_error (parser_context_t *context_p); +void *scanner_malloc (parser_context_t *context_p, size_t size); +void scanner_free (void *ptr, size_t size); + +scanner_info_t *scanner_insert_info (parser_context_t *context_p, const uint8_t *source_p, size_t size); +void scanner_release_next (parser_context_t *context_p, size_t size); +void scanner_set_active (parser_context_t *context_p); +void scanner_release_active (parser_context_t *context_p, size_t size); +void scanner_release_switch_cases (scanner_case_info_t *case_p); +void scanner_reverse_info_list (parser_context_t *context_p); +void scanner_cleanup (parser_context_t *context_p); + +void scanner_get_location (scanner_location_t *location_p, parser_context_t *context_p); +void scanner_set_location (parser_context_t *context_p, scanner_location_t *location_p); + +void scanner_scan_all (parser_context_t *context_p); /** * @} diff --git a/jerry-core/parser/js/js-parser-mem.c b/jerry-core/parser/js/js-parser-mem.c index 9d53eee38..d3fafb6a1 100644 --- a/jerry-core/parser/js/js-parser-mem.c +++ b/jerry-core/parser/js/js-parser-mem.c @@ -52,8 +52,9 @@ parser_malloc (parser_context_t *context_p, /**< context */ /** * Free memory allocated by parser_malloc. */ -void parser_free (void *ptr, /**< pointer to free */ - size_t size) /**< size of the memory block */ +inline void JERRY_ATTR_ALWAYS_INLINE +parser_free (void *ptr, /**< pointer to free */ + size_t size) /**< size of the memory block */ { jmem_heap_free_block (ptr, size); } /* parser_free */ diff --git a/jerry-core/parser/js/js-parser-scanner.c b/jerry-core/parser/js/js-parser-scanner.c deleted file mode 100644 index fe36c11f9..000000000 --- a/jerry-core/parser/js/js-parser-scanner.c +++ /dev/null @@ -1,1030 +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. - */ - -#include "js-parser-internal.h" -#include "lit-char-helpers.h" - -#if ENABLED (JERRY_PARSER) - -/** \addtogroup parser Parser - * @{ - * - * \addtogroup jsparser JavaScript - * @{ - * - * \addtogroup jsparser_scanner Scanner - * @{ - */ - -/** - * Scan mode types types. - */ -typedef enum -{ - SCAN_MODE_PRIMARY_EXPRESSION, /**< scanning primary expression */ - SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW, /**< scanning primary expression after new */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - SCAN_MODE_ARROW_FUNCTION, /**< arrow function might follows */ -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - SCAN_MODE_POST_PRIMARY_EXPRESSION, /**< scanning post primary expression */ - SCAN_MODE_PRIMARY_EXPRESSION_END, /**< scanning primary expression end */ - SCAN_MODE_STATEMENT, /**< scanning statement */ - SCAN_MODE_FUNCTION_ARGUMENTS, /**< scanning function arguments */ - SCAN_MODE_PROPERTY_NAME, /**< scanning property name */ -#if ENABLED (JERRY_ES2015_CLASS) - SCAN_MODE_CLASS_DECLARATION, /**< scanning class declaration */ - SCAN_MODE_CLASS_METHOD, /**< scanning class method */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ -} scan_modes_t; - -/** - * Scan stack mode types types. - */ -typedef enum -{ - SCAN_STACK_HEAD, /**< head */ - SCAN_STACK_PAREN_EXPRESSION, /**< parent expression group */ - SCAN_STACK_PAREN_STATEMENT, /**< parent statement group */ - SCAN_STACK_COLON_EXPRESSION, /**< colon expression group */ - SCAN_STACK_COLON_STATEMENT, /**< colon statement group */ - SCAN_STACK_SQUARE_BRACKETED_EXPRESSION, /**< square bracketed expression group */ - SCAN_STACK_OBJECT_LITERAL, /**< object literal group */ - SCAN_STACK_BLOCK_STATEMENT, /**< block statement group */ - SCAN_STACK_BLOCK_EXPRESSION, /**< block expression group */ - SCAN_STACK_BLOCK_PROPERTY, /**< block property group */ -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) - SCAN_STACK_COMPUTED_PROPERTY, /**< computed property name */ -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) - SCAN_STACK_TEMPLATE_STRING, /**< template string */ -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ -#if ENABLED (JERRY_ES2015_CLASS) - SCAN_STACK_CLASS, /**< class language element */ - SCAN_STACK_CLASS_EXTENDS, /**< class extends expression */ -#endif /* ENABLED (JERRY_ES2015_CLASS) */ -#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) - SCAN_STACK_FUNCTION_PARAMETERS, /**< function parameter initializer */ -#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ -} scan_stack_modes_t; - -/** - * Scan primary expression. - * - * @return true for continue, false for break - */ -static bool -parser_scan_primary_expression (parser_context_t *context_p, /**< context */ - lexer_token_type_t type, /**< current token type */ - scan_stack_modes_t stack_top, /**< current stack top */ - scan_modes_t *mode) /**< scan mode */ -{ - switch (type) - { - case LEXER_KEYW_NEW: - { - *mode = SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW; - break; - } - case LEXER_DIVIDE: - case LEXER_ASSIGN_DIVIDE: - { - lexer_construct_regexp_object (context_p, true); - *mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; - break; - } - case LEXER_KEYW_FUNCTION: - { - parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_EXPRESSION); - *mode = SCAN_MODE_FUNCTION_ARGUMENTS; - break; - } - case LEXER_LEFT_PAREN: - { - parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION); - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - break; - } - case LEXER_LEFT_SQUARE: - { - parser_stack_push_uint8 (context_p, SCAN_STACK_SQUARE_BRACKETED_EXPRESSION); - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - break; - } - case LEXER_LEFT_BRACE: - { - parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); - *mode = SCAN_MODE_PROPERTY_NAME; - return true; - } -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) - case LEXER_TEMPLATE_LITERAL: - { - if (context_p->source_p[-1] != LIT_CHAR_GRAVE_ACCENT) - { - parser_stack_push_uint8 (context_p, SCAN_STACK_TEMPLATE_STRING); - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - break; - } - - /* The string is a normal string literal. */ - /* FALLTHRU */ - } -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ - case LEXER_LITERAL: -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - { - bool is_ident = (context_p->token.lit_location.type == LEXER_IDENT_LITERAL); - - *mode = (is_ident ? SCAN_MODE_ARROW_FUNCTION - : SCAN_MODE_POST_PRIMARY_EXPRESSION); - break; - } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - case LEXER_KEYW_THIS: - case LEXER_LIT_TRUE: - case LEXER_LIT_FALSE: - case LEXER_LIT_NULL: - { - *mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; - break; - } -#if ENABLED (JERRY_ES2015_CLASS) - case LEXER_KEYW_CLASS: - { - parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_EXPRESSION); - *mode = SCAN_MODE_CLASS_DECLARATION; - break; - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - case LEXER_RIGHT_SQUARE: - { - if (stack_top != SCAN_STACK_SQUARE_BRACKETED_EXPRESSION) - { - parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED); - } - parser_stack_pop_uint8 (context_p); - *mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; - break; - } - case LEXER_COMMA: - { - if (stack_top != SCAN_STACK_SQUARE_BRACKETED_EXPRESSION) - { - parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED); - } - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - break; - } - case LEXER_RIGHT_PAREN: - { -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - *mode = SCAN_MODE_ARROW_FUNCTION; -#else /* !ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - *mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - - if (stack_top == SCAN_STACK_PAREN_STATEMENT) - { - *mode = SCAN_MODE_STATEMENT; - } - else if (stack_top != SCAN_STACK_PAREN_EXPRESSION) - { - parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED); - } - - parser_stack_pop_uint8 (context_p); - break; - } - case LEXER_SEMICOLON: - { - /* Needed by for (;;) statements. */ - if (stack_top != SCAN_STACK_PAREN_STATEMENT) - { - parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED); - } - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - break; - } - default: - { - parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED); - } - } - return false; -} /* parser_scan_primary_expression */ - -/** - * Scan the tokens after the primary expression. - * - * @return true for break, false for fall through - */ -static bool -parser_scan_post_primary_expression (parser_context_t *context_p, /**< context */ - lexer_token_type_t type, /**< current token type */ - scan_modes_t *mode) /**< scan mode */ -{ - switch (type) - { - case LEXER_DOT: - { - lexer_scan_identifier (context_p, false); - return true; - } - case LEXER_LEFT_PAREN: - { - parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION); - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - return true; - } - case LEXER_LEFT_SQUARE: - { - parser_stack_push_uint8 (context_p, SCAN_STACK_SQUARE_BRACKETED_EXPRESSION); - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - return true; - } - case LEXER_INCREASE: - case LEXER_DECREASE: - { - if (!(context_p->token.flags & LEXER_WAS_NEWLINE)) - { - *mode = SCAN_MODE_PRIMARY_EXPRESSION_END; - return true; - } - /* FALLTHRU */ - } - default: - { - break; - } - } - - return false; -} /* parser_scan_post_primary_expression */ - -/** - * Scan the tokens after the primary expression. - * - * @return true for continue, false for break - */ -static bool -parser_scan_primary_expression_end (parser_context_t *context_p, /**< context */ - lexer_token_type_t type, /**< current token type */ - scan_stack_modes_t stack_top, /**< current stack top */ - lexer_token_type_t end_type, /**< terminator token type */ - scan_modes_t *mode) /**< scan mode */ -{ - switch (type) - { - case LEXER_QUESTION_MARK: - { - parser_stack_push_uint8 (context_p, SCAN_STACK_COLON_EXPRESSION); - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - return false; - } - case LEXER_COMMA: - { - if (stack_top == SCAN_STACK_OBJECT_LITERAL) - { - *mode = SCAN_MODE_PROPERTY_NAME; - return true; - } - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - return false; - } - case LEXER_COLON: - { - if (stack_top == SCAN_STACK_COLON_EXPRESSION - || stack_top == SCAN_STACK_COLON_STATEMENT) - { - if (stack_top == SCAN_STACK_COLON_EXPRESSION) - { - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - } - else - { - *mode = SCAN_MODE_STATEMENT; - } - parser_stack_pop_uint8 (context_p); - return false; - } - /* FALLTHRU */ - } - default: - { - break; - } - } - - if (LEXER_IS_BINARY_OP_TOKEN (type) - || (type == LEXER_SEMICOLON && stack_top == SCAN_STACK_PAREN_STATEMENT)) - { - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - return false; - } - - if ((type == LEXER_RIGHT_SQUARE && stack_top == SCAN_STACK_SQUARE_BRACKETED_EXPRESSION) - || (type == LEXER_RIGHT_PAREN && stack_top == SCAN_STACK_PAREN_EXPRESSION) -#if ENABLED (JERRY_ES2015_CLASS) - || (type == LEXER_LEFT_BRACE && stack_top == SCAN_STACK_CLASS_EXTENDS) -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - || (type == LEXER_RIGHT_BRACE && stack_top == SCAN_STACK_OBJECT_LITERAL)) - { - parser_stack_pop_uint8 (context_p); - *mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - if (type == LEXER_RIGHT_PAREN) - { - *mode = SCAN_MODE_ARROW_FUNCTION; - } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ -#if ENABLED (JERRY_ES2015_CLASS) - if (stack_top == SCAN_STACK_CLASS_EXTENDS) - { - *mode = SCAN_MODE_CLASS_METHOD; - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - return false; - } - -#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) - if (type == LEXER_RIGHT_BRACE && stack_top == SCAN_STACK_TEMPLATE_STRING) - { - context_p->source_p--; - context_p->column--; - lexer_parse_string (context_p); - - if (context_p->source_p[-1] != LIT_CHAR_GRAVE_ACCENT) - { - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - } - else - { - parser_stack_pop_uint8 (context_p); - *mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; - } - return false; - } -#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ - - *mode = SCAN_MODE_STATEMENT; - if (type == LEXER_RIGHT_PAREN && stack_top == SCAN_STACK_PAREN_STATEMENT) - { - parser_stack_pop_uint8 (context_p); - return false; - } - -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) - if (context_p->token.type == LEXER_RIGHT_SQUARE && stack_top == SCAN_STACK_COMPUTED_PROPERTY) - { - lexer_next_token (context_p); - - parser_stack_pop_uint8 (context_p); - stack_top = (scan_stack_modes_t) context_p->stack_top_uint8; - - if (stack_top == SCAN_STACK_BLOCK_PROPERTY) - { - if (context_p->token.type != LEXER_LEFT_PAREN) - { - parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIST_EXPECTED); - } - - *mode = SCAN_MODE_FUNCTION_ARGUMENTS; - return true; - } - - JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL); - - if (context_p->token.type == LEXER_LEFT_PAREN) - { - parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_PROPERTY); - *mode = SCAN_MODE_FUNCTION_ARGUMENTS; - return true; - } - - if (context_p->token.type != LEXER_COLON) - { - parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED); - } - - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - return false; - } -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ - -#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) - if (context_p->token.type == LEXER_RIGHT_PAREN && stack_top == SCAN_STACK_FUNCTION_PARAMETERS) - { - lexer_next_token (context_p); - - parser_stack_pop_uint8 (context_p); - - if (context_p->token.type != LEXER_LEFT_BRACE) - { - parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED); - } - *mode = SCAN_MODE_STATEMENT; - return false; - } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ - - /* Check whether we can enter to statement mode. */ - if (stack_top != SCAN_STACK_BLOCK_STATEMENT - && stack_top != SCAN_STACK_BLOCK_EXPRESSION - && stack_top != SCAN_STACK_BLOCK_PROPERTY -#if ENABLED (JERRY_ES2015_CLASS) - && stack_top != SCAN_STACK_CLASS -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - && !(stack_top == SCAN_STACK_HEAD && end_type == LEXER_SCAN_SWITCH)) - { - parser_raise_error (context_p, PARSER_ERR_INVALID_EXPRESSION); - } - - if (type == LEXER_RIGHT_BRACE - || (context_p->token.flags & LEXER_WAS_NEWLINE)) - { - return true; - } - - if (type != LEXER_SEMICOLON) - { - parser_raise_error (context_p, PARSER_ERR_INVALID_EXPRESSION); - } - - return false; -} /* parser_scan_primary_expression_end */ - -/** - * Scan statements. - * - * @return true for continue, false for break - */ -static bool -parser_scan_statement (parser_context_t *context_p, /**< context */ - lexer_token_type_t type, /**< current token type */ - scan_stack_modes_t stack_top, /**< current stack top */ - scan_modes_t *mode) /**< scan mode */ -{ - switch (type) - { - case LEXER_SEMICOLON: - case LEXER_KEYW_ELSE: - case LEXER_KEYW_DO: - case LEXER_KEYW_TRY: - case LEXER_KEYW_FINALLY: - case LEXER_KEYW_DEBUGGER: - { - return false; - } - case LEXER_KEYW_IF: - case LEXER_KEYW_WHILE: - case LEXER_KEYW_WITH: - case LEXER_KEYW_SWITCH: - case LEXER_KEYW_CATCH: - { - lexer_next_token (context_p); - if (context_p->token.type != LEXER_LEFT_PAREN) - { - parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED); - } - - parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_STATEMENT); - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - return false; - } - case LEXER_KEYW_FOR: - { - lexer_next_token (context_p); - if (context_p->token.type != LEXER_LEFT_PAREN) - { - parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED); - } - - lexer_next_token (context_p); - parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_STATEMENT); - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - - if (context_p->token.type == LEXER_KEYW_VAR) - { - return false; - } - return true; - } - case LEXER_KEYW_VAR: - case LEXER_KEYW_THROW: - { - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - return false; - } - case LEXER_KEYW_RETURN: - { - lexer_next_token (context_p); - if (!(context_p->token.flags & LEXER_WAS_NEWLINE) - && context_p->token.type != LEXER_SEMICOLON - && context_p->token.type != LEXER_RIGHT_BRACE) - { - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - } - return true; - } - case LEXER_KEYW_BREAK: - case LEXER_KEYW_CONTINUE: - { - lexer_next_token (context_p); - if (!(context_p->token.flags & LEXER_WAS_NEWLINE) - && context_p->token.type == LEXER_LITERAL - && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) - { - return false; - } - return true; - } - case LEXER_KEYW_DEFAULT: - { - lexer_next_token (context_p); - if (context_p->token.type != LEXER_COLON) - { - parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED); - } - return false; - } - case LEXER_KEYW_CASE: - { - parser_stack_push_uint8 (context_p, SCAN_STACK_COLON_STATEMENT); - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - return false; - } - case LEXER_RIGHT_BRACE: - { - if (stack_top == SCAN_STACK_BLOCK_STATEMENT - || stack_top == SCAN_STACK_BLOCK_EXPRESSION -#if ENABLED (JERRY_ES2015_CLASS) - || stack_top == SCAN_STACK_CLASS -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - || stack_top == SCAN_STACK_BLOCK_PROPERTY) - { - parser_stack_pop_uint8 (context_p); - - if (stack_top == SCAN_STACK_BLOCK_EXPRESSION) - { - *mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; - } -#if ENABLED (JERRY_ES2015_CLASS) - else if (stack_top == SCAN_STACK_CLASS) - { - *mode = SCAN_MODE_CLASS_METHOD; - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - else if (stack_top == SCAN_STACK_BLOCK_PROPERTY) - { - *mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; - lexer_next_token (context_p); - if (context_p->token.type != LEXER_COMMA - && context_p->token.type != LEXER_RIGHT_BRACE) - { - parser_raise_error (context_p, PARSER_ERR_OBJECT_ITEM_SEPARATOR_EXPECTED); - } - return true; - } - return false; - } - break; - } - case LEXER_LEFT_BRACE: - { - parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT); - return false; - } - case LEXER_KEYW_FUNCTION: - { - parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT); - *mode = SCAN_MODE_FUNCTION_ARGUMENTS; - return false; - } -#if ENABLED (JERRY_ES2015_CLASS) - case LEXER_KEYW_CLASS: - { - parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT); - *mode = SCAN_MODE_CLASS_DECLARATION; - return false; - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - default: - { - break; - } - } - - *mode = SCAN_MODE_PRIMARY_EXPRESSION; - - if (type == LEXER_LITERAL - && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) - { - lexer_next_token (context_p); - if (context_p->token.type == LEXER_COLON) - { - *mode = SCAN_MODE_STATEMENT; - return false; - } -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - *mode = SCAN_MODE_ARROW_FUNCTION; -#else /* !ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - *mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - } - - return true; -} /* parser_scan_statement */ - -/** - * Pre-scan for token(s). - */ -void -parser_scan_until (parser_context_t *context_p, /**< context */ - lexer_range_t *range_p, /**< destination range */ - lexer_token_type_t end_type) /**< terminator token type */ -{ - scan_modes_t mode; - lexer_token_type_t end_type_b = end_type; - - range_p->source_p = context_p->source_p; - range_p->source_end_p = context_p->source_p; - range_p->line = context_p->line; - range_p->column = context_p->column; - - mode = SCAN_MODE_PRIMARY_EXPRESSION; - - if (end_type == LEXER_KEYW_CASE) - { - end_type = LEXER_SCAN_SWITCH; - end_type_b = LEXER_SCAN_SWITCH; - mode = SCAN_MODE_STATEMENT; - } - else - { - lexer_next_token (context_p); - -#if ENABLED (JERRY_ES2015_FOR_OF) - lexer_token_type_t for_in_of_token = LEXER_FOR_IN_OF; -#else /* !ENABLED (JERRY_ES2015_FOR_OF) */ - lexer_token_type_t for_in_of_token = LEXER_KEYW_IN; -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ - - if (end_type == for_in_of_token) - { - end_type_b = LEXER_SEMICOLON; - if (context_p->token.type == LEXER_KEYW_VAR) - { - lexer_next_token (context_p); - } - } - } - - parser_stack_push_uint8 (context_p, SCAN_STACK_HEAD); - - while (true) - { - lexer_token_type_t type = (lexer_token_type_t) context_p->token.type; - scan_stack_modes_t stack_top = (scan_stack_modes_t) context_p->stack_top_uint8; - - if (type == LEXER_EOS) - { - parser_raise_error (context_p, PARSER_ERR_EXPRESSION_EXPECTED); - } - - if (stack_top == SCAN_STACK_HEAD) - { - if (type == end_type || type == end_type_b) - { - parser_stack_pop_uint8 (context_p); - return; - } - -#if ENABLED (JERRY_ES2015_FOR_OF) - if (end_type == LEXER_FOR_IN_OF) - { - if (type == LEXER_KEYW_IN) - { - parser_stack_pop_uint8 (context_p); - context_p->token.type = LEXER_KEYW_IN; - return; - } - else if (lexer_compare_literal_to_identifier (context_p, "of", 2)) - { - parser_stack_pop_uint8 (context_p); - context_p->token.type = LEXER_LITERAL_OF; - return; - } - } -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ - } - - switch (mode) - { - case SCAN_MODE_PRIMARY_EXPRESSION: - { - if (type == LEXER_ADD - || type == LEXER_SUBTRACT - || LEXER_IS_UNARY_OP_TOKEN (type)) - { - break; - } - /* FALLTHRU */ - } - case SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW: - { - if (parser_scan_primary_expression (context_p, type, stack_top, &mode)) - { - continue; - } - break; - } -#if ENABLED (JERRY_ES2015_CLASS) - case SCAN_MODE_CLASS_DECLARATION: - { - if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) - { - lexer_next_token (context_p); - } - - if (context_p->token.type == LEXER_KEYW_EXTENDS) - { - parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_EXTENDS); - mode = SCAN_MODE_PRIMARY_EXPRESSION; - break; - } - else if (context_p->token.type != LEXER_LEFT_BRACE) - { - parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED); - } - - mode = SCAN_MODE_CLASS_METHOD; - break; - } - case SCAN_MODE_CLASS_METHOD: - { - if (type == LEXER_SEMICOLON) - { - break; - } - - if (type == LEXER_RIGHT_BRACE - && (stack_top == SCAN_STACK_BLOCK_STATEMENT - || stack_top == SCAN_STACK_BLOCK_EXPRESSION)) - { - mode = (stack_top == SCAN_STACK_BLOCK_EXPRESSION) ? SCAN_MODE_PRIMARY_EXPRESSION_END : SCAN_MODE_STATEMENT; - parser_stack_pop_uint8 (context_p); - break; - } - - if (lexer_compare_literal_to_identifier (context_p, "static", 6)) - { - lexer_next_token (context_p); - } - - if (lexer_compare_literal_to_identifier (context_p, "get", 3) - || lexer_compare_literal_to_identifier (context_p, "set", 3)) - { - lexer_next_token (context_p); - } - - parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS); - mode = SCAN_MODE_FUNCTION_ARGUMENTS; - continue; - } -#endif /* ENABLED (JERRY_ES2015_CLASS) */ -#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) - case SCAN_MODE_ARROW_FUNCTION: - { - if (type == LEXER_ARROW) - { - lexer_next_token (context_p); - - if (context_p->token.type == LEXER_LEFT_BRACE) - { - parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_EXPRESSION); - mode = SCAN_MODE_STATEMENT; - } - else - { - mode = SCAN_MODE_PRIMARY_EXPRESSION; - range_p->source_end_p = context_p->source_p; - continue; - } - break; - } - mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; - /* FALLTHRU */ - } -#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ - case SCAN_MODE_POST_PRIMARY_EXPRESSION: - { - if (parser_scan_post_primary_expression (context_p, type, &mode)) - { - break; - } - /* FALLTHRU */ - } - case SCAN_MODE_PRIMARY_EXPRESSION_END: - { - if (parser_scan_primary_expression_end (context_p, type, stack_top, end_type, &mode)) - { - continue; - } - break; - } - case SCAN_MODE_STATEMENT: - { - if (end_type == LEXER_SCAN_SWITCH - && stack_top == SCAN_STACK_HEAD - && (type == LEXER_KEYW_DEFAULT || type == LEXER_KEYW_CASE || type == LEXER_RIGHT_BRACE)) - { - parser_stack_pop_uint8 (context_p); - return; - } - - if (parser_scan_statement (context_p, type, stack_top, &mode)) - { - continue; - } - break; - } - case SCAN_MODE_FUNCTION_ARGUMENTS: - { -#if ENABLED (JERRY_ES2015_CLASS) - JERRY_ASSERT (stack_top == SCAN_STACK_BLOCK_STATEMENT - || stack_top == SCAN_STACK_BLOCK_EXPRESSION - || stack_top == SCAN_STACK_CLASS - || stack_top == SCAN_STACK_BLOCK_PROPERTY); -#else /* !ENABLED (JERRY_ES2015_CLASS) */ - JERRY_ASSERT (stack_top == SCAN_STACK_BLOCK_STATEMENT - || stack_top == SCAN_STACK_BLOCK_EXPRESSION - || stack_top == SCAN_STACK_BLOCK_PROPERTY); -#endif /* ENABLED (JERRY_ES2015_CLASS) */ - - if (context_p->token.type == LEXER_LITERAL - && (context_p->token.lit_location.type == LEXER_IDENT_LITERAL - || context_p->token.lit_location.type == LEXER_STRING_LITERAL - || context_p->token.lit_location.type == LEXER_NUMBER_LITERAL)) - { - lexer_next_token (context_p); - } - - if (context_p->token.type != LEXER_LEFT_PAREN) - { - parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIST_EXPECTED); - } - lexer_next_token (context_p); - - if (context_p->token.type != LEXER_RIGHT_PAREN) - { - while (true) - { -#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) - if (context_p->token.type == LEXER_THREE_DOTS) - { - lexer_next_token (context_p); - } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ - - if (context_p->token.type != LEXER_LITERAL - || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) - { - parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); - } - lexer_next_token (context_p); - - if (context_p->token.type != LEXER_COMMA) - { - break; - } - lexer_next_token (context_p); - } - } - -#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) - if (context_p->token.type == LEXER_ASSIGN) - { - parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PARAMETERS); - mode = SCAN_MODE_PRIMARY_EXPRESSION; - break; - } -#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ - - if (context_p->token.type != LEXER_RIGHT_PAREN) - { - parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED); - } - - lexer_next_token (context_p); - - if (context_p->token.type != LEXER_LEFT_BRACE) - { - parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED); - } - mode = SCAN_MODE_STATEMENT; - break; - } - case SCAN_MODE_PROPERTY_NAME: - { - JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL); - - lexer_scan_identifier (context_p, true); - -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) - if (context_p->token.type == LEXER_LEFT_SQUARE) - { - parser_stack_push_uint8 (context_p, SCAN_STACK_COMPUTED_PROPERTY); - mode = SCAN_MODE_PRIMARY_EXPRESSION; - break; - } -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ - - if (context_p->token.type == LEXER_RIGHT_BRACE) - { - parser_stack_pop_uint8 (context_p); - mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; - break; - } - - if (context_p->token.type == LEXER_PROPERTY_GETTER - || context_p->token.type == LEXER_PROPERTY_SETTER) - { - lexer_next_token (context_p); - - parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_PROPERTY); - -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) - if (context_p->token.type == LEXER_LEFT_SQUARE) - { - parser_stack_push_uint8 (context_p, SCAN_STACK_COMPUTED_PROPERTY); - mode = SCAN_MODE_PRIMARY_EXPRESSION; - break; - } -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ - - if (context_p->token.type != LEXER_LITERAL) - { - parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); - } - - mode = SCAN_MODE_FUNCTION_ARGUMENTS; - continue; - } - - lexer_next_token (context_p); - -#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) - if (context_p->token.type == LEXER_LEFT_PAREN) - { - parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_PROPERTY); - mode = SCAN_MODE_FUNCTION_ARGUMENTS; - continue; - } - - if (context_p->token.type == LEXER_COMMA) - { - continue; - } - - if (context_p->token.type == LEXER_RIGHT_BRACE) - { - parser_stack_pop_uint8 (context_p); - mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; - break; - } -#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ - - if (context_p->token.type != LEXER_COLON) - { - parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED); - } - - mode = SCAN_MODE_PRIMARY_EXPRESSION; - break; - } - } - - range_p->source_end_p = context_p->source_p; - lexer_next_token (context_p); - } -} /* parser_scan_until */ - -/** - * @} - * @} - * @} - */ - -#endif /* ENABLED (JERRY_PARSER) */ diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 4547a8ac6..f482bad5d 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -133,7 +133,7 @@ typedef struct typedef struct { parser_branch_t branch; /**< branch to the end */ - lexer_range_t condition_range; /**< condition part */ + scanner_location_t condition_location; /**< condition part */ uint32_t start_offset; /**< start byte code offset */ } parser_while_statement_t; @@ -143,8 +143,8 @@ typedef struct typedef struct { parser_branch_t branch; /**< branch to the end */ - lexer_range_t condition_range; /**< condition part */ - lexer_range_t expression_range; /**< increase part */ + scanner_location_t condition_location; /**< condition part */ + scanner_location_t expression_location; /**< expression part */ uint32_t start_offset; /**< start byte code offset */ } parser_for_statement_t; @@ -155,18 +155,7 @@ typedef struct { parser_branch_t branch; /**< branch to the end */ uint32_t start_offset; /**< start byte code offset */ -} parser_for_in_statement_t; - -#if ENABLED (JERRY_ES2015_FOR_OF) -/** - * For-of statement. - */ -typedef struct -{ - parser_branch_t branch; /**< branch to the end */ - uint32_t start_offset; /**< start byte code offset */ -} parser_for_of_statement_t; -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ +} parser_for_in_of_statement_t; /** * With statement. @@ -225,10 +214,10 @@ parser_statement_length (uint8_t type) /**< type of statement */ /* PARSER_STATEMENT_FOR */ (uint8_t) (sizeof (parser_for_statement_t) + sizeof (parser_loop_statement_t) + 1), /* PARSER_STATEMENT_FOR_IN */ - (uint8_t) (sizeof (parser_for_in_statement_t) + sizeof (parser_loop_statement_t) + 1), + (uint8_t) (sizeof (parser_for_in_of_statement_t) + sizeof (parser_loop_statement_t) + 1), #if ENABLED (JERRY_ES2015_FOR_OF) /* PARSER_STATEMENT_FOR_OF */ - (uint8_t) (sizeof (parser_for_of_statement_t) + sizeof (parser_loop_statement_t) + 1), + (uint8_t) (sizeof (parser_for_in_of_statement_t) + sizeof (parser_loop_statement_t) + 1), #endif /* ENABLED (JERRY_ES2015_FOR_OF) */ /* PARSER_STATEMENT_WITH */ (uint8_t) (sizeof (parser_with_statement_t) + 1), @@ -735,6 +724,12 @@ parser_parse_do_while_statement_end (parser_context_t *context_p) /**< context * parser_set_continues_to_current_position (context_p, loop.branch_list_p); + /* FIXME: These statements should not have scanner info. */ + if (context_p->next_scanner_info_p->type == SCANNER_TYPE_WHILE) + { + scanner_release_next (context_p, sizeof (scanner_location_info_t)); + } + parser_parse_enclosed_expr (context_p); if (context_p->last_cbc_opcode != CBC_PUSH_FALSE) @@ -785,13 +780,28 @@ parser_parse_while_statement_start (parser_context_t *context_p) /**< context */ parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED); } + JERRY_ASSERT (context_p->next_scanner_info_p->source_p != context_p->source_p + || context_p->next_scanner_info_p->type == SCANNER_TYPE_WHILE); + + if (context_p->next_scanner_info_p->source_p != context_p->source_p) + { + /* The prescanner couldn't find the end of the while condition. */ + lexer_next_token (context_p); + parser_parse_expression (context_p, PARSE_EXPR); + + JERRY_ASSERT (context_p->token.type != LEXER_RIGHT_PAREN); + parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED); + } + parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &while_statement.branch); JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE); - while_statement.start_offset = context_p->byte_code_size; - /* The conditional part is processed at the end. */ - parser_scan_until (context_p, &while_statement.condition_range, LEXER_RIGHT_PAREN); + while_statement.start_offset = context_p->byte_code_size; + scanner_get_location (&while_statement.condition_location, context_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)); lexer_next_token (context_p); loop.branch_list_p = NULL; @@ -811,7 +821,7 @@ parser_parse_while_statement_end (parser_context_t *context_p) /**< context */ parser_while_statement_t while_statement; parser_loop_statement_t loop; lexer_token_t current_token; - lexer_range_t range; + scanner_location_t location; cbc_opcode_t opcode; JERRY_ASSERT (context_p->stack_top_uint8 == PARSER_STATEMENT_WHILE); @@ -824,19 +834,19 @@ parser_parse_while_statement_end (parser_context_t *context_p) /**< context */ parser_stack_iterator_skip (&iterator, sizeof (parser_loop_statement_t)); parser_stack_iterator_read (&iterator, &while_statement, sizeof (parser_while_statement_t)); - parser_save_range (context_p, &range, context_p->source_end_p); + scanner_get_location (&location, context_p); current_token = context_p->token; parser_set_branch_to_current_position (context_p, &while_statement.branch); parser_set_continues_to_current_position (context_p, loop.branch_list_p); - parser_set_range (context_p, &while_statement.condition_range); + scanner_set_location (context_p, &while_statement.condition_location); lexer_next_token (context_p); parser_parse_expression (context_p, PARSE_EXPR); - if (context_p->token.type != LEXER_EOS) + if (context_p->token.type != LEXER_RIGHT_PAREN) { - parser_raise_error (context_p, PARSER_ERR_INVALID_EXPRESSION); + parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED); } opcode = CBC_BRANCH_IF_TRUE_BACKWARD; @@ -857,7 +867,7 @@ parser_parse_while_statement_end (parser_context_t *context_p) /**< context */ parser_emit_cbc_backward_branch (context_p, (uint16_t) opcode, while_statement.start_offset); parser_set_breaks_to_current_position (context_p, loop.branch_list_p); - parser_set_range (context_p, &range); + scanner_set_location (context_p, &location); context_p->token = current_token; } /* parser_parse_while_statement_end */ @@ -914,7 +924,6 @@ static void parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ { parser_loop_statement_t loop; - lexer_range_t start_range; JERRY_ASSERT (context_p->token.type == LEXER_KEYW_FOR); lexer_next_token (context_p); @@ -924,18 +933,29 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED); } + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + parser_for_in_of_statement_t for_in_of_statement; + scanner_location_t start_location; + lexer_range_t end_range; + #if ENABLED (JERRY_ES2015_FOR_OF) - lexer_token_type_t scan_token = LEXER_FOR_IN_OF; + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN + || context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_OF); + + bool is_for_in = (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN); #else /* !ENABLED (JERRY_ES2015_FOR_OF) */ - lexer_token_type_t scan_token = LEXER_KEYW_IN; + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN); + + bool is_for_in = true; #endif /* ENABLED (JERRY_ES2015_FOR_OF) */ - parser_scan_until (context_p, &start_range, scan_token); + scanner_get_location (&start_location, context_p); + scanner_set_location (context_p, &((scanner_location_info_t *) context_p->next_scanner_info_p)->location); + /* The length of both 'in' and 'of' is two. */ + const uint8_t *source_end_p = context_p->source_p - 2; - if (context_p->token.type == LEXER_KEYW_IN) - { - parser_for_in_statement_t for_in_statement; - lexer_range_t range; + scanner_release_next (context_p, sizeof (scanner_location_info_t)); lexer_next_token (context_p); parser_parse_expression (context_p, PARSE_EXPR); @@ -946,18 +966,23 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ } #ifndef JERRY_NDEBUG - PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION); + PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, + is_for_in ? PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION + : PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION); #endif /* !JERRY_NDEBUG */ parser_emit_cbc_ext_forward_branch (context_p, - CBC_EXT_FOR_IN_CREATE_CONTEXT, - &for_in_statement.branch); + is_for_in ? CBC_EXT_FOR_IN_CREATE_CONTEXT + : CBC_EXT_FOR_OF_CREATE_CONTEXT, + &for_in_of_statement.branch); JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE); - for_in_statement.start_offset = context_p->byte_code_size; + for_in_of_statement.start_offset = context_p->byte_code_size; - parser_save_range (context_p, &range, context_p->source_end_p); - parser_set_range (context_p, &start_range); + /* The expression parser must not read the 'in' or 'of' tokens. */ + parser_save_range (context_p, &end_range, context_p->source_end_p); + scanner_set_location (context_p, &start_location); + context_p->source_end_p = source_end_p; lexer_next_token (context_p); if (context_p->token.type == LEXER_KEYW_VAR) @@ -986,7 +1011,8 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ parser_set_branch_to_current_position (context_p, &branch); } - parser_emit_cbc_ext (context_p, CBC_EXT_FOR_IN_GET_NEXT); + parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT + : CBC_EXT_FOR_OF_GET_NEXT); parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index); } else @@ -1003,7 +1029,8 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ opcode = parser_check_left_hand_side_expression (context_p, opcode); - parser_emit_cbc_ext (context_p, CBC_EXT_FOR_IN_GET_NEXT); + parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT + : CBC_EXT_FOR_OF_GET_NEXT); parser_flush_cbc (context_p); context_p->last_cbc_opcode = opcode; @@ -1011,157 +1038,93 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */ if (context_p->token.type != LEXER_EOS) { +#if ENABLED (JERRY_ES2015_FOR_OF) + parser_raise_error (context_p, is_for_in ? PARSER_ERR_IN_EXPECTED : PARSER_ERR_OF_EXPECTED); +#else /* !ENABLED (JERRY_ES2015_FOR_OF) */ parser_raise_error (context_p, PARSER_ERR_IN_EXPECTED); +#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ } parser_flush_cbc (context_p); - parser_set_range (context_p, &range); + parser_set_range (context_p, &end_range); lexer_next_token (context_p); loop.branch_list_p = NULL; - parser_stack_push (context_p, &for_in_statement, sizeof (parser_for_in_statement_t)); + parser_stack_push (context_p, &for_in_of_statement, sizeof (parser_for_in_of_statement_t)); parser_stack_push (context_p, &loop, sizeof (parser_loop_statement_t)); - parser_stack_push_uint8 (context_p, PARSER_STATEMENT_FOR_IN); - parser_stack_iterator_init (context_p, &context_p->last_statement); - } #if ENABLED (JERRY_ES2015_FOR_OF) - else if (context_p->token.type == LEXER_LITERAL_OF) + parser_stack_push_uint8 (context_p, is_for_in ? PARSER_STATEMENT_FOR_IN + : PARSER_STATEMENT_FOR_OF); +#else /* !ENABLED (JERRY_ES2015_FOR_OF) */ + parser_stack_push_uint8 (context_p, PARSER_STATEMENT_FOR_IN); +#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ + parser_stack_iterator_init (context_p, &context_p->last_statement); + return; + } + + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_SEMICOLON) { - parser_for_of_statement_t for_of_statement; - lexer_range_t range; - - lexer_next_token (context_p); - parser_parse_expression (context_p, PARSE_EXPR); - - if (context_p->token.type != LEXER_RIGHT_PAREN) - { - parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED); - } - -#ifndef JERRY_NDEBUG - PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION); -#endif /* !JERRY_NDEBUG */ - - parser_emit_cbc_ext_forward_branch (context_p, - CBC_EXT_FOR_OF_CREATE_CONTEXT, - &for_of_statement.branch); - - JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE); - for_of_statement.start_offset = context_p->byte_code_size; - - parser_save_range (context_p, &range, context_p->source_end_p); - parser_set_range (context_p, &start_range); - lexer_next_token (context_p); - if (context_p->token.type == LEXER_KEYW_VAR) { - uint16_t literal_index; - - lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL); - JERRY_ASSERT (context_p->token.type == LEXER_LITERAL - && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); - - context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR; - - literal_index = context_p->lit_object.index; - - lexer_next_token (context_p); - - if (context_p->token.type == LEXER_ASSIGN) - { - parser_branch_t branch; - - /* Initialiser is never executed. */ - parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &branch); - lexer_next_token (context_p); - parser_parse_expression (context_p, - PARSE_EXPR_STATEMENT | PARSE_EXPR_NO_COMMA); - parser_set_branch_to_current_position (context_p, &branch); - } - - parser_emit_cbc_ext (context_p, CBC_EXT_FOR_OF_GET_NEXT); - parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index); + parser_parse_var_statement (context_p); } else { - uint16_t opcode; - - parser_parse_expression (context_p, PARSE_EXPR); - - opcode = context_p->last_cbc_opcode; - - /* The CBC_EXT_FOR_OF_CREATE_CONTEXT flushed the opcode combiner. */ - JERRY_ASSERT (opcode != CBC_PUSH_TWO_LITERALS - && opcode != CBC_PUSH_THREE_LITERALS); - - opcode = parser_check_left_hand_side_expression (context_p, opcode); - - parser_emit_cbc_ext (context_p, CBC_EXT_FOR_OF_GET_NEXT); - parser_flush_cbc (context_p); - - context_p->last_cbc_opcode = opcode; + parser_parse_expression (context_p, PARSE_EXPR_STATEMENT); } - if (context_p->token.type != LEXER_EOS) - { - parser_raise_error (context_p, PARSER_ERR_OF_EXPECTED); - } - - parser_flush_cbc (context_p); - parser_set_range (context_p, &range); - lexer_next_token (context_p); - - loop.branch_list_p = NULL; - - parser_stack_push (context_p, &for_of_statement, sizeof (parser_for_of_statement_t)); - parser_stack_push (context_p, &loop, sizeof (parser_loop_statement_t)); - parser_stack_push_uint8 (context_p, PARSER_STATEMENT_FOR_OF); - parser_stack_iterator_init (context_p, &context_p->last_statement); - } -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ - else - { - parser_for_statement_t for_statement; - - start_range.source_end_p = context_p->source_end_p; - parser_set_range (context_p, &start_range); - lexer_next_token (context_p); - if (context_p->token.type != LEXER_SEMICOLON) { - if (context_p->token.type == LEXER_KEYW_VAR) - { - parser_parse_var_statement (context_p); - } - else - { - parser_parse_expression (context_p, PARSE_EXPR_STATEMENT); - } + parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED); + } + } - if (context_p->token.type != LEXER_SEMICOLON) - { - parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED); - } + JERRY_ASSERT (context_p->next_scanner_info_p->source_p != context_p->source_p + || context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR); + + if (context_p->next_scanner_info_p->source_p != context_p->source_p + || ((scanner_for_info_t *) context_p->next_scanner_info_p)->end_location.source_p == NULL) + { + /* The prescanner couldn't find the second semicolon or the closing paranthesis. */ + lexer_next_token (context_p); + parser_parse_expression (context_p, PARSE_EXPR); + + if (context_p->token.type != LEXER_SEMICOLON) + { + parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED); } - parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &for_statement.branch); - - JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE); - for_statement.start_offset = context_p->byte_code_size; - - /* The conditional and expression parts are processed at the end. */ - parser_scan_until (context_p, &for_statement.condition_range, LEXER_SEMICOLON); - parser_scan_until (context_p, &for_statement.expression_range, LEXER_RIGHT_PAREN); lexer_next_token (context_p); + parser_parse_expression (context_p, PARSE_EXPR_STATEMENT); - loop.branch_list_p = NULL; - - parser_stack_push (context_p, &for_statement, sizeof (parser_for_statement_t)); - parser_stack_push (context_p, &loop, sizeof (parser_loop_statement_t)); - parser_stack_push_uint8 (context_p, PARSER_STATEMENT_FOR); - parser_stack_iterator_init (context_p, &context_p->last_statement); + JERRY_ASSERT (context_p->token.type != LEXER_RIGHT_PAREN); + parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED); } + + parser_for_statement_t for_statement; + scanner_for_info_t *for_info_p = (scanner_for_info_t *) context_p->next_scanner_info_p; + + parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &for_statement.branch); + + JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE); + + for_statement.start_offset = context_p->byte_code_size; + scanner_get_location (&for_statement.condition_location, context_p); + for_statement.expression_location = for_info_p->expression_location; + + scanner_set_location (context_p, &for_info_p->end_location); + scanner_release_next (context_p, sizeof (parser_for_statement_t)); + lexer_next_token (context_p); + + loop.branch_list_p = NULL; + + parser_stack_push (context_p, &for_statement, sizeof (parser_for_statement_t)); + parser_stack_push (context_p, &loop, sizeof (parser_loop_statement_t)); + parser_stack_push_uint8 (context_p, PARSER_STATEMENT_FOR); + parser_stack_iterator_init (context_p, &context_p->last_statement); } /* parser_parse_for_statement_start */ /** @@ -1173,7 +1136,7 @@ parser_parse_for_statement_end (parser_context_t *context_p) /**< context */ parser_for_statement_t for_statement; parser_loop_statement_t loop; lexer_token_t current_token; - lexer_range_t range; + scanner_location_t location; cbc_opcode_t opcode; JERRY_ASSERT (context_p->stack_top_uint8 == PARSER_STATEMENT_FOR); @@ -1186,36 +1149,36 @@ parser_parse_for_statement_end (parser_context_t *context_p) /**< context */ parser_stack_iterator_skip (&iterator, sizeof (parser_loop_statement_t)); parser_stack_iterator_read (&iterator, &for_statement, sizeof (parser_for_statement_t)); - parser_save_range (context_p, &range, context_p->source_end_p); + scanner_get_location (&location, context_p); current_token = context_p->token; - parser_set_range (context_p, &for_statement.expression_range); + scanner_set_location (context_p, &for_statement.expression_location); lexer_next_token (context_p); parser_set_continues_to_current_position (context_p, loop.branch_list_p); - if (context_p->token.type != LEXER_EOS) + if (context_p->token.type != LEXER_RIGHT_PAREN) { parser_parse_expression (context_p, PARSE_EXPR_STATEMENT); - if (context_p->token.type != LEXER_EOS) + if (context_p->token.type != LEXER_RIGHT_PAREN) { - parser_raise_error (context_p, PARSER_ERR_INVALID_EXPRESSION); + parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED); } } parser_set_branch_to_current_position (context_p, &for_statement.branch); - parser_set_range (context_p, &for_statement.condition_range); + scanner_set_location (context_p, &for_statement.condition_location); lexer_next_token (context_p); - if (context_p->token.type != LEXER_EOS) + if (context_p->token.type != LEXER_SEMICOLON) { parser_parse_expression (context_p, PARSE_EXPR); - if (context_p->token.type != LEXER_EOS) + if (context_p->token.type != LEXER_SEMICOLON) { - parser_raise_error (context_p, PARSER_ERR_INVALID_EXPRESSION); + parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED); } opcode = CBC_BRANCH_IF_TRUE_BACKWARD; @@ -1241,7 +1204,7 @@ parser_parse_for_statement_end (parser_context_t *context_p) /**< context */ parser_emit_cbc_backward_branch (context_p, (uint16_t) opcode, for_statement.start_offset); parser_set_breaks_to_current_position (context_p, loop.branch_list_p); - parser_set_range (context_p, &range); + scanner_set_location (context_p, &location); context_p->token = current_token; } /* parser_parse_for_statement_end */ @@ -1254,11 +1217,10 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context * parser_switch_statement_t switch_statement; parser_loop_statement_t loop; parser_stack_iterator_t iterator; - lexer_range_t switch_body_start; - lexer_range_t unused_range; + scanner_location_t start_location; bool switch_case_was_found; bool default_case_was_found; - parser_branch_node_t *cases_p = NULL; + parser_branch_node_t *case_branches_p = NULL; JERRY_ASSERT (context_p->token.type == LEXER_KEYW_SWITCH); @@ -1269,25 +1231,32 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context * parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED); } - parser_save_range (context_p, &switch_body_start, context_p->source_end_p); - lexer_next_token (context_p); + JERRY_ASSERT (context_p->next_scanner_info_p->source_p == context_p->source_p + && context_p->next_scanner_info_p->type == SCANNER_TYPE_SWITCH); - if (context_p->token.type == LEXER_RIGHT_BRACE) - { - /* Unlikely case, but possible. */ - parser_emit_cbc (context_p, CBC_POP); - parser_flush_cbc (context_p); - parser_stack_push_uint8 (context_p, PARSER_STATEMENT_BLOCK); - parser_stack_iterator_init (context_p, &context_p->last_statement); - return; - } + scanner_case_info_t *case_info_p = ((scanner_switch_info_t *) context_p->next_scanner_info_p)->case_p; + scanner_set_active (context_p); - if (context_p->token.type != LEXER_KEYW_CASE - && context_p->token.type != LEXER_KEYW_DEFAULT) + if (case_info_p == NULL) { + lexer_next_token (context_p); + + if (context_p->token.type == LEXER_RIGHT_BRACE) + { + scanner_release_active (context_p, sizeof (scanner_switch_info_t)); + + parser_emit_cbc (context_p, CBC_POP); + parser_flush_cbc (context_p); + parser_stack_push_uint8 (context_p, PARSER_STATEMENT_BLOCK); + parser_stack_iterator_init (context_p, &context_p->last_statement); + return; + } + parser_raise_error (context_p, PARSER_ERR_INVALID_SWITCH); } + scanner_get_location (&start_location, context_p); + /* The reason of using an iterator is error management. If an error * occures, parser_free_jumps() free all data. However, the branches * created by parser_emit_cbc_forward_branch_item() would not be freed. @@ -1311,78 +1280,76 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context * uint32_t last_line_info_line = context_p->last_line_info_line; #endif /* ENABLED (JERRY_LINE_INFO) */ - while (true) + do { - parser_scan_until (context_p, &unused_range, LEXER_KEYW_CASE); + scanner_set_location (context_p, &case_info_p->location); + case_info_p = case_info_p->next_p; - if (context_p->token.type == LEXER_KEYW_DEFAULT) + + /* The last letter of case and default is 'e' and 't' respectively. */ + JERRY_ASSERT (context_p->source_p[-1] == LIT_CHAR_LOWERCASE_E + || context_p->source_p[-1] == LIT_CHAR_LOWERCASE_T); + + bool is_default = context_p->source_p[-1] == LIT_CHAR_LOWERCASE_T; + lexer_next_token (context_p); + + if (is_default) { if (default_case_was_found) { parser_raise_error (context_p, PARSER_ERR_MULTIPLE_DEFAULTS_NOT_ALLOWED); } - lexer_next_token (context_p); if (context_p->token.type != LEXER_COLON) { parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED); } default_case_was_found = true; + continue; } - else if (context_p->token.type == LEXER_KEYW_CASE - || context_p->token.type == LEXER_RIGHT_BRACE) - { - if (switch_case_was_found) - { - parser_branch_node_t *new_case_p; - uint16_t opcode = CBC_BRANCH_IF_STRICT_EQUAL; - if (context_p->token.type != LEXER_KEYW_CASE) - { - /* We don't duplicate the value for the last case. */ - parser_emit_cbc (context_p, CBC_STRICT_EQUAL); - opcode = CBC_BRANCH_IF_TRUE_FORWARD; - } - new_case_p = parser_emit_cbc_forward_branch_item (context_p, opcode, NULL); - if (cases_p == NULL) - { - switch_statement.branch_list_p = new_case_p; - parser_stack_iterator_write (&iterator, &switch_statement, sizeof (parser_switch_statement_t)); - } - else - { - cases_p->next_p = new_case_p; - } - cases_p = new_case_p; - } - - /* End of switch statement. */ - if (context_p->token.type == LEXER_RIGHT_BRACE) - { - break; - } - - lexer_next_token (context_p); + switch_case_was_found = true; #if ENABLED (JERRY_LINE_INFO) - if (context_p->token.line != context_p->last_line_info_line) - { - parser_emit_line_info (context_p, context_p->token.line, true); - } + if (context_p->token.line != context_p->last_line_info_line) + { + parser_emit_line_info (context_p, context_p->token.line, true); + } #endif /* ENABLED (JERRY_LINE_INFO) */ - parser_parse_expression (context_p, PARSE_EXPR); + parser_parse_expression (context_p, PARSE_EXPR); - if (context_p->token.type != LEXER_COLON) - { - parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED); - } - switch_case_was_found = true; + if (context_p->token.type != LEXER_COLON) + { + parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED); } - lexer_next_token (context_p); + uint16_t opcode = CBC_BRANCH_IF_STRICT_EQUAL; + + if (case_info_p == NULL + || (case_info_p->next_p == NULL && case_info_p->location.source_p[-1] == LIT_CHAR_LOWERCASE_T)) + { + /* There are no more 'case' statements in the switch. */ + parser_emit_cbc (context_p, CBC_STRICT_EQUAL); + opcode = CBC_BRANCH_IF_TRUE_FORWARD; + } + + parser_branch_node_t *new_case_p = parser_emit_cbc_forward_branch_item (context_p, opcode, NULL); + + if (case_branches_p == NULL) + { + switch_statement.branch_list_p = new_case_p; + parser_stack_iterator_write (&iterator, &switch_statement, sizeof (parser_switch_statement_t)); + } + else + { + case_branches_p->next_p = new_case_p; + } + + case_branches_p = new_case_p; } + while (case_info_p != NULL); JERRY_ASSERT (switch_case_was_found || default_case_was_found); @@ -1405,7 +1372,10 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context * parser_stack_change_last_uint8 (context_p, PARSER_STATEMENT_SWITCH_NO_DEFAULT); } - parser_set_range (context_p, &switch_body_start); + scanner_release_switch_cases (((scanner_switch_info_t *) context_p->active_scanner_info_p)->case_p); + scanner_release_active (context_p, sizeof (scanner_switch_info_t)); + + scanner_set_location (context_p, &start_location); lexer_next_token (context_p); } /* parser_parse_switch_statement_start */ @@ -1569,7 +1539,6 @@ parser_parse_case_statement (parser_context_t *context_p) /**< context */ { parser_stack_iterator_t iterator; parser_switch_statement_t switch_statement; - lexer_range_t dummy_range; parser_branch_node_t *branch_p; if (context_p->stack_top_uint8 != PARSER_STATEMENT_SWITCH @@ -1578,7 +1547,20 @@ parser_parse_case_statement (parser_context_t *context_p) /**< context */ parser_raise_error (context_p, PARSER_ERR_CASE_NOT_IN_SWITCH); } - parser_scan_until (context_p, &dummy_range, LEXER_COLON); + 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); + + JERRY_ASSERT (context_p->token.type != LEXER_COLON); + parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED); + } + + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_CASE); + + 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)); lexer_next_token (context_p); parser_stack_iterator_init (context_p, &iterator); @@ -2753,59 +2735,44 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ } case PARSER_STATEMENT_FOR_IN: - { - parser_for_in_statement_t for_in_statement; - parser_loop_statement_t loop; - - parser_stack_pop_uint8 (context_p); - parser_stack_pop (context_p, &loop, sizeof (parser_loop_statement_t)); - parser_stack_pop (context_p, &for_in_statement, sizeof (parser_for_in_statement_t)); - parser_stack_iterator_init (context_p, &context_p->last_statement); - - parser_set_continues_to_current_position (context_p, loop.branch_list_p); - - parser_flush_cbc (context_p); - PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION); -#ifndef JERRY_NDEBUG - PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION); -#endif /* !JERRY_NDEBUG */ - - parser_emit_cbc_ext_backward_branch (context_p, - CBC_EXT_BRANCH_IF_FOR_IN_HAS_NEXT, - for_in_statement.start_offset); - - parser_set_breaks_to_current_position (context_p, loop.branch_list_p); - parser_set_branch_to_current_position (context_p, &for_in_statement.branch); - continue; - } #if ENABLED (JERRY_ES2015_FOR_OF) case PARSER_STATEMENT_FOR_OF: +#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ { - parser_for_of_statement_t for_of_statement; + parser_for_in_of_statement_t for_in_of_statement; parser_loop_statement_t loop; +#if ENABLED (JERRY_ES2015_FOR_OF) + bool is_for_in = (context_p->stack_top_uint8 == PARSER_STATEMENT_FOR_IN); +#else + bool is_for_in = true; +#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ + parser_stack_pop_uint8 (context_p); parser_stack_pop (context_p, &loop, sizeof (parser_loop_statement_t)); - parser_stack_pop (context_p, &for_of_statement, sizeof (parser_for_of_statement_t)); + parser_stack_pop (context_p, &for_in_of_statement, sizeof (parser_for_in_of_statement_t)); parser_stack_iterator_init (context_p, &context_p->last_statement); parser_set_continues_to_current_position (context_p, loop.branch_list_p); parser_flush_cbc (context_p); - PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION); + PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, is_for_in ? PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION + : PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION); #ifndef JERRY_NDEBUG - PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION); + PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, + is_for_in ? PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION + : PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION); #endif /* !JERRY_NDEBUG */ parser_emit_cbc_ext_backward_branch (context_p, - CBC_EXT_BRANCH_IF_FOR_OF_HAS_NEXT, - for_of_statement.start_offset); + is_for_in ? CBC_EXT_BRANCH_IF_FOR_IN_HAS_NEXT + : CBC_EXT_BRANCH_IF_FOR_OF_HAS_NEXT, + for_in_of_statement.start_offset); parser_set_breaks_to_current_position (context_p, loop.branch_list_p); - parser_set_branch_to_current_position (context_p, &for_of_statement.branch); + parser_set_branch_to_current_position (context_p, &for_in_of_statement.branch); continue; } -#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ case PARSER_STATEMENT_WITH: { diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 793c5874a..8889d6719 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -2393,8 +2393,6 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ if (arg_list_p == NULL) { context.status_flags = PARSER_NO_REG_STORE | PARSER_LEXICAL_ENV_NEEDED | PARSER_ARGUMENTS_NOT_NEEDED; - context.source_p = source_p; - context.source_end_p = source_p + source_size; } else { @@ -2407,16 +2405,8 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ context.status_flags |= PARSER_LEXICAL_ENV_NEEDED | PARSER_NO_REG_STORE; } #endif /* ENABLED (JERRY_DEBUGGER) */ - context.source_p = arg_list_p; - context.source_end_p = arg_list_p + arg_list_size; } - context.stack_depth = 0; - context.stack_limit = 0; - context.last_context_p = NULL; - context.last_statement.current_p = NULL; - context.status_flags |= parse_opts & PARSER_STRICT_MODE_MASK; - #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) if (parse_opts & ECMA_PARSE_EVAL) { @@ -2430,10 +2420,23 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ context.status_flags |= PARSER_GET_CLASS_PARSER_OPTS (parse_opts); #endif /* ENABLED (JERRY_ES2015_CLASS) */ + context.stack_depth = 0; + context.stack_limit = 0; + context.last_context_p = NULL; + context.last_statement.current_p = NULL; + context.status_flags |= parse_opts & PARSER_STRICT_MODE_MASK; + context.token.flags = 0; context.line = 1; context.column = 1; + scanner_info_t scanner_info_end; + scanner_info_end.next_p = NULL; + scanner_info_end.source_p = NULL; + scanner_info_end.type = SCANNER_TYPE_END; + context.next_scanner_info_p = &scanner_info_end; + context.active_scanner_info_p = NULL; + context.last_cbc_opcode = PARSER_CBC_UNAVAILABLE; context.argument_count = 0; @@ -2445,7 +2448,6 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ parser_list_init (&context.literal_pool, sizeof (lexer_literal_t), (uint32_t) ((128 - sizeof (void *)) / sizeof (lexer_literal_t))); - parser_stack_init (&context); #ifndef JERRY_NDEBUG context.context_stack_depth = 0; @@ -2463,6 +2465,42 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ } #endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ + context.source_p = source_p; + context.source_end_p = source_p + source_size; + context.line = 1; + context.column = 1; + + scanner_scan_all (&context); + + if (JERRY_UNLIKELY (context.error != PARSER_ERR_NO_ERROR)) + { + JERRY_ASSERT (context.error == PARSER_ERR_OUT_OF_MEMORY); + + if (error_location_p != NULL) + { + error_location_p->error = context.error; + error_location_p->line = context.token.line; + error_location_p->column = context.token.column; + } + return NULL; + } + + if (arg_list_p == NULL) + { + context.source_p = source_p; + context.source_end_p = source_p + source_size; + } + else + { + context.source_p = arg_list_p; + context.source_end_p = arg_list_p + arg_list_size; + } + + context.line = 1; + context.column = 1; + + parser_stack_init (&context); + #if ENABLED (JERRY_DEBUGGER) context.breakpoint_info_count = 0; #endif /* ENABLED (JERRY_DEBUGGER) */ @@ -2529,6 +2567,8 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ context.allocated_buffer_size); } + scanner_cleanup (&context); + #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) if (context.module_current_node_p != NULL && context.module_current_node_p->module_names_p != NULL) @@ -2881,12 +2921,14 @@ parser_parse_arrow_function (parser_context_t *context_p, /**< context */ #endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ /** - * Raise a parse error + * Raise a parse error. */ void parser_raise_error (parser_context_t *context_p, /**< context */ parser_error_t error) /**< error code */ { + /* Must be compatible with the scanner because + * the lexer might throws errors during prescanning. */ parser_saved_context_t *saved_context_p = context_p->last_context_p; while (saved_context_p != NULL) diff --git a/jerry-core/parser/js/js-scanner-util.c b/jerry-core/parser/js/js-scanner-util.c new file mode 100644 index 000000000..2259476a4 --- /dev/null +++ b/jerry-core/parser/js/js-scanner-util.c @@ -0,0 +1,290 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "js-parser-internal.h" + +#if ENABLED (JERRY_PARSER) + +/** \addtogroup parser Parser + * @{ + * + * \addtogroup jsparser JavaScript + * @{ + * + * \addtogroup jsparser_scanner Scanner + * @{ + */ + +/** + * Raise a scanner error. + */ +void +scanner_raise_error (parser_context_t *context_p) /**< context */ +{ + PARSER_THROW (context_p->try_buffer); + /* Should never been reached. */ + JERRY_ASSERT (0); +} /* scanner_raise_error */ + +/** + * Allocate memory for scanner. + * + * @return allocated memory + */ +void * +scanner_malloc (parser_context_t *context_p, /**< context */ + size_t size) /**< size of the memory block */ +{ + void *result; + + JERRY_ASSERT (size > 0); + result = jmem_heap_alloc_block_null_on_error (size); + + if (result == NULL) + { + scanner_cleanup (context_p); + + /* This is the only error which specify its reason. */ + context_p->error = PARSER_ERR_OUT_OF_MEMORY; + PARSER_THROW (context_p->try_buffer); + } + return result; +} /* scanner_malloc */ + +/** + * Free memory allocated by scanner_malloc. + */ +inline void JERRY_ATTR_ALWAYS_INLINE +scanner_free (void *ptr, /**< pointer to free */ + size_t size) /**< size of the memory block */ +{ + jmem_heap_free_block (ptr, size); +} /* scanner_free */ + +/** + * Insert a scanner info block into the scanner info chain. + * + * @return newly allocated scanner info + */ +scanner_info_t * +scanner_insert_info (parser_context_t *context_p, /**< context */ + const uint8_t *source_p, /**< triggering position */ + size_t size) /**< size of the memory block */ +{ + scanner_info_t *new_scanner_info_p = (scanner_info_t *) scanner_malloc (context_p, size); + scanner_info_t *scanner_info_p = context_p->next_scanner_info_p; + scanner_info_t *prev_scanner_info_p = NULL; + + JERRY_ASSERT (scanner_info_p != NULL); + + new_scanner_info_p->source_p = source_p; + + while (source_p < scanner_info_p->source_p) + { + prev_scanner_info_p = scanner_info_p; + scanner_info_p = scanner_info_p->next_p; + + JERRY_ASSERT (scanner_info_p != NULL); + } + + /* Multiple scanner info blocks cannot be assigned to the same position. */ + JERRY_ASSERT (source_p != scanner_info_p->source_p); + + new_scanner_info_p->next_p = scanner_info_p; + + if (JERRY_LIKELY (prev_scanner_info_p == NULL)) + { + context_p->next_scanner_info_p = new_scanner_info_p; + } + else + { + prev_scanner_info_p->next_p = new_scanner_info_p; + } + + return new_scanner_info_p; +} /* scanner_insert_info */ + +/** + * Release the next scanner info. + */ +inline void JERRY_ATTR_ALWAYS_INLINE +scanner_release_next (parser_context_t *context_p, /**< context */ + size_t size) /**< size of the memory block */ +{ + scanner_info_t *next_p = context_p->next_scanner_info_p->next_p; + + jmem_heap_free_block (context_p->next_scanner_info_p, size); + context_p->next_scanner_info_p = next_p; +} /* scanner_release_next */ + +/** + * Set the active scanner info to the next scanner info. + */ +inline void JERRY_ATTR_ALWAYS_INLINE +scanner_set_active (parser_context_t *context_p) +{ + scanner_info_t *scanner_info_p = context_p->next_scanner_info_p; + + context_p->next_scanner_info_p = scanner_info_p->next_p; + scanner_info_p->next_p = context_p->active_scanner_info_p; + context_p->active_scanner_info_p = scanner_info_p; +} /* scanner_set_active */ + +/** + * Release the active scanner info. + */ +inline void JERRY_ATTR_ALWAYS_INLINE +scanner_release_active (parser_context_t *context_p, /**< context */ + size_t size) /**< size of the memory block */ +{ + scanner_info_t *next_p = context_p->active_scanner_info_p->next_p; + + jmem_heap_free_block (context_p->active_scanner_info_p, size); + context_p->active_scanner_info_p = next_p; +} /* scanner_release_active */ + +void +scanner_release_switch_cases (scanner_case_info_t *case_p) /**< case list */ +{ + while (case_p != NULL) + { + scanner_case_info_t *next_p = case_p->next_p; + + jmem_heap_free_block (case_p, sizeof (scanner_case_info_t)); + case_p = next_p; + } +} /* scanner_release_switch_cases */ + +/** + * Reverse the scanner info chain after the scanning is completed. + */ +void +scanner_reverse_info_list (parser_context_t *context_p) /**< context */ +{ + scanner_info_t *scanner_info_p = context_p->next_scanner_info_p; + scanner_info_t *last_scanner_info_p = NULL; + + if (scanner_info_p->type == SCANNER_TYPE_END) + { + return; + } + + do + { + scanner_info_t *next_scanner_info_p = scanner_info_p->next_p; + scanner_info_p->next_p = last_scanner_info_p; + + last_scanner_info_p = scanner_info_p; + scanner_info_p = next_scanner_info_p; + } + while (scanner_info_p->type != SCANNER_TYPE_END); + + context_p->next_scanner_info_p->next_p = scanner_info_p; + context_p->next_scanner_info_p = last_scanner_info_p; +} /* scanner_reverse_info_list */ + +/** + * Release unused scanner info blocks. + * This should happen only if an error is occured. + */ +void +scanner_cleanup (parser_context_t *context_p) /**< context */ +{ + scanner_info_t *scanner_info_p = context_p->next_scanner_info_p; + + while (scanner_info_p != NULL) + { + scanner_info_t *next_scanner_info_p = scanner_info_p->next_p; + + size_t size = sizeof (scanner_info_t); + + switch (scanner_info_p->type) + { + case SCANNER_TYPE_END: + { + scanner_info_p = context_p->active_scanner_info_p; + continue; + } + case SCANNER_TYPE_WHILE: + case SCANNER_TYPE_FOR_IN: +#if ENABLED (JERRY_ES2015_FOR_OF) + case SCANNER_TYPE_FOR_OF: +#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ + case SCANNER_TYPE_CASE: + { + size = sizeof (scanner_location_info_t); + break; + } + case SCANNER_TYPE_FOR: + { + size = sizeof (scanner_for_info_t); + break; + } + case SCANNER_TYPE_SWITCH: + { + scanner_release_switch_cases (((scanner_switch_info_t *) scanner_info_p)->case_p); + size = sizeof (scanner_switch_info_t); + break; + } + default: + { +#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) + JERRY_ASSERT (scanner_info_p->type == SCANNER_TYPE_ARROW); +#else /* !ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + JERRY_ASSERT (0); +#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + break; + } + } + + scanner_free (scanner_info_p, size); + scanner_info_p = next_scanner_info_p; + } + + context_p->next_scanner_info_p = NULL; + context_p->active_scanner_info_p = NULL; +} /* scanner_cleanup */ + +/** + * Get location from context. + */ +inline void JERRY_ATTR_ALWAYS_INLINE +scanner_get_location (scanner_location_t *location_p, /**< location */ + parser_context_t *context_p) /**< context */ +{ + location_p->source_p = context_p->source_p; + location_p->line = context_p->line; + location_p->column = context_p->column; +} /* scanner_get_location */ + +/** + * Set context location. + */ +inline void JERRY_ATTR_ALWAYS_INLINE +scanner_set_location (parser_context_t *context_p, /**< context */ + scanner_location_t *location_p) /**< location */ +{ + context_p->source_p = location_p->source_p; + context_p->line = location_p->line; + context_p->column = location_p->column; +} /* scanner_set_location */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_PARSER) */ diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c new file mode 100644 index 000000000..aaa9e5990 --- /dev/null +++ b/jerry-core/parser/js/js-scanner.c @@ -0,0 +1,1702 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "js-parser-internal.h" +#include "lit-char-helpers.h" + +#if ENABLED (JERRY_PARSER) + +/** \addtogroup parser Parser + * @{ + * + * \addtogroup jsparser JavaScript + * @{ + * + * \addtogroup jsparser_scanner Scanner + * @{ + */ + +/** + * Scan mode types types. + */ +typedef enum +{ + SCAN_MODE_PRIMARY_EXPRESSION, /**< scanning primary expression */ + SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW, /**< scanning primary expression after new */ +#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) + SCAN_MODE_ARROW_FUNCTION, /**< arrow function might follows */ +#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + SCAN_MODE_POST_PRIMARY_EXPRESSION, /**< scanning post primary expression */ + SCAN_MODE_PRIMARY_EXPRESSION_END, /**< scanning primary expression end */ + SCAN_MODE_STATEMENT, /**< scanning statement */ + SCAN_MODE_FUNCTION_ARGUMENTS, /**< scanning function arguments */ + SCAN_MODE_PROPERTY_NAME, /**< scanning property name */ +#if ENABLED (JERRY_ES2015_CLASS) + SCAN_MODE_CLASS_DECLARATION, /**< scanning class declaration */ + SCAN_MODE_CLASS_METHOD, /**< scanning class method */ +#endif /* ENABLED (JERRY_ES2015_CLASS) */ +} scan_modes_t; + +/** + * Scan stack mode types types. + */ +typedef enum +{ + SCAN_STACK_HEAD, /**< head */ + SCAN_STACK_PAREN_EXPRESSION, /**< parent expression group */ + SCAN_STACK_PAREN_STATEMENT, /**< parent statement group */ + SCAN_STACK_WHILE_START, /**< start of "while" iterator */ + SCAN_STACK_FOR_START, /**< start of "for" iterator */ + SCAN_STACK_FOR_CONDITION, /**< condition part of "for" iterator */ + SCAN_STACK_FOR_EXPRESSION, /**< expression part of "for" iterator */ + SCAN_STACK_SWITCH_EXPRESSION, /**< expression part of "switch" statement */ + SCAN_STACK_SWITCH_BLOCK, /**< block part of "switch" statement */ + SCAN_STACK_COLON_EXPRESSION, /**< colon expression group */ + SCAN_STACK_CASE_STATEMENT, /**< colon statement group */ + SCAN_STACK_SQUARE_BRACKETED_EXPRESSION, /**< square bracketed expression group */ + SCAN_STACK_OBJECT_LITERAL, /**< object literal group */ + SCAN_STACK_BLOCK_STATEMENT, /**< block statement group */ + SCAN_STACK_BLOCK_EXPRESSION, /**< block expression group */ + SCAN_STACK_BLOCK_PROPERTY, /**< block property group */ +#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) + SCAN_STACK_COMPUTED_PROPERTY, /**< computed property name */ +#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) + SCAN_STACK_TEMPLATE_STRING, /**< template string */ +#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ +#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) + SCAN_STACK_ARROW_EXPRESSION, /**< (possible) arrow function */ +#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +#if ENABLED (JERRY_ES2015_CLASS) + SCAN_STACK_CLASS, /**< class language element */ + SCAN_STACK_CLASS_EXTENDS, /**< class extends expression */ +#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) + SCAN_STACK_FUNCTION_PARAMETERS, /**< function parameter initializer */ +#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ +} scan_stack_modes_t; + +/** + * Generic descriptor which stores only the start position. + */ +typedef struct +{ + const uint8_t *source_p; /**< start source byte */ +} scanner_source_start_t; + +/** + * For statement descriptor. + */ +typedef struct +{ + union + { + const uint8_t *source_p; /**< start source byte */ + scanner_for_info_t *for_info_p; /**< for info */ + } u; +} scanner_for_statement_t; + +/** + * Switch statement descriptor. + */ +typedef struct +{ + scanner_case_info_t **last_case_p; /**< last case info */ +} scanner_switch_statement_t; + +/** + * Scanner context. + */ +typedef struct +{ + uint8_t mode; /**< scanner mode */ + scanner_switch_statement_t active_switch_statement; /**< currently active switch statement */ +} scanner_context_t; + +#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) + +static void +scanner_process_arrow (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + scanner_source_start_t source_start; + + parser_stack_pop_uint8 (context_p); + parser_stack_pop (context_p, &source_start, sizeof (scanner_source_start_t)); + + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_ARROW + || (context_p->token.flags & LEXER_WAS_NEWLINE)) + { + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + return; + } + + scanner_info_t *info_p = scanner_insert_info (context_p, source_start.source_p, sizeof (scanner_info_t)); + info_p->type = SCANNER_TYPE_ARROW; + + scanner_context_p->mode = SCAN_MODE_ARROW_FUNCTION; +} /* scanner_process_arrow */ + +#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + +/** + * Scan primary expression. + * + * @return true for continue, false for break + */ +static bool +scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p, /* scanner context */ + lexer_token_type_t type, /**< current token type */ + scan_stack_modes_t stack_top) /**< current stack top */ +{ + switch (type) + { + case LEXER_KEYW_NEW: + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW; + break; + } + case LEXER_DIVIDE: + case LEXER_ASSIGN_DIVIDE: + { + lexer_construct_regexp_object (context_p, true); + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + break; + } + case LEXER_KEYW_FUNCTION: + { + parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_EXPRESSION); + scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS; + break; + } + case LEXER_LEFT_PAREN: + { +#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) + 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_ARROW_EXPRESSION); +#else + parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION); +#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + break; + } + case LEXER_LEFT_SQUARE: + { + parser_stack_push_uint8 (context_p, SCAN_STACK_SQUARE_BRACKETED_EXPRESSION); + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + break; + } + case LEXER_LEFT_BRACE: + { + parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL); + scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME; + return true; + } +#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) + case LEXER_TEMPLATE_LITERAL: + { + if (context_p->source_p[-1] != LIT_CHAR_GRAVE_ACCENT) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_TEMPLATE_STRING); + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + break; + } + + /* The string is a normal string literal. */ + /* FALLTHRU */ + } +#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ + case LEXER_LITERAL: +#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) + { + bool is_ident = (context_p->token.lit_location.type == LEXER_IDENT_LITERAL); + + scanner_context_p->mode = (is_ident ? SCAN_MODE_ARROW_FUNCTION + : SCAN_MODE_POST_PRIMARY_EXPRESSION); + break; + } +#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + case LEXER_KEYW_THIS: + case LEXER_KEYW_SUPER: + case LEXER_LIT_TRUE: + case LEXER_LIT_FALSE: + case LEXER_LIT_NULL: + { + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + break; + } +#if ENABLED (JERRY_ES2015_CLASS) + case LEXER_KEYW_CLASS: + { + parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_EXPRESSION); + scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION; + break; + } +#endif /* ENABLED (JERRY_ES2015_CLASS) */ + case LEXER_RIGHT_SQUARE: + { + if (stack_top != SCAN_STACK_SQUARE_BRACKETED_EXPRESSION) + { + scanner_raise_error (context_p); + } + parser_stack_pop_uint8 (context_p); + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + break; + } + case LEXER_COMMA: + { + if (stack_top != SCAN_STACK_SQUARE_BRACKETED_EXPRESSION) + { + scanner_raise_error (context_p); + } + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + break; + } + case LEXER_RIGHT_PAREN: + { + switch (stack_top) + { + case SCAN_STACK_PAREN_STATEMENT: + { + scanner_context_p->mode = SCAN_MODE_STATEMENT; + break; + } + case SCAN_STACK_PAREN_EXPRESSION: + { + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + break; + } + case SCAN_STACK_FOR_EXPRESSION: + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + return true; + } +#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) + case SCAN_STACK_ARROW_EXPRESSION: + { + scanner_process_arrow (context_p, scanner_context_p); + return true; + } +#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + default: + { + scanner_raise_error (context_p); + } + } + + parser_stack_pop_uint8 (context_p); + break; + } + default: + { + scanner_raise_error (context_p); + } + } + return false; +} /* scanner_scan_primary_expression */ + +/** + * Scan the tokens after the primary expression. + * + * @return true for break, false for fall through + */ +static bool +scanner_scan_post_primary_expression (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p, /**< scanner context */ + lexer_token_type_t type) /**< current token type */ +{ + switch (type) + { + case LEXER_DOT: + { + lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_NO_OPTS); + return true; + } + case LEXER_LEFT_PAREN: + { + parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION); + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return true; + } + case LEXER_LEFT_SQUARE: + { + parser_stack_push_uint8 (context_p, SCAN_STACK_SQUARE_BRACKETED_EXPRESSION); + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return true; + } + case LEXER_INCREASE: + case LEXER_DECREASE: + { + if (!(context_p->token.flags & LEXER_WAS_NEWLINE)) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + return true; + } + /* FALLTHRU */ + } + default: + { + break; + } + } + + return false; +} /* scanner_scan_post_primary_expression */ + +/** + * Scan the tokens after the primary expression. + * + * @return true for continue, false for break + */ +static bool +scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p, /**< scanner context */ + lexer_token_type_t type, /**< current token type */ + scan_stack_modes_t stack_top) /**< current stack top */ +{ + switch (type) + { + case LEXER_QUESTION_MARK: + { + parser_stack_push_uint8 (context_p, SCAN_STACK_COLON_EXPRESSION); + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return false; + } + case LEXER_COMMA: + { + if (stack_top == SCAN_STACK_OBJECT_LITERAL) + { + scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME; + return true; + } + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return false; + } + case LEXER_COLON: + { + if (stack_top == SCAN_STACK_COLON_EXPRESSION) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + parser_stack_pop_uint8 (context_p); + return false; + } + + if (stack_top != SCAN_STACK_CASE_STATEMENT) + { + break; + } + + scanner_source_start_t source_start; + + parser_stack_pop_uint8 (context_p); + parser_stack_pop (context_p, &source_start, sizeof (scanner_source_start_t)); + + 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_CASE; + + scanner_get_location (&location_info_p->location, context_p); + + scanner_context_p->mode = SCAN_MODE_STATEMENT; + return false; + } + default: + { + break; + } + } + + if (LEXER_IS_BINARY_OP_TOKEN (type) + && (type != LEXER_KEYW_IN || stack_top != SCAN_STACK_FOR_START)) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return false; + } + + switch (stack_top) + { + case SCAN_STACK_HEAD: + case SCAN_STACK_SWITCH_BLOCK: + case SCAN_STACK_BLOCK_STATEMENT: + case SCAN_STACK_BLOCK_EXPRESSION: + case SCAN_STACK_BLOCK_PROPERTY: +#if ENABLED (JERRY_ES2015_CLASS) + case SCAN_STACK_CLASS: +#endif /* ENABLED (JERRY_ES2015_CLASS) */ + { + scanner_context_p->mode = SCAN_MODE_STATEMENT; + + if (type == LEXER_RIGHT_BRACE + || (context_p->token.flags & LEXER_WAS_NEWLINE)) + { + return true; + } + + if (type == LEXER_SEMICOLON) + { + return false; + } + break; + } + case SCAN_STACK_PAREN_EXPRESSION: + { + if (type != LEXER_RIGHT_PAREN) + { + break; + } + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + parser_stack_pop_uint8 (context_p); + return false; + } + case SCAN_STACK_PAREN_STATEMENT: + { + if (type != LEXER_RIGHT_PAREN) + { + break; + } + + scanner_context_p->mode = SCAN_MODE_STATEMENT; + parser_stack_pop_uint8 (context_p); + return false; + } + case SCAN_STACK_WHILE_START: + { + if (type != LEXER_RIGHT_PAREN) + { + break; + } + + scanner_source_start_t source_start; + + parser_stack_pop_uint8 (context_p); + parser_stack_pop (context_p, &source_start, sizeof (scanner_source_start_t)); + + 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_WHILE; + + scanner_get_location (&location_info_p->location, context_p); + + scanner_context_p->mode = SCAN_MODE_STATEMENT; + return false; + } + case SCAN_STACK_FOR_START: + { + if (type == LEXER_KEYW_IN +#if ENABLED (JERRY_ES2015_FOR_OF) + || lexer_compare_literal_to_identifier (context_p, "of", 2) +#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ + || false) + { + scanner_for_statement_t for_statement; + + parser_stack_pop_uint8 (context_p); + parser_stack_pop (context_p, &for_statement, sizeof (scanner_for_statement_t)); + + scanner_location_info_t *location_info; + location_info = (scanner_location_info_t *) scanner_insert_info (context_p, + for_statement.u.source_p, + sizeof (scanner_location_info_t)); +#if ENABLED (JERRY_ES2015_FOR_OF) + location_info->info.type = (type == LEXER_KEYW_IN) ? SCANNER_TYPE_FOR_IN : SCANNER_TYPE_FOR_OF; +#else /* !ENABLED (JERRY_ES2015_FOR_OF) */ + location_info->info.type = SCANNER_TYPE_FOR_IN; +#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ + + scanner_get_location (&location_info->location, context_p); + + parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_STATEMENT); + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return false; + } + + if (type != LEXER_SEMICOLON) + { + break; + } + + scanner_for_statement_t for_statement; + + parser_stack_pop_uint8 (context_p); + parser_stack_pop (context_p, NULL, sizeof (scanner_for_statement_t)); + + for_statement.u.source_p = context_p->source_p; + parser_stack_push (context_p, &for_statement, sizeof (scanner_for_statement_t)); + parser_stack_push_uint8 (context_p, SCAN_STACK_FOR_CONDITION); + + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_SEMICOLON) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return true; + } + + type = LEXER_SEMICOLON; + /* FALLTHRU */ + } + case SCAN_STACK_FOR_CONDITION: + { + if (type != LEXER_SEMICOLON) + { + break; + } + + scanner_for_statement_t for_statement; + + parser_stack_pop_uint8 (context_p); + parser_stack_pop (context_p, &for_statement, sizeof (scanner_for_statement_t)); + + scanner_for_info_t *for_info_p; + for_info_p = (scanner_for_info_t *) scanner_insert_info (context_p, + for_statement.u.source_p, + sizeof (scanner_for_info_t)); + for_info_p->info.type = SCANNER_TYPE_FOR; + + scanner_get_location (&for_info_p->expression_location, context_p); + for_info_p->end_location.source_p = NULL; + + for_statement.u.for_info_p = for_info_p; + + parser_stack_push (context_p, &for_statement, sizeof (scanner_for_statement_t)); + parser_stack_push_uint8 (context_p, SCAN_STACK_FOR_EXPRESSION); + + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_RIGHT_PAREN) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return true; + } + + type = LEXER_RIGHT_PAREN; + /* FALLTHRU */ + } + case SCAN_STACK_FOR_EXPRESSION: + { + if (type != LEXER_RIGHT_PAREN) + { + break; + } + + scanner_for_statement_t for_statement; + + parser_stack_pop_uint8 (context_p); + parser_stack_pop (context_p, &for_statement, sizeof (scanner_for_statement_t)); + + scanner_get_location (&for_statement.u.for_info_p->end_location, context_p); + + scanner_context_p->mode = SCAN_MODE_STATEMENT; + return false; + } + case SCAN_STACK_SWITCH_EXPRESSION: + { + if (type != LEXER_RIGHT_PAREN) + { + break; + } + + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_LEFT_BRACE) + { + break; + } + + parser_stack_pop_uint8 (context_p); + + scanner_switch_statement_t switch_statement = scanner_context_p->active_switch_statement; + parser_stack_push (context_p, &switch_statement, sizeof (scanner_switch_statement_t)); + parser_stack_push_uint8 (context_p, SCAN_STACK_SWITCH_BLOCK); + + scanner_switch_info_t *switch_info_p; + switch_info_p = (scanner_switch_info_t *) scanner_insert_info (context_p, + context_p->source_p, + sizeof (scanner_switch_info_t)); + switch_info_p->info.type = SCANNER_TYPE_SWITCH; + switch_info_p->case_p = NULL; + scanner_context_p->active_switch_statement.last_case_p = &switch_info_p->case_p; + + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_RIGHT_BRACE + && context_p->token.type != LEXER_KEYW_CASE + && context_p->token.type != LEXER_KEYW_DEFAULT) + { + break; + } + + scanner_context_p->mode = SCAN_MODE_STATEMENT; + return true; + } + case SCAN_STACK_SQUARE_BRACKETED_EXPRESSION: + { + if (type != LEXER_RIGHT_SQUARE) + { + break; + } + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + parser_stack_pop_uint8 (context_p); + return false; + } + case SCAN_STACK_OBJECT_LITERAL: + { + if (type != LEXER_RIGHT_BRACE) + { + break; + } + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + parser_stack_pop_uint8 (context_p); + return false; + } +#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) + case SCAN_STACK_COMPUTED_PROPERTY: + { + if (type != LEXER_RIGHT_SQUARE) + { + break; + } + + lexer_next_token (context_p); + + parser_stack_pop_uint8 (context_p); + stack_top = (scan_stack_modes_t) context_p->stack_top_uint8; + + if (stack_top == SCAN_STACK_BLOCK_PROPERTY + || stack_top == SCAN_STACK_CLASS) + { + if (context_p->token.type != LEXER_LEFT_PAREN) + { + scanner_raise_error (context_p); + } + + scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS; + return true; + } + + JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL); + + if (context_p->token.type == LEXER_LEFT_PAREN) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_PROPERTY); + scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS; + return true; + } + + if (context_p->token.type != LEXER_COLON) + { + scanner_raise_error (context_p); + } + + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return false; + } +#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ +#if ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) + case SCAN_STACK_TEMPLATE_STRING: + { + if (type != LEXER_RIGHT_BRACE) + { + break; + } + + context_p->source_p--; + context_p->column--; + lexer_parse_string (context_p); + + if (context_p->source_p[-1] != LIT_CHAR_GRAVE_ACCENT) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + } + else + { + parser_stack_pop_uint8 (context_p); + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + } + return false; + } +#endif /* ENABLED (JERRY_ES2015_TEMPLATE_STRINGS) */ +#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) + case SCAN_STACK_ARROW_EXPRESSION: + { + if (type != LEXER_RIGHT_PAREN) + { + break; + } + + scanner_process_arrow (context_p, scanner_context_p); + return true; + } +#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +#if ENABLED (JERRY_ES2015_CLASS) + case SCAN_STACK_CLASS_EXTENDS: + { + if (type != LEXER_LEFT_BRACE) + { + break; + } + scanner_context_p->mode = SCAN_MODE_CLASS_METHOD; + parser_stack_pop_uint8 (context_p); + return false; + } +#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) + case SCAN_STACK_FUNCTION_PARAMETERS: + { + if (type != LEXER_RIGHT_PAREN) + { + break; + } + + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_LEFT_BRACE) + { + scanner_raise_error (context_p); + } + + scanner_context_p->mode = SCAN_MODE_STATEMENT; + parser_stack_pop_uint8 (context_p); + return false; + } +#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ + default: + { + break; + } + } + + scanner_raise_error (context_p); + return false; +} /* scanner_scan_primary_expression_end */ + +/** + * Scan statements. + * + * @return true for continue, false for break + */ +static bool +scanner_scan_statement (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p, /**< scanner context */ + lexer_token_type_t type, /**< current token type */ + scan_stack_modes_t stack_top) /**< current stack top */ +{ + switch (type) + { + case LEXER_SEMICOLON: + case LEXER_KEYW_ELSE: + case LEXER_KEYW_DO: + case LEXER_KEYW_TRY: + case LEXER_KEYW_FINALLY: + case LEXER_KEYW_DEBUGGER: + { + return false; + } + case LEXER_KEYW_IF: + case LEXER_KEYW_WITH: + case LEXER_KEYW_SWITCH: + case LEXER_KEYW_CATCH: + { + lexer_next_token (context_p); + if (context_p->token.type != LEXER_LEFT_PAREN) + { + scanner_raise_error (context_p); + } + + parser_stack_push_uint8 (context_p, type != LEXER_KEYW_SWITCH ? SCAN_STACK_PAREN_STATEMENT + : SCAN_STACK_SWITCH_EXPRESSION); + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return false; + } + case LEXER_KEYW_WHILE: + { + lexer_next_token (context_p); + if (context_p->token.type != LEXER_LEFT_PAREN) + { + scanner_raise_error (context_p); + } + + 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_WHILE_START); + + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return false; + } + case LEXER_KEYW_FOR: + { + lexer_next_token (context_p); + if (context_p->token.type != LEXER_LEFT_PAREN) + { + scanner_raise_error (context_p); + } + + scanner_for_statement_t for_statement; + for_statement.u.source_p = context_p->source_p; + + parser_stack_push (context_p, &for_statement, sizeof (scanner_for_statement_t)); + parser_stack_push_uint8 (context_p, SCAN_STACK_FOR_START); + + lexer_next_token (context_p); + + if (context_p->token.type == LEXER_SEMICOLON) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; + return true; + } + + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + if (context_p->token.type == LEXER_KEYW_VAR) + { + return false; + } + return true; + } + case LEXER_KEYW_VAR: + case LEXER_KEYW_THROW: + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return false; + } + case LEXER_KEYW_RETURN: + { + lexer_next_token (context_p); + if (!(context_p->token.flags & LEXER_WAS_NEWLINE) + && context_p->token.type != LEXER_SEMICOLON + && context_p->token.type != LEXER_RIGHT_BRACE) + { + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + } + return true; + } + case LEXER_KEYW_BREAK: + case LEXER_KEYW_CONTINUE: + { + lexer_next_token (context_p); + if (!(context_p->token.flags & LEXER_WAS_NEWLINE) + && context_p->token.type == LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) + { + return false; + } + return true; + } + case LEXER_KEYW_CASE: + case LEXER_KEYW_DEFAULT: + { + if (stack_top != SCAN_STACK_SWITCH_BLOCK) + { + scanner_raise_error (context_p); + } + + scanner_case_info_t *case_info_p; + case_info_p = (scanner_case_info_t *) scanner_malloc (context_p, sizeof (scanner_case_info_t)); + + *(scanner_context_p->active_switch_statement.last_case_p) = case_info_p; + scanner_context_p->active_switch_statement.last_case_p = &case_info_p->next_p; + + case_info_p->next_p = NULL; + scanner_get_location (&case_info_p->location, context_p); + + if (type == LEXER_KEYW_DEFAULT) + { + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_COLON) + { + scanner_raise_error (context_p); + } + + return false; + } + + 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_CASE_STATEMENT); + + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + return false; + } + case LEXER_RIGHT_BRACE: + { + switch (stack_top) + { + case SCAN_STACK_SWITCH_BLOCK: + { + scanner_switch_statement_t switch_statement; + + parser_stack_pop_uint8 (context_p); + parser_stack_pop (context_p, &switch_statement, sizeof (scanner_switch_statement_t)); + + scanner_context_p->active_switch_statement = switch_statement; + + JERRY_ASSERT (scanner_context_p->mode == SCAN_MODE_STATEMENT); + return false; + } + case SCAN_STACK_BLOCK_STATEMENT: + { + JERRY_ASSERT (scanner_context_p->mode == SCAN_MODE_STATEMENT); + break; + } + case SCAN_STACK_BLOCK_EXPRESSION: + { + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + break; + } + case SCAN_STACK_BLOCK_PROPERTY: + { + lexer_next_token (context_p); + if (context_p->token.type != LEXER_COMMA + && context_p->token.type != LEXER_RIGHT_BRACE) + { + scanner_raise_error (context_p); + } + + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + parser_stack_pop_uint8 (context_p); + return true; + } +#if ENABLED (JERRY_ES2015_CLASS) + case SCAN_STACK_CLASS: + { + scanner_context_p->mode = SCAN_MODE_CLASS_METHOD; + break; + } +#endif /* ENABLED (JERRY_ES2015_CLASS) */ + default: + { + scanner_raise_error (context_p); + } + } + + parser_stack_pop_uint8 (context_p); + return false; + } + case LEXER_LEFT_BRACE: + { + parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT); + return false; + } + case LEXER_KEYW_FUNCTION: + { + parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT); + scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS; + return false; + } +#if ENABLED (JERRY_ES2015_CLASS) + case LEXER_KEYW_CLASS: + { + parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT); + scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION; + return false; + } +#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + case LEXER_KEYW_IMPORT: + { + if (stack_top != SCAN_STACK_HEAD) + { + scanner_raise_error (context_p); + } + + lexer_next_token (context_p); + + if (context_p->token.type == LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_STRING_LITERAL) + { + return false; + } + + bool parse_imports = true; + + if (context_p->token.type == LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) + { + lexer_next_token (context_p); + + if (context_p->token.type == LEXER_COMMA) + { + lexer_next_token (context_p); + } + else + { + parse_imports = false; + } + } + + if (parse_imports) + { + if (context_p->token.type == LEXER_MULTIPLY) + { + lexer_next_token (context_p); + if (!lexer_compare_literal_to_identifier (context_p, "as", 2)) + { + scanner_raise_error (context_p); + } + + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) + { + scanner_raise_error (context_p); + } + + lexer_next_token (context_p); + } + else if (context_p->token.type == LEXER_LEFT_BRACE) + { + lexer_next_token (context_p); + + while (context_p->token.type != LEXER_RIGHT_BRACE) + { + if (context_p->token.type != LEXER_LITERAL + || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) + { + scanner_raise_error (context_p); + } + + lexer_next_token (context_p); + + if (lexer_compare_literal_to_identifier (context_p, "as", 2)) + { + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) + { + scanner_raise_error (context_p); + } + + lexer_next_token (context_p); + } + + if (context_p->token.type != LEXER_RIGHT_BRACE) + { + if (context_p->token.type != LEXER_COMMA) + { + scanner_raise_error (context_p); + } + + lexer_next_token (context_p); + } + } + + lexer_next_token (context_p); + } + else + { + scanner_raise_error (context_p); + } + } + + if (!lexer_compare_literal_to_identifier (context_p, "from", 4)) + { + scanner_raise_error (context_p); + } + + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_LITERAL + && context_p->token.lit_location.type != LEXER_STRING_LITERAL) + { + scanner_raise_error (context_p); + } + + return false; + } + case LEXER_KEYW_EXPORT: + { + if (stack_top != SCAN_STACK_HEAD) + { + scanner_raise_error (context_p); + } + + lexer_next_token (context_p); + + if (context_p->token.type == LEXER_KEYW_DEFAULT) + { + return false; + } + + if (context_p->token.type == LEXER_MULTIPLY) + { + lexer_next_token (context_p); + if (!lexer_compare_literal_to_identifier (context_p, "from", 4)) + { + scanner_raise_error (context_p); + } + + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_STRING_LITERAL) + { + scanner_raise_error (context_p); + } + + return false; + } + + if (context_p->token.type == LEXER_LEFT_BRACE) + { + lexer_next_token (context_p); + + while (context_p->token.type != LEXER_RIGHT_BRACE) + { + if (context_p->token.type != LEXER_LITERAL + || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) + { + scanner_raise_error (context_p); + } + + lexer_next_token (context_p); + + if (lexer_compare_literal_to_identifier (context_p, "as", 2)) + { + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) + { + scanner_raise_error (context_p); + } + + lexer_next_token (context_p); + } + + if (context_p->token.type != LEXER_RIGHT_BRACE) + { + if (context_p->token.type != LEXER_COMMA) + { + scanner_raise_error (context_p); + } + + lexer_next_token (context_p); + } + } + + lexer_next_token (context_p); + + if (!lexer_compare_literal_to_identifier (context_p, "from", 4)) + { + return true; + } + + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_STRING_LITERAL) + { + scanner_raise_error (context_p); + } + + return false; + } + + return true; + } +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + default: + { + break; + } + } + + scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; + + if (type == LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) + { + lexer_next_token (context_p); + if (context_p->token.type == LEXER_COLON) + { + scanner_context_p->mode = SCAN_MODE_STATEMENT; + return false; + } +#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) + scanner_context_p->mode = SCAN_MODE_ARROW_FUNCTION; +#else /* !ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; +#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + } + + return true; +} /* scanner_scan_statement */ + +/** + * Scan the whole source code. + */ +void +scanner_scan_all (parser_context_t *context_p) /**< context */ +{ + scanner_context_t scanner_context; + +#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) + const uint8_t *source_start_p = context_p->source_p; + + if (context_p->is_show_opcodes) + { + JERRY_DEBUG_MSG ("\n--- Scanning start ---\n\n"); + } +#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ + + scanner_context.mode = SCAN_MODE_STATEMENT; + scanner_context.active_switch_statement.last_case_p = NULL; + + parser_stack_init (context_p); + + PARSER_TRY (context_p->try_buffer) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_HEAD); + lexer_next_token (context_p); + + while (true) + { + lexer_token_type_t type = (lexer_token_type_t) context_p->token.type; + scan_stack_modes_t stack_top = (scan_stack_modes_t) context_p->stack_top_uint8; + + if (type == LEXER_EOS) + { + if (stack_top == SCAN_STACK_HEAD) + { + break; + } + scanner_raise_error (context_p); + } + + switch (scanner_context.mode) + { + case SCAN_MODE_PRIMARY_EXPRESSION: + { + if (type == LEXER_ADD + || type == LEXER_SUBTRACT + || LEXER_IS_UNARY_OP_TOKEN (type)) + { + break; + } + /* FALLTHRU */ + } + case SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW: + { + if (scanner_scan_primary_expression (context_p, &scanner_context, type, stack_top)) + { + continue; + } + break; + } +#if ENABLED (JERRY_ES2015_CLASS) + case SCAN_MODE_CLASS_DECLARATION: + { + if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) + { + lexer_next_token (context_p); + } + + if (context_p->token.type == LEXER_KEYW_EXTENDS) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_EXTENDS); + scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; + break; + } + else if (context_p->token.type != LEXER_LEFT_BRACE) + { + scanner_raise_error (context_p); + } + + scanner_context.mode = SCAN_MODE_CLASS_METHOD; + break; + } + case SCAN_MODE_CLASS_METHOD: + { + if (type == LEXER_SEMICOLON) + { + break; + } + + if (type == LEXER_RIGHT_BRACE + && (stack_top == SCAN_STACK_BLOCK_STATEMENT + || stack_top == SCAN_STACK_BLOCK_EXPRESSION)) + { + scanner_context.mode = (stack_top == SCAN_STACK_BLOCK_EXPRESSION ? SCAN_MODE_PRIMARY_EXPRESSION_END + : SCAN_MODE_STATEMENT); + parser_stack_pop_uint8 (context_p); + break; + } + + if (lexer_compare_literal_to_identifier (context_p, "static", 6)) + { + lexer_next_token (context_p); + } + + if (lexer_compare_literal_to_identifier (context_p, "get", 3) + || lexer_compare_literal_to_identifier (context_p, "set", 3)) + { + lexer_next_token (context_p); + } + + parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS); + +#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) + if (context_p->token.type == LEXER_LEFT_SQUARE) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_COMPUTED_PROPERTY); + scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; + break; + } +#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ + + scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS; + continue; + } +#endif /* ENABLED (JERRY_ES2015_CLASS) */ +#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) + case SCAN_MODE_ARROW_FUNCTION: + { + if (type == LEXER_ARROW) + { + lexer_next_token (context_p); + + if (context_p->token.type == LEXER_LEFT_BRACE) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_EXPRESSION); + scanner_context.mode = SCAN_MODE_STATEMENT; + } + else + { + scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; + continue; + } + break; + } + scanner_context.mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + /* FALLTHRU */ + } +#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + case SCAN_MODE_POST_PRIMARY_EXPRESSION: + { + if (scanner_scan_post_primary_expression (context_p, &scanner_context, type)) + { + break; + } + /* FALLTHRU */ + } + case SCAN_MODE_PRIMARY_EXPRESSION_END: + { + if (scanner_scan_primary_expression_end (context_p, &scanner_context, type, stack_top)) + { + continue; + } + break; + } + case SCAN_MODE_STATEMENT: + { + if (scanner_scan_statement (context_p, &scanner_context, type, stack_top)) + { + continue; + } + break; + } + case SCAN_MODE_FUNCTION_ARGUMENTS: + { +#if ENABLED (JERRY_ES2015_CLASS) + JERRY_ASSERT (stack_top == SCAN_STACK_BLOCK_STATEMENT + || stack_top == SCAN_STACK_BLOCK_EXPRESSION + || stack_top == SCAN_STACK_CLASS + || stack_top == SCAN_STACK_BLOCK_PROPERTY); +#else /* !ENABLED (JERRY_ES2015_CLASS) */ + JERRY_ASSERT (stack_top == SCAN_STACK_BLOCK_STATEMENT + || stack_top == SCAN_STACK_BLOCK_EXPRESSION + || stack_top == SCAN_STACK_BLOCK_PROPERTY); +#endif /* ENABLED (JERRY_ES2015_CLASS) */ + + if (context_p->token.type == LEXER_LITERAL + && (context_p->token.lit_location.type == LEXER_IDENT_LITERAL + || context_p->token.lit_location.type == LEXER_STRING_LITERAL + || context_p->token.lit_location.type == LEXER_NUMBER_LITERAL)) + { + lexer_next_token (context_p); + } + + if (context_p->token.type != LEXER_LEFT_PAREN) + { + scanner_raise_error (context_p); + } + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_RIGHT_PAREN) + { + while (true) + { +#if ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) + if (context_p->token.type == LEXER_THREE_DOTS) + { + lexer_next_token (context_p); + } +#endif /* ENABLED (JERRY_ES2015_FUNCTION_REST_PARAMETER) */ + + if (context_p->token.type != LEXER_LITERAL + || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) + { + scanner_raise_error (context_p); + } + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_COMMA) + { + break; + } + lexer_next_token (context_p); + } + } + +#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) + if (context_p->token.type == LEXER_ASSIGN) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PARAMETERS); + scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; + break; + } +#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */ + + if (context_p->token.type != LEXER_RIGHT_PAREN) + { + scanner_raise_error (context_p); + } + + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_LEFT_BRACE) + { + scanner_raise_error (context_p); + } + scanner_context.mode = SCAN_MODE_STATEMENT; + break; + } + case SCAN_MODE_PROPERTY_NAME: + { + JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL); + + lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_PROPERTY); + +#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) + if (context_p->token.type == LEXER_LEFT_SQUARE) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_COMPUTED_PROPERTY); + scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; + break; + } +#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ + + if (context_p->token.type == LEXER_RIGHT_BRACE) + { + parser_stack_pop_uint8 (context_p); + scanner_context.mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + break; + } + + if (context_p->token.type == LEXER_PROPERTY_GETTER + || context_p->token.type == LEXER_PROPERTY_SETTER) + { + lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_PROPERTY | LEXER_SCAN_IDENT_NO_KEYW); + + parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_PROPERTY); + +#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) + if (context_p->token.type == LEXER_LEFT_SQUARE) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_COMPUTED_PROPERTY); + scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; + break; + } +#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ + + if (context_p->token.type != LEXER_LITERAL) + { + scanner_raise_error (context_p); + } + + scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS; + continue; + } + + lexer_next_token (context_p); + +#if ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) + if (context_p->token.type == LEXER_LEFT_PAREN) + { + parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_PROPERTY); + scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS; + continue; + } + + if (context_p->token.type == LEXER_COMMA) + { + continue; + } + + if (context_p->token.type == LEXER_RIGHT_BRACE) + { + parser_stack_pop_uint8 (context_p); + scanner_context.mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + break; + } +#endif /* ENABLED (JERRY_ES2015_OBJECT_INITIALIZER) */ + + if (context_p->token.type != LEXER_COLON) + { + scanner_raise_error (context_p); + } + + scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; + break; + } + } + + lexer_next_token (context_p); + } + } + PARSER_CATCH + { + /* Ignore the errors thrown by the lexer. */ + if (context_p->error != PARSER_ERR_OUT_OF_MEMORY) + { + context_p->error = PARSER_ERR_NO_ERROR; + } + } + PARSER_TRY_END + + scanner_reverse_info_list (context_p); + +#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) + if (context_p->is_show_opcodes) + { + scanner_info_t *info_p = context_p->next_scanner_info_p; + + while (info_p->type != SCANNER_TYPE_END) + { + const char *name_p = NULL; + bool print_location = false; + + switch (info_p->type) + { + case SCANNER_TYPE_WHILE: + { + name_p = "WHILE"; + print_location = true; + break; + } + case SCANNER_TYPE_FOR: + { + scanner_for_info_t *for_info_p = (scanner_for_info_t *) info_p; + JERRY_DEBUG_MSG (" FOR: source:%d expression:%d[%d:%d] end:%d[%d:%d]\n", + (int) (for_info_p->info.source_p - source_start_p), + (int) (for_info_p->expression_location.source_p - source_start_p), + (int) for_info_p->expression_location.line, + (int) for_info_p->expression_location.column, + (int) (for_info_p->end_location.source_p - source_start_p), + (int) for_info_p->end_location.line, + (int) for_info_p->end_location.column); + break; + } + case SCANNER_TYPE_FOR_IN: + { + name_p = "FOR-IN"; + print_location = true; + break; + } +#if ENABLED (JERRY_ES2015_FOR_OF) + case SCANNER_TYPE_FOR_OF: + { + name_p = "FOR-OF"; + print_location = true; + break; + } +#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ + case SCANNER_TYPE_SWITCH: + { + JERRY_DEBUG_MSG (" SWITCH: source:%d\n", + (int) (info_p->source_p - source_start_p)); + + scanner_case_info_t *current_case_p = ((scanner_switch_info_t *) info_p)->case_p; + + while (current_case_p != NULL) + { + JERRY_DEBUG_MSG (" CASE: location:%d[%d:%d]\n", + (int) (current_case_p->location.source_p - source_start_p), + (int) current_case_p->location.line, + (int) current_case_p->location.column); + + current_case_p = current_case_p->next_p; + } + break; + } + case SCANNER_TYPE_CASE: + { + name_p = "CASE"; + print_location = true; + break; + } +#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) + case SCANNER_TYPE_ARROW: + { + JERRY_DEBUG_MSG (" ARROW: source:%d\n", (int) (info_p->source_p - source_start_p)); + break; + } +#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ + } + + if (print_location) + { + scanner_location_info_t *location_info_p = (scanner_location_info_t *) info_p; + JERRY_DEBUG_MSG (" %s: source:%d location:%d[%d:%d]\n", + name_p, + (int) (location_info_p->info.source_p - source_start_p), + (int) (location_info_p->location.source_p - source_start_p), + (int) location_info_p->location.line, + (int) location_info_p->location.column); + } + + info_p = info_p->next_p; + } + + JERRY_DEBUG_MSG ("\n--- Scanning end ---\n\n"); + } +#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ + + parser_stack_free (context_p); +} /* scanner_scan_all */ + +/** + * @} + * @} + * @} + */ + +#endif /* ENABLED (JERRY_PARSER) */ diff --git a/jerry-core/parser/js/js-scanner.h b/jerry-core/parser/js/js-scanner.h new file mode 100644 index 000000000..b388f046b --- /dev/null +++ b/jerry-core/parser/js/js-scanner.h @@ -0,0 +1,111 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef JS_SCANNER_H +#define JS_SCANNER_H + +/** \addtogroup parser Parser + * @{ + * + * \addtogroup jsparser JavaScript + * @{ + * + * \addtogroup jsparser_scanner Scanner + * @{ + */ + +/** + * Allowed types for scanner_info_t structures. + */ +typedef enum +{ + SCANNER_TYPE_END, /**< mark the last info block */ + SCANNER_TYPE_WHILE, /**< while statement */ + SCANNER_TYPE_FOR, /**< for statement */ + SCANNER_TYPE_FOR_IN, /**< for-in statement */ +#if ENABLED (JERRY_ES2015_FOR_OF) + SCANNER_TYPE_FOR_OF, /**< for-of statement */ +#endif /* ENABLED (JERRY_ES2015_FOR_OF) */ + SCANNER_TYPE_SWITCH, /**< switch statement */ + SCANNER_TYPE_CASE, /**< case statement */ +#if ENABLED (JERRY_ES2015_ARROW_FUNCTION) + SCANNER_TYPE_ARROW, /**< arrow function */ +#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */ +} scanner_info_type_t; + +/** + * Source code location which can be used to change the position of parsing. + */ +typedef struct +{ + const uint8_t *source_p; /**< next source byte */ + parser_line_counter_t line; /**< token start line */ + parser_line_counter_t column; /**< token start column */ +} scanner_location_t; + +/** + * Scanner info blocks which provides information for the parser. + */ +typedef struct scanner_info_t +{ + struct scanner_info_t *next_p; /**< next info structure */ + const uint8_t *source_p; /**< triggering position of this scanner info */ + uint8_t type; /**< type of the scanner info */ +} scanner_info_t; + +/** + * Scanner info extended with a location. + */ +typedef struct +{ + scanner_info_t info; /**< header */ + scanner_location_t location; /**< location */ +} scanner_location_info_t; + +/** + * Scanner info for "for" statements. + */ +typedef struct +{ + scanner_info_t info; /**< header */ + scanner_location_t expression_location; /**< location of expression start */ + scanner_location_t end_location; /**< location of expression end */ +} scanner_for_info_t; + +/** + * Case statement list for scanner_switch_info_t structure. + */ +typedef struct scanner_case_info_t +{ + struct scanner_case_info_t *next_p; /**< next case statement info */ + scanner_location_t location; /**< location of case statement */ +} scanner_case_info_t; + +/** + * Scanner info for "switch" statements. + */ +typedef struct +{ + scanner_info_t info; /**< header */ + scanner_case_info_t *case_p; /**< list of switch cases */ +} scanner_switch_info_t; + +/** + * @} + * @} + * @} + */ + +#endif /* !JS_SCANNER_H */ diff --git a/tests/jerry/es2015/arrow-function.js b/tests/jerry/es2015/arrow-function.js index 9a8e90e15..64d499d04 100644 --- a/tests/jerry/es2015/arrow-function.js +++ b/tests/jerry/es2015/arrow-function.js @@ -125,6 +125,13 @@ default: func = () => ((([0,0,0]))) assert (func ().length == 3); + + func = (a = 5, b = 7 * 2) => a + b; + assert (func() == 19); + assert (func(1) == 15); + + func = (a = Math.cos(0)) => a; + assert (func() == 1); } must_throw ("var x => x;"); @@ -136,6 +143,7 @@ must_throw ("(x,y,) => 0"); must_throw ("x\n => 0"); must_throw ("this => 0"); must_throw ("(true) => 0"); +must_throw ("()\n=>5"); must_throw_strict ("(package) => 0"); must_throw_strict ("(package) => { return 5 }"); must_throw_strict ("(x,x,x) => 0"); diff --git a/tests/jerry/es2015/module-export-01.js b/tests/jerry/es2015/module-export-01.js index 90bfff549..a094fedb7 100644 --- a/tests/jerry/es2015/module-export-01.js +++ b/tests/jerry/es2015/module-export-01.js @@ -39,3 +39,6 @@ assert (x === 42); assert (f(1) === 1); var dog = new Dog("Pluto") assert(dog.speak() === "Pluto barks.") + +// Pre-scanner regression test +for (var tmp in {}) ; diff --git a/tests/jerry/es2015/module-export-02.js b/tests/jerry/es2015/module-export-02.js index 6fddc5f09..198a148ab 100644 --- a/tests/jerry/es2015/module-export-02.js +++ b/tests/jerry/es2015/module-export-02.js @@ -18,3 +18,6 @@ export {aa,} from "module-export-01.js"; export {bb as b_, cc as c_} from "module-export-01.js"; export * from "module-export-01.js"; export default function () {return "default"}; + +// Pre-scanner regression test +for (var tmp in {}) ; diff --git a/tests/jerry/es2015/module-export-03.js b/tests/jerry/es2015/module-export-03.js index eb8850c36..4ac8be546 100644 --- a/tests/jerry/es2015/module-export-03.js +++ b/tests/jerry/es2015/module-export-03.js @@ -24,3 +24,6 @@ export default class { } export * from "module-export-02.js" + +// Pre-scanner regression test +for (var tmp in {}) ; diff --git a/tests/jerry/es2015/module-export-04.js b/tests/jerry/es2015/module-export-04.js index 39d7caecd..360781cbe 100644 --- a/tests/jerry/es2015/module-export-04.js +++ b/tests/jerry/es2015/module-export-04.js @@ -15,3 +15,6 @@ export var x = 41 export default a = "str" + +// Pre-scanner regression test +for (var tmp in {}) ; diff --git a/tests/jerry/es2015/module-export-05.js b/tests/jerry/es2015/module-export-05.js index 5a6349c02..bf0a0b684 100644 --- a/tests/jerry/es2015/module-export-05.js +++ b/tests/jerry/es2015/module-export-05.js @@ -16,3 +16,6 @@ export * from "module-export-01.js"; export * from "module-export-04.js"; export default a = "str" + +// Pre-scanner regression test +for (var tmp in {}) ; diff --git a/tests/jerry/es2015/module-export-06.js b/tests/jerry/es2015/module-export-06.js index 8c614a490..f52854a2b 100644 --- a/tests/jerry/es2015/module-export-06.js +++ b/tests/jerry/es2015/module-export-06.js @@ -17,3 +17,6 @@ export {} export {} from "module-export-01.js"; export {}; export {} from "module-export-04.js" + +// Pre-scanner regression test +for (var tmp in {}) ; diff --git a/tests/jerry/es2015/module-export-07.js b/tests/jerry/es2015/module-export-07.js index 39dea13ee..798cc4dd1 100644 --- a/tests/jerry/es2015/module-export-07.js +++ b/tests/jerry/es2015/module-export-07.js @@ -15,3 +15,6 @@ var y, z; export default x = y = z = "default"; + +// Pre-scanner regression test +for (var tmp in {}) ; diff --git a/tests/jerry/es2015/module-import-01.js b/tests/jerry/es2015/module-import-01.js index 54f6826f5..97424163e 100644 --- a/tests/jerry/es2015/module-import-01.js +++ b/tests/jerry/es2015/module-import-01.js @@ -31,3 +31,6 @@ assert (mod.f("str") === "str") var dog = new mod.Dog("Oddie") assert (dog.speak() === "Oddie barks.") + +// Pre-scanner regression test +for (var tmp in {}) ; diff --git a/tests/jerry/es2015/module-import-02.js b/tests/jerry/es2015/module-import-02.js index 669c7a49e..6b3d7da04 100644 --- a/tests/jerry/es2015/module-import-02.js +++ b/tests/jerry/es2015/module-import-02.js @@ -22,3 +22,6 @@ assert (b_ === 5) assert (c_(b_) === 10) assert (mod.x === 42) assert (Array.isArray(mod.d)) + +// Pre-scanner regression test +for (var tmp in {}) ; diff --git a/tests/jerry/es2015/module-import-03.js b/tests/jerry/es2015/module-import-03.js index 11214a9e6..49cd5e989 100644 --- a/tests/jerry/es2015/module-import-03.js +++ b/tests/jerry/es2015/module-import-03.js @@ -22,3 +22,6 @@ assert(i.incr() === 6); assert (aa === "a"); assert (x === 42); assert (c_(x) == 84); + +// Pre-scanner regression test +for (var tmp in {}) ; diff --git a/tests/jerry/es2015/module-import-04.js b/tests/jerry/es2015/module-import-04.js index f0a5181a1..91abdc34a 100644 --- a/tests/jerry/es2015/module-import-04.js +++ b/tests/jerry/es2015/module-import-04.js @@ -17,3 +17,6 @@ import "module-import-01.js"; import "module-export-05.js"; import "module-export-06.js"; import "module-export-07.js"; + +// Pre-scanner regression test +for (var tmp in {}) ; diff --git a/tests/jerry/regression-test-issue-1555.js b/tests/jerry/regression-test-issue-1555.js index c277bfaf3..6e2db192e 100644 --- a/tests/jerry/regression-test-issue-1555.js +++ b/tests/jerry/regression-test-issue-1555.js @@ -14,7 +14,7 @@ var src = "var a = 0; while(a) { switch(a) {"; /* The += operation has a longer opcode. */ -for (var i = 0; i < 4000; i++) +for (var i = 0; i < 3500; i++) src += "case " + i + ": a += a += a; break; "; src += "} }";