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 += "} }";