Dániel Bátyai 68909fc5de
Fix lexical scoping between scripts (#3558)
This change fixes the handling of lexical blocks when executing multiple
scripts, and also fixes a few issues with module environments.

After this change, all script files will run in the same context and
will have access to lexically scoped global variables of previous
scripts, and module environments will no longer have a bound global
'this' value.

The REPL implementation in main-unix is also fixed to correctly handle
lexically scoped variables.

Fixes #3561.

JerryScript-DCO-1.0-Signed-off-by: Dániel Bátyai dbatyai@inf.u-szeged.hu
2020-02-21 13:30:48 +01:00

3374 lines
105 KiB
C

/* 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 "jcontext.h"
#include "js-parser-internal.h"
#include "js-scanner-internal.h"
#include "lit-char-helpers.h"
#if ENABLED (JERRY_PARSER)
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_scanner Scanner
* @{
*/
/**
* Scan return types.
*/
typedef enum
{
SCAN_NEXT_TOKEN, /**< get next token after return */
SCAN_KEEP_TOKEN, /**< keep the current token after return */
} scan_return_types_t;
/**
* Checks whether token type is "of".
*/
#if ENABLED (JERRY_ES2015)
#define SCANNER_IDENTIFIER_IS_OF() (lexer_token_is_identifier (context_p, "of", 2))
#else
#define SCANNER_IDENTIFIER_IS_OF() (false)
#endif /* ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_ES2015)
/**
* Returns the correct computed property mode based on the literal_pool_flags.
*/
#define GET_COMPUTED_PROPERTY_MODE(literal_pool_flags) \
(((literal_pool_flags) & SCANNER_LITERAL_POOL_GENERATOR) ? SCAN_STACK_COMPUTED_GENERATOR_FUNCTION \
: SCAN_STACK_COMPUTED_PROPERTY)
#endif /* ENABLED (JERRY_ES2015) */
/**
* Scan primary expression.
*
* @return SCAN_NEXT_TOKEN to read the next token, or SCAN_KEEP_TOKEN to do nothing
*/
static scan_return_types_t
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;
#if ENABLED (JERRY_ES2015)
if (scanner_try_scan_new_target (context_p))
{
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
}
#endif /* ENABLED (JERRY_ES2015) */
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:
{
scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
#if ENABLED (JERRY_ES2015)
context_p->status_flags &= (uint32_t) ~PARSER_IS_GENERATOR_FUNCTION;
#endif /* ENABLED (JERRY_ES2015) */
lexer_next_token (context_p);
#if ENABLED (JERRY_ES2015)
if (context_p->token.type == LEXER_MULTIPLY)
{
scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_GENERATOR;
context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION;
lexer_next_token (context_p);
}
#endif /* ENABLED (JERRY_ES2015) */
if (context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
{
lexer_next_token (context_p);
}
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_EXPRESSION);
scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS;
return SCAN_KEEP_TOKEN;
}
case LEXER_LEFT_PAREN:
{
scanner_scan_bracket (context_p, scanner_context_p);
return SCAN_KEEP_TOKEN;
}
case LEXER_LEFT_SQUARE:
{
#if ENABLED (JERRY_ES2015)
scanner_push_destructuring_pattern (context_p, scanner_context_p, SCANNER_BINDING_NONE, false);
#endif /* ENABLED (JERRY_ES2015) */
parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL);
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
case LEXER_LEFT_BRACE:
{
#if ENABLED (JERRY_ES2015)
scanner_push_destructuring_pattern (context_p, scanner_context_p, SCANNER_BINDING_NONE, false);
#endif /* ENABLED (JERRY_ES2015) */
parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL);
scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME;
return SCAN_KEEP_TOKEN;
}
#if ENABLED (JERRY_ES2015)
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) */
case LEXER_LITERAL:
{
#if ENABLED (JERRY_ES2015)
const uint8_t *source_p = context_p->source_p;
if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL
&& lexer_check_arrow (context_p))
{
scanner_scan_simple_arrow (context_p, scanner_context_p, source_p);
return SCAN_KEEP_TOKEN;
}
else if (JERRY_UNLIKELY (lexer_token_is_async (context_p)))
{
scanner_context_p->async_source_p = source_p;
scanner_check_async_function (context_p, scanner_context_p);
return SCAN_KEEP_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015) */
if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
{
scanner_add_reference (context_p, scanner_context_p);
}
/* FALLTHRU */
}
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)
case LEXER_KEYW_CLASS:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_EXPRESSION);
scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION;
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
return SCAN_KEEP_TOKEN;
}
break;
}
#endif /* ENABLED (JERRY_ES2015) */
case LEXER_RIGHT_SQUARE:
{
if (stack_top != SCAN_STACK_ARRAY_LITERAL)
{
scanner_raise_error (context_p);
}
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
return SCAN_KEEP_TOKEN;
}
#if ENABLED (JERRY_ES2015)
case LEXER_THREE_DOTS:
#endif /* ENABLED (JERRY_ES2015) */
case LEXER_COMMA:
{
/* Elision or spread arguments */
#if ENABLED (JERRY_ES2015)
bool raise_error = (stack_top != SCAN_STACK_PAREN_EXPRESSION && stack_top != SCAN_STACK_ARRAY_LITERAL);
#else /* !ENABLED (JERRY_ES2015) */
bool raise_error = stack_top != SCAN_STACK_ARRAY_LITERAL;
#endif /* ENABLED (JERRY_ES2015) */
if (raise_error)
{
scanner_raise_error (context_p);
}
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
#if ENABLED (JERRY_ES2015)
if (scanner_context_p->binding_type != SCANNER_BINDING_NONE)
{
scanner_context_p->mode = SCAN_MODE_BINDING;
}
#endif /* ENABLED (JERRY_ES2015) */
break;
}
#if ENABLED (JERRY_ES2015)
case LEXER_KEYW_YIELD:
{
lexer_next_token (context_p);
if (lexer_check_yield_no_arg (context_p))
{
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
}
if (context_p->token.type == LEXER_MULTIPLY)
{
return SCAN_NEXT_TOKEN;
}
return SCAN_KEEP_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015) */
case LEXER_RIGHT_PAREN:
{
if (stack_top == SCAN_STACK_PAREN_EXPRESSION)
{
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
parser_stack_pop_uint8 (context_p);
break;
}
/* FALLTHRU */
}
default:
{
scanner_raise_error (context_p);
}
}
return SCAN_NEXT_TOKEN;
} /* 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 */
scan_stack_modes_t stack_top) /**< current stack top */
{
switch (type)
{
case LEXER_DOT:
{
lexer_scan_identifier (context_p);
if (context_p->token.type != LEXER_LITERAL
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
scanner_raise_error (context_p);
}
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;
}
#if ENABLED (JERRY_ES2015)
case LEXER_TEMPLATE_LITERAL:
{
if (JERRY_UNLIKELY (context_p->source_p[-1] != LIT_CHAR_GRAVE_ACCENT))
{
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
parser_stack_push_uint8 (context_p, SCAN_STACK_TAGGED_TEMPLATE_LITERAL);
}
return true;
}
#endif /* ENABLED (JERRY_ES2015) */
case LEXER_LEFT_SQUARE:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_PROPERTY_ACCESSOR);
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
return true;
}
case LEXER_INCREASE:
case LEXER_DECREASE:
{
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
if (context_p->token.flags & LEXER_WAS_NEWLINE)
{
return false;
}
lexer_next_token (context_p);
type = (lexer_token_type_t) context_p->token.type;
if (type != LEXER_QUESTION_MARK)
{
break;
}
/* FALLTHRU */
}
case LEXER_QUESTION_MARK:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_COLON_EXPRESSION);
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
return true;
}
default:
{
break;
}
}
if (LEXER_IS_BINARY_OP_TOKEN (type)
&& (type != LEXER_KEYW_IN || !SCANNER_IS_FOR_START (stack_top)))
{
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
return true;
}
return false;
} /* scanner_scan_post_primary_expression */
/**
* Scan the tokens after the primary expression.
*
* @return SCAN_NEXT_TOKEN to read the next token, or SCAN_KEEP_TOKEN to do nothing
*/
static scan_return_types_t
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 */
{
if (type == LEXER_COMMA)
{
switch (stack_top)
{
case SCAN_STACK_VAR:
#if ENABLED (JERRY_ES2015)
case SCAN_STACK_LET:
case SCAN_STACK_CONST:
#endif /* ENABLED (JERRY_ES2015) */
case SCAN_STACK_FOR_VAR_START:
#if ENABLED (JERRY_ES2015)
case SCAN_STACK_FOR_LET_START:
case SCAN_STACK_FOR_CONST_START:
#endif /* ENABLED (JERRY_ES2015) */
{
scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT;
return SCAN_NEXT_TOKEN;
}
case SCAN_STACK_COLON_EXPRESSION:
{
scanner_raise_error (context_p);
break;
}
#if ENABLED (JERRY_ES2015)
case SCAN_STACK_BINDING_INIT:
case SCAN_STACK_BINDING_LIST_INIT:
{
break;
}
case SCAN_STACK_ARROW_ARGUMENTS:
{
lexer_next_token (context_p);
scanner_check_arrow_arg (context_p, scanner_context_p);
return SCAN_KEEP_TOKEN;
}
case SCAN_STACK_ARROW_EXPRESSION:
{
break;
}
case SCAN_STACK_FUNCTION_PARAMETERS:
{
scanner_context_p->mode = SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS;
parser_stack_pop_uint8 (context_p);
return SCAN_NEXT_TOKEN;
}
case SCAN_STACK_ARRAY_LITERAL:
{
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
if (scanner_context_p->binding_type != SCANNER_BINDING_NONE)
{
scanner_context_p->mode = SCAN_MODE_BINDING;
}
return SCAN_NEXT_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015) */
case SCAN_STACK_OBJECT_LITERAL:
{
scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME;
return SCAN_KEEP_TOKEN;
}
default:
{
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
return SCAN_NEXT_TOKEN;
}
}
}
switch (stack_top)
{
case SCAN_STACK_WITH_EXPRESSION:
{
if (type != LEXER_RIGHT_PAREN)
{
break;
}
parser_stack_pop_uint8 (context_p);
uint16_t status_flags = scanner_context_p->active_literal_pool_p->status_flags;
parser_stack_push_uint8 (context_p, (status_flags & SCANNER_LITERAL_POOL_IN_WITH) ? 1 : 0);
parser_stack_push_uint8 (context_p, SCAN_STACK_WITH_STATEMENT);
status_flags |= SCANNER_LITERAL_POOL_IN_WITH;
scanner_context_p->active_literal_pool_p->status_flags = status_flags;
scanner_context_p->mode = SCAN_MODE_STATEMENT;
return SCAN_NEXT_TOKEN;
}
case SCAN_STACK_DO_EXPRESSION:
{
if (type != LEXER_RIGHT_PAREN)
{
break;
}
scanner_context_p->mode = SCAN_MODE_STATEMENT_END;
return SCAN_NEXT_TOKEN;
}
case SCAN_STACK_WHILE_EXPRESSION:
{
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 SCAN_NEXT_TOKEN;
}
case SCAN_STACK_PAREN_EXPRESSION:
{
if (type != LEXER_RIGHT_PAREN)
{
break;
}
parser_stack_pop_uint8 (context_p);
#if ENABLED (JERRY_ES2015)
if (context_p->stack_top_uint8 == SCAN_STACK_USE_ASYNC)
{
scanner_add_async_literal (context_p, scanner_context_p);
}
#endif /* ENABLED (JERRY_ES2015) */
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
return SCAN_NEXT_TOKEN;
}
case SCAN_STACK_STATEMENT_WITH_EXPR:
{
if (type != LEXER_RIGHT_PAREN)
{
break;
}
scanner_context_p->mode = SCAN_MODE_STATEMENT;
parser_stack_pop_uint8 (context_p);
return SCAN_NEXT_TOKEN;
}
#if ENABLED (JERRY_ES2015)
case SCAN_STACK_BINDING_LIST_INIT:
{
parser_stack_pop_uint8 (context_p);
JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_ARRAY_LITERAL
|| context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL
|| context_p->stack_top_uint8 == SCAN_STACK_LET
|| context_p->stack_top_uint8 == SCAN_STACK_CONST
|| context_p->stack_top_uint8 == SCAN_STACK_FOR_LET_START
|| context_p->stack_top_uint8 == SCAN_STACK_FOR_CONST_START
|| context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_PARAMETERS
|| context_p->stack_top_uint8 == SCAN_STACK_ARROW_ARGUMENTS);
scanner_binding_item_t *item_p = scanner_context_p->active_binding_list_p->items_p;
uint8_t flag = SCANNER_LITERAL_NO_REG;
if (scanner_context_p->binding_type == SCANNER_BINDING_ARROW_ARG)
{
flag = SCANNER_LITERAL_ARROW_DESTRUCTURED_ARG_NO_REG;
}
while (item_p != NULL)
{
if (item_p->literal_p->type & SCANNER_LITERAL_IS_USED)
{
item_p->literal_p->type |= flag;
}
item_p = item_p->next_p;
}
scanner_pop_binding_list (scanner_context_p);
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
return SCAN_KEEP_TOKEN;
}
case SCAN_STACK_BINDING_INIT:
{
scanner_binding_literal_t binding_literal;
parser_stack_pop_uint8 (context_p);
parser_stack_pop (context_p, &binding_literal, sizeof (scanner_binding_literal_t));
JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_ARRAY_LITERAL
|| context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL
|| context_p->stack_top_uint8 == SCAN_STACK_LET
|| context_p->stack_top_uint8 == SCAN_STACK_CONST
|| context_p->stack_top_uint8 == SCAN_STACK_FOR_LET_START
|| context_p->stack_top_uint8 == SCAN_STACK_FOR_CONST_START
|| context_p->stack_top_uint8 == SCAN_STACK_ARROW_ARGUMENTS);
if (binding_literal.literal_p->type & SCANNER_LITERAL_IS_USED)
{
stack_top = (scan_stack_modes_t) context_p->stack_top_uint8;
if ((stack_top == SCAN_STACK_ARRAY_LITERAL || stack_top == SCAN_STACK_OBJECT_LITERAL)
&& (scanner_context_p->binding_type == SCANNER_BINDING_ARROW_ARG))
{
binding_literal.literal_p->type |= SCANNER_LITERAL_ARROW_DESTRUCTURED_ARG_NO_REG;
}
else
{
binding_literal.literal_p->type |= SCANNER_LITERAL_NO_REG;
}
}
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
return SCAN_KEEP_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015) */
case SCAN_STACK_VAR:
#if ENABLED (JERRY_ES2015)
case SCAN_STACK_LET:
case SCAN_STACK_CONST:
#endif /* ENABLED (JERRY_ES2015) */
{
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
scanner_context_p->active_literal_pool_p->status_flags &= (uint16_t) ~SCANNER_LITERAL_POOL_IN_EXPORT;
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
parser_stack_pop_uint8 (context_p);
return SCAN_KEEP_TOKEN;
}
case SCAN_STACK_FOR_VAR_START:
#if ENABLED (JERRY_ES2015)
case SCAN_STACK_FOR_LET_START:
case SCAN_STACK_FOR_CONST_START:
#endif /* ENABLED (JERRY_ES2015) */
case SCAN_STACK_FOR_START:
{
if (type == LEXER_KEYW_IN || SCANNER_IDENTIFIER_IS_OF ())
{
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)
location_info->info.type = (type == LEXER_KEYW_IN) ? SCANNER_TYPE_FOR_IN : SCANNER_TYPE_FOR_OF;
if (stack_top == SCAN_STACK_FOR_LET_START || stack_top == SCAN_STACK_FOR_CONST_START)
{
parser_stack_push_uint8 (context_p, SCAN_STACK_FOR_BLOCK_END);
}
#else /* !ENABLED (JERRY_ES2015) */
location_info->info.type = SCANNER_TYPE_FOR_IN;
#endif /* ENABLED (JERRY_ES2015) */
scanner_get_location (&location_info->location, context_p);
parser_stack_push_uint8 (context_p, SCAN_STACK_STATEMENT_WITH_EXPR);
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
return SCAN_NEXT_TOKEN;
}
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));
#if ENABLED (JERRY_ES2015)
if (stack_top == SCAN_STACK_FOR_LET_START || stack_top == SCAN_STACK_FOR_CONST_START)
{
parser_stack_push_uint8 (context_p, SCAN_STACK_FOR_BLOCK_END);
}
#endif /* ENABLED (JERRY_ES2015) */
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 SCAN_KEEP_TOKEN;
}
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 SCAN_KEEP_TOKEN;
}
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 SCAN_NEXT_TOKEN;
}
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;
}
#if ENABLED (JERRY_ES2015)
scanner_literal_pool_t *literal_pool_p;
literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_BLOCK);
literal_pool_p->source_p = context_p->source_p - 1;
#endif /* ENABLED (JERRY_ES2015) */
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_OR_TERMINATOR;
return SCAN_KEEP_TOKEN;
}
case SCAN_STACK_CASE_STATEMENT:
{
if (type != LEXER_COLON)
{
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_OR_TERMINATOR;
return SCAN_NEXT_TOKEN;
}
case SCAN_STACK_COLON_EXPRESSION:
{
if (type != LEXER_COLON)
{
break;
}
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
parser_stack_pop_uint8 (context_p);
return SCAN_NEXT_TOKEN;
}
#if ENABLED (JERRY_ES2015)
case SCAN_STACK_ARRAY_LITERAL:
case SCAN_STACK_OBJECT_LITERAL:
{
if (((stack_top == SCAN_STACK_ARRAY_LITERAL) && (type != LEXER_RIGHT_SQUARE))
|| ((stack_top == SCAN_STACK_OBJECT_LITERAL) && (type != LEXER_RIGHT_BRACE)))
{
break;
}
scanner_source_start_t source_start;
uint8_t binding_type = scanner_context_p->binding_type;
parser_stack_pop_uint8 (context_p);
scanner_context_p->binding_type = context_p->stack_top_uint8;
parser_stack_pop_uint8 (context_p);
parser_stack_pop (context_p, &source_start, sizeof (scanner_source_start_t));
lexer_next_token (context_p);
if (binding_type == SCANNER_BINDING_CATCH && context_p->stack_top_uint8 == SCAN_STACK_CATCH_STATEMENT)
{
scanner_pop_binding_list (scanner_context_p);
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_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
return SCAN_NEXT_TOKEN;
}
if (context_p->token.type != LEXER_ASSIGN)
{
if (SCANNER_NEEDS_BINDING_LIST (binding_type))
{
scanner_pop_binding_list (scanner_context_p);
}
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
return SCAN_KEEP_TOKEN;
}
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_INITIALIZER;
scanner_get_location (&location_info_p->location, context_p);
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
if (SCANNER_NEEDS_BINDING_LIST (binding_type))
{
scanner_binding_item_t *item_p = scanner_context_p->active_binding_list_p->items_p;
while (item_p != NULL)
{
item_p->literal_p->type &= (uint8_t) ~SCANNER_LITERAL_IS_USED;
item_p = item_p->next_p;
}
parser_stack_push_uint8 (context_p, SCAN_STACK_BINDING_LIST_INIT);
}
return SCAN_NEXT_TOKEN;
}
#else /* !ENABLED (JERRY_ES2015) */
case SCAN_STACK_ARRAY_LITERAL:
#endif /* ENABLED (JERRY_ES2015) */
case SCAN_STACK_PROPERTY_ACCESSOR:
{
if (type != LEXER_RIGHT_SQUARE)
{
break;
}
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
parser_stack_pop_uint8 (context_p);
return SCAN_NEXT_TOKEN;
}
#if !ENABLED (JERRY_ES2015)
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 SCAN_NEXT_TOKEN;
}
#endif /* !ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_ES2015)
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_FUNCTION_PROPERTY)
{
scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS;
return SCAN_KEEP_TOKEN;
}
JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL);
if (context_p->token.type == LEXER_LEFT_PAREN)
{
scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS;
return SCAN_KEEP_TOKEN;
}
if (context_p->token.type != LEXER_COLON)
{
scanner_raise_error (context_p);
}
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
if (scanner_context_p->binding_type != SCANNER_BINDING_NONE)
{
scanner_context_p->mode = SCAN_MODE_BINDING;
}
return SCAN_NEXT_TOKEN;
}
case SCAN_STACK_COMPUTED_GENERATOR_FUNCTION:
{
if (type != LEXER_RIGHT_SQUARE)
{
break;
}
lexer_next_token (context_p);
parser_stack_pop_uint8 (context_p);
JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL
|| context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_PROPERTY);
scanner_push_literal_pool (context_p,
scanner_context_p,
SCANNER_LITERAL_POOL_FUNCTION | SCANNER_LITERAL_POOL_GENERATOR);
context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION;
scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS;
return SCAN_KEEP_TOKEN;
}
case SCAN_STACK_TEMPLATE_STRING:
case SCAN_STACK_TAGGED_TEMPLATE_LITERAL:
{
if (type != LEXER_RIGHT_BRACE)
{
break;
}
context_p->source_p--;
context_p->column--;
lexer_parse_string (context_p, LEXER_STRING_NO_OPTS);
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 SCAN_NEXT_TOKEN;
}
case SCAN_STACK_ARROW_ARGUMENTS:
{
if (type != LEXER_RIGHT_PAREN)
{
break;
}
scanner_check_arrow (context_p, scanner_context_p);
return SCAN_KEEP_TOKEN;
}
case SCAN_STACK_ARROW_EXPRESSION:
{
scanner_pop_literal_pool (context_p, scanner_context_p);
parser_stack_pop_uint8 (context_p);
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
return SCAN_KEEP_TOKEN;
}
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 SCAN_KEEP_TOKEN;
}
case SCAN_STACK_FUNCTION_PARAMETERS:
{
parser_stack_pop_uint8 (context_p);
if (type != LEXER_RIGHT_PAREN
&& (type != LEXER_EOS || context_p->stack_top_uint8 != SCAN_STACK_SCRIPT_FUNCTION))
{
break;
}
scanner_context_p->mode = SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS;
return SCAN_KEEP_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015) */
default:
{
scanner_context_p->mode = SCAN_MODE_STATEMENT_END;
return SCAN_KEEP_TOKEN;
}
}
scanner_raise_error (context_p);
return SCAN_NEXT_TOKEN;
} /* scanner_scan_primary_expression_end */
/**
* Scan statements.
*
* @return SCAN_NEXT_TOKEN to read the next token, or SCAN_KEEP_TOKEN to do nothing
*/
static scan_return_types_t
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:
{
scanner_context_p->mode = SCAN_MODE_STATEMENT_END;
return SCAN_KEEP_TOKEN;
}
case LEXER_LEFT_BRACE:
{
#if ENABLED (JERRY_ES2015)
scanner_literal_pool_t *literal_pool_p;
literal_pool_p = scanner_push_literal_pool (context_p,
scanner_context_p,
SCANNER_LITERAL_POOL_BLOCK);
literal_pool_p->source_p = context_p->source_p;
#endif /* ENABLED (JERRY_ES2015) */
scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT);
return SCAN_NEXT_TOKEN;
}
case LEXER_KEYW_DO:
{
scanner_context_p->mode = SCAN_MODE_STATEMENT;
parser_stack_push_uint8 (context_p, SCAN_STACK_DO_STATEMENT);
return SCAN_NEXT_TOKEN;
}
case LEXER_KEYW_TRY:
{
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LEFT_BRACE)
{
scanner_raise_error (context_p);
}
#if ENABLED (JERRY_ES2015)
scanner_literal_pool_t *literal_pool_p;
literal_pool_p = scanner_push_literal_pool (context_p,
scanner_context_p,
SCANNER_LITERAL_POOL_BLOCK);
literal_pool_p->source_p = context_p->source_p;
#endif /* ENABLED (JERRY_ES2015) */
scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
parser_stack_push_uint8 (context_p, SCAN_STACK_TRY_STATEMENT);
return SCAN_NEXT_TOKEN;
}
case LEXER_KEYW_DEBUGGER:
{
scanner_context_p->mode = SCAN_MODE_STATEMENT_END;
return SCAN_NEXT_TOKEN;
}
case LEXER_KEYW_IF:
case LEXER_KEYW_WITH:
case LEXER_KEYW_SWITCH:
{
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LEFT_PAREN)
{
scanner_raise_error (context_p);
}
uint8_t mode = SCAN_STACK_STATEMENT_WITH_EXPR;
if (type == LEXER_KEYW_IF)
{
parser_stack_push_uint8 (context_p, SCAN_STACK_IF_STATEMENT);
}
else if (type == LEXER_KEYW_WITH)
{
mode = SCAN_STACK_WITH_EXPRESSION;
}
else if (type == LEXER_KEYW_SWITCH)
{
mode = SCAN_STACK_SWITCH_EXPRESSION;
}
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
parser_stack_push_uint8 (context_p, mode);
return SCAN_NEXT_TOKEN;
}
case LEXER_KEYW_WHILE:
{
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LEFT_PAREN)
{
scanner_raise_error (context_p);
}
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
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_EXPRESSION);
return SCAN_NEXT_TOKEN;
}
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;
uint8_t stack_mode = SCAN_STACK_FOR_START;
scan_return_types_t return_type = SCAN_KEEP_TOKEN;
lexer_next_token (context_p);
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
#if ENABLED (JERRY_ES2015)
const uint8_t *source_p = context_p->source_p;
#endif /* ENABLED (JERRY_ES2015) */
switch (context_p->token.type)
{
case LEXER_SEMICOLON:
{
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
break;
}
case LEXER_KEYW_VAR:
{
scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT;
stack_mode = SCAN_STACK_FOR_VAR_START;
return_type = SCAN_NEXT_TOKEN;
break;
}
#if ENABLED (JERRY_ES2015)
case LEXER_LITERAL:
{
if (!lexer_token_is_let (context_p))
{
break;
}
parser_line_counter_t line = context_p->line;
parser_line_counter_t column = context_p->column;
if (lexer_check_arrow (context_p))
{
context_p->source_p = source_p;
context_p->line = line;
context_p->column = column;
context_p->token.flags &= (uint8_t) ~LEXER_NO_SKIP_SPACES;
break;
}
lexer_next_token (context_p);
type = (lexer_token_type_t) context_p->token.type;
if (type != LEXER_LEFT_SQUARE
&& type != LEXER_LEFT_BRACE
&& (type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL))
{
scanner_info_t *info_p = scanner_insert_info (context_p, source_p, sizeof (scanner_info_t));
info_p->type = SCANNER_TYPE_LET_EXPRESSION;
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
break;
}
scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT;
/* FALLTHRU */
}
case LEXER_KEYW_LET:
case LEXER_KEYW_CONST:
{
scanner_literal_pool_t *literal_pool_p;
literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_BLOCK);
literal_pool_p->source_p = source_p;
if (scanner_context_p->mode == SCAN_MODE_PRIMARY_EXPRESSION)
{
scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT;
return_type = SCAN_NEXT_TOKEN;
}
stack_mode = ((context_p->token.type == LEXER_KEYW_CONST) ? SCAN_STACK_FOR_CONST_START
: SCAN_STACK_FOR_LET_START);
break;
}
#endif /* ENABLED (JERRY_ES2015) */
}
parser_stack_push (context_p, &for_statement, sizeof (scanner_for_statement_t));
parser_stack_push_uint8 (context_p, stack_mode);
return return_type;
}
case LEXER_KEYW_VAR:
{
scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT;
parser_stack_push_uint8 (context_p, SCAN_STACK_VAR);
return SCAN_NEXT_TOKEN;
}
#if ENABLED (JERRY_ES2015)
case LEXER_KEYW_LET:
{
scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT;
parser_stack_push_uint8 (context_p, SCAN_STACK_LET);
return SCAN_NEXT_TOKEN;
}
case LEXER_KEYW_CONST:
{
scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT;
parser_stack_push_uint8 (context_p, SCAN_STACK_CONST);
return SCAN_NEXT_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015) */
case LEXER_KEYW_THROW:
{
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
return SCAN_NEXT_TOKEN;
}
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_EOS
&& context_p->token.type != LEXER_RIGHT_BRACE)
{
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
return SCAN_KEEP_TOKEN;
}
scanner_context_p->mode = SCAN_MODE_STATEMENT_END;
return SCAN_KEEP_TOKEN;
}
case LEXER_KEYW_BREAK:
case LEXER_KEYW_CONTINUE:
{
lexer_next_token (context_p);
scanner_context_p->mode = SCAN_MODE_STATEMENT_END;
if (!(context_p->token.flags & LEXER_WAS_NEWLINE)
&& context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
{
return SCAN_NEXT_TOKEN;
}
return SCAN_KEEP_TOKEN;
}
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);
}
scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
return SCAN_NEXT_TOKEN;
}
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 SCAN_NEXT_TOKEN;
}
case LEXER_KEYW_FUNCTION:
{
lexer_next_token (context_p);
uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION;
#if ENABLED (JERRY_ES2015)
if (context_p->token.type == LEXER_MULTIPLY)
{
status_flags |= SCANNER_LITERAL_POOL_GENERATOR;
lexer_next_token (context_p);
/* This flag should be set after the function name is read. */
context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION;
}
else
{
context_p->status_flags &= (uint32_t) ~PARSER_IS_GENERATOR_FUNCTION;
}
#endif /* ENABLED (JERRY_ES2015) */
if (context_p->token.type != LEXER_LITERAL
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
scanner_raise_error (context_p);
}
lexer_lit_location_t *literal_p = scanner_add_literal (context_p, scanner_context_p);
#if ENABLED (JERRY_ES2015)
if (literal_p->type & SCANNER_LITERAL_IS_LOCAL
&& !(literal_p->type & (SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_ARG)))
{
scanner_raise_redeclaration_error (context_p);
}
literal_p->type |= SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_FUNC_DECLARATION;
#else
literal_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC;
#endif /* ENABLED (JERRY_ES2015) */
scanner_push_literal_pool (context_p, scanner_context_p, status_flags);
scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS;
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_STATEMENT);
return SCAN_NEXT_TOKEN;
}
#if ENABLED (JERRY_ES2015)
case LEXER_KEYW_CLASS:
{
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_lit_location_t *literal_p = scanner_add_literal (context_p, scanner_context_p);
scanner_detect_invalid_let (context_p, literal_p);
literal_p->type |= SCANNER_LITERAL_IS_LET;
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
if (scanner_context_p->active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_EXPORT)
{
literal_p->type |= SCANNER_LITERAL_NO_REG;
scanner_context_p->active_literal_pool_p->status_flags &= (uint16_t) ~SCANNER_LITERAL_POOL_IN_EXPORT;
}
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION;
parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_STATEMENT);
return SCAN_NEXT_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
case LEXER_KEYW_IMPORT:
{
if (stack_top != SCAN_STACK_SCRIPT)
{
scanner_raise_error (context_p);
}
scanner_context_p->context_status_flags |= PARSER_IS_MODULE;
scanner_context_p->mode = SCAN_MODE_STATEMENT_END;
lexer_next_token (context_p);
if (context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_STRING_LITERAL)
{
return SCAN_NEXT_TOKEN;
}
bool parse_imports = true;
if (context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
{
lexer_lit_location_t *literal_p = scanner_add_literal (context_p, scanner_context_p);
#if ENABLED (JERRY_ES2015)
scanner_detect_invalid_let (context_p, literal_p);
literal_p->type |= SCANNER_LITERAL_IS_LOCAL | SCANNER_LITERAL_NO_REG;
#else /* !ENABLED (JERRY_ES2015) */
literal_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_NO_REG;
#endif /* ENABLED (JERRY_ES2015) */
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_token_is_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_lit_location_t *literal_p = scanner_add_literal (context_p, scanner_context_p);
#if ENABLED (JERRY_ES2015)
scanner_detect_invalid_let (context_p, literal_p);
literal_p->type |= SCANNER_LITERAL_IS_LOCAL | SCANNER_LITERAL_NO_REG;
#else /* !ENABLED (JERRY_ES2015) */
literal_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_NO_REG;
#endif /* ENABLED (JERRY_ES2015) */
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);
}
#if ENABLED (JERRY_ES2015)
const uint8_t *source_p = context_p->source_p;
#endif /* ENABLED (JERRY_ES2015) */
if (lexer_check_next_character (context_p, LIT_CHAR_LOWERCASE_A))
{
lexer_next_token (context_p);
if (!lexer_token_is_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);
}
#if ENABLED (JERRY_ES2015)
source_p = context_p->source_p;
#endif /* ENABLED (JERRY_ES2015) */
}
lexer_lit_location_t *literal_p = scanner_add_literal (context_p, scanner_context_p);
#if ENABLED (JERRY_ES2015)
if (literal_p->type & (SCANNER_LITERAL_IS_ARG
| SCANNER_LITERAL_IS_VAR
| SCANNER_LITERAL_IS_LOCAL))
{
context_p->source_p = source_p;
scanner_raise_redeclaration_error (context_p);
}
if (literal_p->type & SCANNER_LITERAL_IS_FUNC)
{
literal_p->type &= (uint8_t) ~SCANNER_LITERAL_IS_FUNC;
}
literal_p->type |= SCANNER_LITERAL_IS_LOCAL | SCANNER_LITERAL_NO_REG;
#else /* !ENABLED (JERRY_ES2015) */
literal_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_NO_REG;
#endif /* ENABLED (JERRY_ES2015) */
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_token_is_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 SCAN_NEXT_TOKEN;
}
case LEXER_KEYW_EXPORT:
{
if (stack_top != SCAN_STACK_SCRIPT)
{
scanner_raise_error (context_p);
}
scanner_context_p->context_status_flags |= PARSER_IS_MODULE;
lexer_next_token (context_p);
if (context_p->token.type == LEXER_KEYW_DEFAULT)
{
lexer_next_token (context_p);
if (context_p->token.type == LEXER_KEYW_FUNCTION)
{
lexer_next_token (context_p);
if (context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
{
lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p);
#if ENABLED (JERRY_ES2015)
if (location_p->type & SCANNER_LITERAL_IS_LOCAL
&& !(location_p->type & SCANNER_LITERAL_IS_FUNC))
{
scanner_raise_redeclaration_error (context_p);
}
location_p->type |= SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_LET;
#else /* !ENABLED (JERRY_ES2015) */
location_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC;
#endif /* ENABLED (JERRY_ES2015) */
lexer_next_token (context_p);
}
else
{
lexer_lit_location_t *location_p;
location_p = scanner_add_custom_literal (context_p,
scanner_context_p->active_literal_pool_p,
&lexer_default_literal);
#if ENABLED (JERRY_ES2015)
location_p->type |= SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_LET;
#else /* !ENABLED (JERRY_ES2015) */
location_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC;
#endif /* ENABLED (JERRY_ES2015) */
}
scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION);
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_STATEMENT);
scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS;
return SCAN_KEEP_TOKEN;
}
#if ENABLED (JERRY_ES2015)
if (context_p->token.type == LEXER_KEYW_CLASS)
{
scanner_context_p->mode = SCAN_MODE_CLASS_DECLARATION;
parser_stack_push_uint8 (context_p, SCAN_STACK_CLASS_STATEMENT);
lexer_next_token (context_p);
if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
{
lexer_lit_location_t *literal_p = scanner_add_literal (context_p, scanner_context_p);
scanner_detect_invalid_let (context_p, literal_p);
literal_p->type |= SCANNER_LITERAL_IS_LET | SCANNER_LITERAL_NO_REG;
return SCAN_NEXT_TOKEN;
}
lexer_lit_location_t *literal_p;
literal_p = scanner_add_custom_literal (context_p,
scanner_context_p->active_literal_pool_p,
&lexer_default_literal);
literal_p->type |= SCANNER_LITERAL_IS_LET | SCANNER_LITERAL_NO_REG;
return SCAN_KEEP_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015) */
/* Assignment expression. */
lexer_lit_location_t *location_p;
location_p = scanner_add_custom_literal (context_p,
scanner_context_p->active_literal_pool_p,
&lexer_default_literal);
location_p->type |= SCANNER_LITERAL_IS_VAR;
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
return SCAN_KEEP_TOKEN;
}
location_p = scanner_add_literal (context_p, scanner_context_p);
location_p->type |= SCANNER_LITERAL_IS_VAR;
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
return SCAN_NEXT_TOKEN;
}
scanner_context_p->mode = SCAN_MODE_STATEMENT_END;
if (context_p->token.type == LEXER_MULTIPLY)
{
lexer_next_token (context_p);
if (!lexer_token_is_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 SCAN_NEXT_TOKEN;
}
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_token_is_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_token_is_identifier (context_p, "from", 4))
{
return SCAN_KEEP_TOKEN;
}
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 SCAN_NEXT_TOKEN;
}
switch (context_p->token.type)
{
#if ENABLED (JERRY_ES2015)
case LEXER_KEYW_CLASS:
case LEXER_KEYW_LET:
case LEXER_KEYW_CONST:
#endif /* ENABLED (JERRY_ES2015) */
case LEXER_KEYW_VAR:
{
scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_IN_EXPORT;
break;
}
}
scanner_context_p->mode = SCAN_MODE_STATEMENT;
return SCAN_KEEP_TOKEN;
}
#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)
{
if (JERRY_UNLIKELY (lexer_check_next_character (context_p, LIT_CHAR_COLON)))
{
lexer_consume_next_character (context_p);
scanner_context_p->mode = SCAN_MODE_STATEMENT;
return SCAN_NEXT_TOKEN;
}
JERRY_ASSERT (context_p->token.flags & LEXER_NO_SKIP_SPACES);
#if ENABLED (JERRY_ES2015)
/* The colon needs to be checked first because the parser also checks
* it first, and this check skips the spaces which affects source_p. */
if (JERRY_UNLIKELY (lexer_check_arrow (context_p)))
{
scanner_scan_simple_arrow (context_p, scanner_context_p, context_p->source_p);
return SCAN_KEEP_TOKEN;
}
if (JERRY_UNLIKELY (lexer_token_is_let (context_p)))
{
lexer_lit_location_t let_literal = context_p->token.lit_location;
const uint8_t *source_p = context_p->source_p;
lexer_next_token (context_p);
type = (lexer_token_type_t) context_p->token.type;
if (type == LEXER_LEFT_SQUARE
|| type == LEXER_LEFT_BRACE
|| (type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL))
{
scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT;
parser_stack_push_uint8 (context_p, SCAN_STACK_LET);
return SCAN_KEEP_TOKEN;
}
scanner_info_t *info_p = scanner_insert_info (context_p, source_p, sizeof (scanner_info_t));
info_p->type = SCANNER_TYPE_LET_EXPRESSION;
lexer_lit_location_t *lit_location_p = scanner_add_custom_literal (context_p,
scanner_context_p->active_literal_pool_p,
&let_literal);
lit_location_p->type |= SCANNER_LITERAL_IS_USED;
if (scanner_context_p->active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH)
{
lit_location_p->type |= SCANNER_LITERAL_NO_REG;
}
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
return SCAN_KEEP_TOKEN;
}
if (JERRY_UNLIKELY (lexer_token_is_async (context_p)))
{
scanner_context_p->async_source_p = context_p->source_p;
if (scanner_check_async_function (context_p, scanner_context_p))
{
scanner_context_p->mode = SCAN_MODE_STATEMENT;
}
return SCAN_KEEP_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015) */
scanner_add_reference (context_p, scanner_context_p);
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
return SCAN_NEXT_TOKEN;
}
return SCAN_KEEP_TOKEN;
} /* scanner_scan_statement */
/**
* Scan statement terminator.
*
* @return SCAN_NEXT_TOKEN to read the next token, or SCAN_KEEP_TOKEN to do nothing
*/
static scan_return_types_t
scanner_scan_statement_end (parser_context_t *context_p, /**< context */
scanner_context_t *scanner_context_p, /**< scanner context */
lexer_token_type_t type) /**< current token type */
{
bool terminator_found = false;
if (type == LEXER_SEMICOLON)
{
lexer_next_token (context_p);
terminator_found = true;
}
while (true)
{
type = (lexer_token_type_t) context_p->token.type;
switch (context_p->stack_top_uint8)
{
case SCAN_STACK_SCRIPT:
case SCAN_STACK_SCRIPT_FUNCTION:
{
if (type == LEXER_EOS)
{
return SCAN_NEXT_TOKEN;
}
break;
}
case SCAN_STACK_BLOCK_STATEMENT:
#if ENABLED (JERRY_ES2015)
case SCAN_STACK_CLASS_STATEMENT:
#endif /* ENABLED (JERRY_ES2015) */
case SCAN_STACK_FUNCTION_STATEMENT:
{
if (type != LEXER_RIGHT_BRACE)
{
break;
}
#if ENABLED (JERRY_ES2015)
if (context_p->stack_top_uint8 != SCAN_STACK_CLASS_STATEMENT)
{
scanner_pop_literal_pool (context_p, scanner_context_p);
}
#else /* !ENABLED (JERRY_ES2015) */
if (context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_STATEMENT)
{
scanner_pop_literal_pool (context_p, scanner_context_p);
}
#endif /* ENABLED (JERRY_ES2015) */
terminator_found = true;
parser_stack_pop_uint8 (context_p);
lexer_next_token (context_p);
continue;
}
case SCAN_STACK_FUNCTION_EXPRESSION:
#if ENABLED (JERRY_ES2015)
case SCAN_STACK_FUNCTION_ARROW:
#endif /* ENABLED (JERRY_ES2015) */
{
if (type != LEXER_RIGHT_BRACE)
{
break;
}
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
#if ENABLED (JERRY_ES2015)
if (context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_ARROW)
{
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
}
#endif /* ENABLED (JERRY_ES2015) */
scanner_pop_literal_pool (context_p, scanner_context_p);
parser_stack_pop_uint8 (context_p);
return SCAN_NEXT_TOKEN;
}
case SCAN_STACK_FUNCTION_PROPERTY:
{
if (type != LEXER_RIGHT_BRACE)
{
break;
}
scanner_pop_literal_pool (context_p, scanner_context_p);
parser_stack_pop_uint8 (context_p);
#if ENABLED (JERRY_ES2015)
if (context_p->stack_top_uint8 == SCAN_STACK_CLASS_STATEMENT
|| context_p->stack_top_uint8 == SCAN_STACK_CLASS_EXPRESSION)
{
scanner_context_p->mode = SCAN_MODE_CLASS_METHOD;
return SCAN_KEEP_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015) */
JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL);
lexer_next_token (context_p);
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
return SCAN_KEEP_TOKEN;
}
if (context_p->token.type != LEXER_COMMA)
{
scanner_raise_error (context_p);
}
scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME;
return SCAN_KEEP_TOKEN;
}
case SCAN_STACK_SWITCH_BLOCK:
{
if (type != LEXER_RIGHT_BRACE)
{
break;
}
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;
#if ENABLED (JERRY_ES2015)
scanner_pop_literal_pool (context_p, scanner_context_p);
#endif /* ENABLED (JERRY_ES2015) */
terminator_found = true;
lexer_next_token (context_p);
continue;
}
case SCAN_STACK_IF_STATEMENT:
{
parser_stack_pop_uint8 (context_p);
if (type == LEXER_KEYW_ELSE
&& (terminator_found || (context_p->token.flags & LEXER_WAS_NEWLINE)))
{
scanner_context_p->mode = SCAN_MODE_STATEMENT;
return SCAN_NEXT_TOKEN;
}
continue;
}
case SCAN_STACK_WITH_STATEMENT:
{
scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p;
JERRY_ASSERT (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH);
parser_stack_pop_uint8 (context_p);
if (context_p->stack_top_uint8 == 0)
{
literal_pool_p->status_flags &= (uint16_t) ~SCANNER_LITERAL_POOL_IN_WITH;
}
parser_stack_pop_uint8 (context_p);
continue;
}
case SCAN_STACK_DO_STATEMENT:
{
parser_stack_pop_uint8 (context_p);
if (type != LEXER_KEYW_WHILE
|| (!terminator_found && !(context_p->token.flags & LEXER_WAS_NEWLINE)))
{
scanner_raise_error (context_p);
}
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LEFT_PAREN)
{
scanner_raise_error (context_p);
}
parser_stack_push_uint8 (context_p, SCAN_STACK_DO_EXPRESSION);
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
return SCAN_NEXT_TOKEN;
}
case SCAN_STACK_DO_EXPRESSION:
{
parser_stack_pop_uint8 (context_p);
terminator_found = true;
continue;
}
#if ENABLED (JERRY_ES2015)
case SCAN_STACK_FOR_BLOCK_END:
{
parser_stack_pop_uint8 (context_p);
scanner_pop_literal_pool (context_p, scanner_context_p);
continue;
}
#endif /* ENABLED (JERRY_ES2015) */
default:
{
JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_TRY_STATEMENT
|| context_p->stack_top_uint8 == SCAN_STACK_CATCH_STATEMENT);
if (type != LEXER_RIGHT_BRACE)
{
break;
}
uint8_t stack_top = context_p->stack_top_uint8;
parser_stack_pop_uint8 (context_p);
lexer_next_token (context_p);
#if ENABLED (JERRY_ES2015)
scanner_pop_literal_pool (context_p, scanner_context_p);
#else /* !ENABLED (JERRY_ES2015) */
if (stack_top == SCAN_STACK_CATCH_STATEMENT)
{
scanner_pop_literal_pool (context_p, scanner_context_p);
}
#endif /* ENABLED (JERRY_ES2015) */
/* A finally statement is optional after a try or catch statement. */
if (context_p->token.type == LEXER_KEYW_FINALLY)
{
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LEFT_BRACE)
{
scanner_raise_error (context_p);
}
#if ENABLED (JERRY_ES2015)
scanner_literal_pool_t *literal_pool_p;
literal_pool_p = scanner_push_literal_pool (context_p,
scanner_context_p,
SCANNER_LITERAL_POOL_BLOCK);
literal_pool_p->source_p = context_p->source_p;
#endif /* ENABLED (JERRY_ES2015) */
parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT);
scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
return SCAN_NEXT_TOKEN;
}
if (stack_top == SCAN_STACK_CATCH_STATEMENT)
{
terminator_found = true;
continue;
}
/* A catch statement must be present after a try statement unless a finally is provided. */
if (context_p->token.type != LEXER_KEYW_CATCH)
{
scanner_raise_error (context_p);
}
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LEFT_PAREN)
{
scanner_raise_error (context_p);
}
scanner_literal_pool_t *literal_pool_p;
literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_BLOCK);
literal_pool_p->source_p = context_p->source_p;
lexer_next_token (context_p);
parser_stack_push_uint8 (context_p, SCAN_STACK_CATCH_STATEMENT);
#if ENABLED (JERRY_ES2015)
if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE)
{
scanner_push_destructuring_pattern (context_p, scanner_context_p, SCANNER_BINDING_CATCH, false);
if (context_p->token.type == LEXER_LEFT_SQUARE)
{
parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL);
scanner_context_p->mode = SCAN_MODE_BINDING;
return SCAN_NEXT_TOKEN;
}
parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL);
scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME;
return SCAN_KEEP_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015) */
if (context_p->token.type != LEXER_LITERAL
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
scanner_raise_error (context_p);
}
lexer_lit_location_t *lit_location_p = scanner_add_literal (context_p, scanner_context_p);
lit_location_p->type |= SCANNER_LITERAL_IS_LOCAL;
lexer_next_token (context_p);
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_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
return SCAN_NEXT_TOKEN;
}
}
if (!terminator_found && !(context_p->token.flags & LEXER_WAS_NEWLINE))
{
scanner_raise_error (context_p);
}
scanner_context_p->mode = SCAN_MODE_STATEMENT;
return SCAN_KEEP_TOKEN;
}
} /* scanner_scan_statement_end */
/**
* Scan the whole source code.
*/
void JERRY_ATTR_NOINLINE
scanner_scan_all (parser_context_t *context_p, /**< context */
const uint8_t *arg_list_p, /**< function argument list */
const uint8_t *arg_list_end_p, /**< end of argument list */
const uint8_t *source_p, /**< valid UTF-8 source code */
const uint8_t *source_end_p) /**< end of source code */
{
scanner_context_t scanner_context;
#if ENABLED (JERRY_PARSER_DUMP_BYTE_CODE)
if (context_p->is_show_opcodes)
{
JERRY_DEBUG_MSG ("\n--- Scanning start ---\n\n");
}
#endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */
scanner_context.context_status_flags = context_p->status_flags;
#if ENABLED (JERRY_DEBUGGER)
scanner_context.debugger_enabled = (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) ? 1 : 0;
#endif /* ENABLED (JERRY_DEBUGGER) */
#if ENABLED (JERRY_ES2015)
scanner_context.binding_type = SCANNER_BINDING_NONE;
scanner_context.active_binding_list_p = NULL;
#endif /* ENABLED (JERRY_ES2015) */
scanner_context.active_literal_pool_p = NULL;
scanner_context.active_switch_statement.last_case_p = NULL;
scanner_context.end_arguments_p = NULL;
#if ENABLED (JERRY_ES2015)
scanner_context.async_source_p = NULL;
#endif /* ENABLED (JERRY_ES2015) */
/* This assignment must be here because of Apple compilers. */
context_p->u.scanner_context_p = &scanner_context;
parser_stack_init (context_p);
PARSER_TRY (context_p->try_buffer)
{
context_p->line = 1;
context_p->column = 1;
if (arg_list_p == NULL)
{
context_p->source_p = source_p;
context_p->source_end_p = source_end_p;
uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS | SCANNER_LITERAL_POOL_NO_REG;
if (context_p->status_flags & PARSER_IS_STRICT)
{
status_flags |= SCANNER_LITERAL_POOL_IS_STRICT;
}
scanner_literal_pool_t *literal_pool_p = scanner_push_literal_pool (context_p, &scanner_context, status_flags);
literal_pool_p->source_p = source_p;
parser_stack_push_uint8 (context_p, SCAN_STACK_SCRIPT);
lexer_next_token (context_p);
scanner_check_directives (context_p, &scanner_context);
}
else
{
context_p->source_p = arg_list_p;
context_p->source_end_p = arg_list_end_p;
uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION;
if (context_p->status_flags & PARSER_IS_STRICT)
{
status_flags |= SCANNER_LITERAL_POOL_IS_STRICT;
}
scanner_push_literal_pool (context_p, &scanner_context, status_flags);
scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS;
parser_stack_push_uint8 (context_p, SCAN_STACK_SCRIPT_FUNCTION);
/* Faking the first token. */
context_p->token.type = LEXER_LEFT_PAREN;
}
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;
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) != SCAN_NEXT_TOKEN)
{
continue;
}
break;
}
#if ENABLED (JERRY_ES2015)
case SCAN_MODE_CLASS_DECLARATION:
{
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;
/* FALLTHRU */
}
case SCAN_MODE_CLASS_METHOD:
{
JERRY_ASSERT (stack_top == SCAN_STACK_CLASS_STATEMENT || stack_top == SCAN_STACK_CLASS_EXPRESSION);
lexer_skip_empty_statements (context_p);
lexer_scan_identifier (context_p);
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
if (stack_top == SCAN_STACK_CLASS_STATEMENT)
{
/* The token is kept to disallow consuming a semicolon after it. */
scanner_context.mode = SCAN_MODE_STATEMENT_END;
continue;
}
scanner_context.mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
parser_stack_pop_uint8 (context_p);
break;
}
if (lexer_token_is_identifier (context_p, "static", 6))
{
lexer_scan_identifier (context_p);
}
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS;
uint16_t literal_pool_flags = SCANNER_LITERAL_POOL_FUNCTION;
if (lexer_token_is_identifier (context_p, "get", 3)
|| lexer_token_is_identifier (context_p, "set", 3))
{
lexer_scan_identifier (context_p);
if (context_p->token.type == LEXER_LEFT_PAREN)
{
scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION);
continue;
}
}
else if (lexer_token_is_identifier (context_p, "async", 5))
{
lexer_scan_identifier (context_p);
if (context_p->token.type == LEXER_LEFT_PAREN)
{
scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION);
continue;
}
literal_pool_flags |= SCANNER_LITERAL_POOL_ASYNC;
if (context_p->token.type == LEXER_MULTIPLY)
{
lexer_scan_identifier (context_p);
literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR;
}
}
else if (context_p->token.type == LEXER_MULTIPLY)
{
lexer_scan_identifier (context_p);
literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR;
}
if (context_p->token.type == LEXER_LEFT_SQUARE)
{
parser_stack_push_uint8 (context_p, GET_COMPUTED_PROPERTY_MODE (literal_pool_flags));
scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
if (context_p->token.type != LEXER_LITERAL)
{
scanner_raise_error (context_p);
}
if (literal_pool_flags & SCANNER_LITERAL_POOL_GENERATOR)
{
context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION;
}
scanner_push_literal_pool (context_p, &scanner_context, literal_pool_flags);
lexer_next_token (context_p);
continue;
}
#endif /* ENABLED (JERRY_ES2015) */
case SCAN_MODE_POST_PRIMARY_EXPRESSION:
{
if (scanner_scan_post_primary_expression (context_p, &scanner_context, type, stack_top))
{
break;
}
type = (lexer_token_type_t) context_p->token.type;
/* FALLTHRU */
}
case SCAN_MODE_PRIMARY_EXPRESSION_END:
{
if (scanner_scan_primary_expression_end (context_p, &scanner_context, type, stack_top) != SCAN_NEXT_TOKEN)
{
continue;
}
break;
}
case SCAN_MODE_STATEMENT_OR_TERMINATOR:
{
if (type == LEXER_RIGHT_BRACE || type == LEXER_EOS)
{
scanner_context.mode = SCAN_MODE_STATEMENT_END;
continue;
}
/* FALLTHRU */
}
case SCAN_MODE_STATEMENT:
{
if (scanner_scan_statement (context_p, &scanner_context, type, stack_top) != SCAN_NEXT_TOKEN)
{
continue;
}
break;
}
case SCAN_MODE_STATEMENT_END:
{
if (scanner_scan_statement_end (context_p, &scanner_context, type) != SCAN_NEXT_TOKEN)
{
continue;
}
if (context_p->token.type == LEXER_EOS)
{
goto scan_completed;
}
break;
}
case SCAN_MODE_VAR_STATEMENT:
{
#if ENABLED (JERRY_ES2015)
if (type == LEXER_LEFT_SQUARE || type == LEXER_LEFT_BRACE)
{
uint8_t binding_type = SCANNER_BINDING_VAR;
if (stack_top == SCAN_STACK_LET || stack_top == SCAN_STACK_FOR_LET_START)
{
binding_type = SCANNER_BINDING_LET;
}
else if (stack_top == SCAN_STACK_CONST || stack_top == SCAN_STACK_FOR_CONST_START)
{
binding_type = SCANNER_BINDING_CONST;
}
scanner_push_destructuring_pattern (context_p, &scanner_context, binding_type, false);
if (type == LEXER_LEFT_SQUARE)
{
parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL);
scanner_context.mode = SCAN_MODE_BINDING;
break;
}
parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL);
scanner_context.mode = SCAN_MODE_PROPERTY_NAME;
continue;
}
#endif /* ENABLED (JERRY_ES2015) */
if (type != LEXER_LITERAL
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
scanner_raise_error (context_p);
}
lexer_lit_location_t *literal_p = scanner_add_literal (context_p, &scanner_context);
#if ENABLED (JERRY_ES2015)
if (stack_top != SCAN_STACK_VAR && stack_top != SCAN_STACK_FOR_VAR_START)
{
scanner_detect_invalid_let (context_p, literal_p);
if (stack_top == SCAN_STACK_LET || stack_top == SCAN_STACK_FOR_LET_START)
{
literal_p->type |= SCANNER_LITERAL_IS_LET;
}
else
{
JERRY_ASSERT (stack_top == SCAN_STACK_CONST || stack_top == SCAN_STACK_FOR_CONST_START);
literal_p->type |= SCANNER_LITERAL_IS_CONST;
}
lexer_next_token (context_p);
if (literal_p->type & SCANNER_LITERAL_IS_USED)
{
literal_p->type |= SCANNER_LITERAL_NO_REG;
}
else if (context_p->token.type == LEXER_ASSIGN)
{
scanner_binding_literal_t binding_literal;
binding_literal.literal_p = literal_p;
parser_stack_push (context_p, &binding_literal, sizeof (scanner_binding_literal_t));
parser_stack_push_uint8 (context_p, SCAN_STACK_BINDING_INIT);
}
}
else
{
if (!(literal_p->type & SCANNER_LITERAL_IS_VAR))
{
scanner_detect_invalid_var (context_p, &scanner_context, literal_p);
literal_p->type |= SCANNER_LITERAL_IS_VAR;
if (scanner_context.active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH)
{
literal_p->type |= SCANNER_LITERAL_NO_REG;
}
}
lexer_next_token (context_p);
}
#else /* !ENABLED (JERRY_ES2015) */
literal_p->type |= SCANNER_LITERAL_IS_VAR;
if (scanner_context.active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH)
{
literal_p->type |= SCANNER_LITERAL_NO_REG;
}
lexer_next_token (context_p);
#endif /* ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
if (scanner_context.active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_EXPORT)
{
literal_p->type |= SCANNER_LITERAL_NO_REG;
}
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
switch (context_p->token.type)
{
case LEXER_ASSIGN:
{
scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION;
/* FALLTHRU */
}
case LEXER_COMMA:
{
lexer_next_token (context_p);
continue;
}
}
if (SCANNER_IS_FOR_START (stack_top))
{
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
JERRY_ASSERT (!(scanner_context.active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_EXPORT));
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
if (context_p->token.type != LEXER_SEMICOLON
&& context_p->token.type != LEXER_KEYW_IN
&& !SCANNER_IDENTIFIER_IS_OF ())
{
scanner_raise_error (context_p);
}
scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
continue;
}
#if ENABLED (JERRY_ES2015)
JERRY_ASSERT (stack_top == SCAN_STACK_VAR || stack_top == SCAN_STACK_LET || stack_top == SCAN_STACK_CONST);
#else /* !ENABLED (JERRY_ES2015) */
JERRY_ASSERT (stack_top == SCAN_STACK_VAR);
#endif /* ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
scanner_context.active_literal_pool_p->status_flags &= (uint16_t) ~SCANNER_LITERAL_POOL_IN_EXPORT;
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
scanner_context.mode = SCAN_MODE_STATEMENT_END;
parser_stack_pop_uint8 (context_p);
continue;
}
case SCAN_MODE_FUNCTION_ARGUMENTS:
{
JERRY_ASSERT (stack_top == SCAN_STACK_SCRIPT_FUNCTION
|| stack_top == SCAN_STACK_FUNCTION_STATEMENT
|| stack_top == SCAN_STACK_FUNCTION_EXPRESSION
|| stack_top == SCAN_STACK_FUNCTION_PROPERTY);
scanner_literal_pool_t *literal_pool_p = scanner_context.active_literal_pool_p;
JERRY_ASSERT (literal_pool_p != NULL && (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION));
literal_pool_p->source_p = context_p->source_p;
#if ENABLED (JERRY_ES2015)
if (JERRY_UNLIKELY (scanner_context.async_source_p != NULL))
{
literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ASYNC;
if (stack_top == SCAN_STACK_FUNCTION_STATEMENT)
{
literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_FUNCTION_STATEMENT;
}
literal_pool_p->source_p = scanner_context.async_source_p;
scanner_context.async_source_p = NULL;
}
#endif /* ENABLED (JERRY_ES2015) */
if (type != LEXER_LEFT_PAREN)
{
scanner_raise_error (context_p);
}
lexer_next_token (context_p);
#if ENABLED (JERRY_ES2015)
/* FALLTHRU */
}
case SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS:
{
bool is_destructuring_binding = false;
#endif /* ENABLED (JERRY_ES2015) */
if (context_p->token.type != LEXER_RIGHT_PAREN && context_p->token.type != LEXER_EOS)
{
while (true)
{
#if ENABLED (JERRY_ES2015)
if (context_p->token.type == LEXER_THREE_DOTS)
{
scanner_context.active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED;
lexer_next_token (context_p);
}
if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE)
{
is_destructuring_binding = true;
break;
}
#endif /* ENABLED (JERRY_ES2015) */
if (context_p->token.type != LEXER_LITERAL
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
scanner_raise_error (context_p);
}
scanner_append_argument (context_p, &scanner_context);
lexer_next_token (context_p);
if (context_p->token.type != LEXER_COMMA)
{
break;
}
lexer_next_token (context_p);
}
}
#if ENABLED (JERRY_ES2015)
if (is_destructuring_binding)
{
scanner_context.active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED;
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PARAMETERS);
scanner_append_hole (context_p, &scanner_context);
scanner_push_destructuring_pattern (context_p, &scanner_context, SCANNER_BINDING_ARG, false);
if (context_p->token.type == LEXER_LEFT_SQUARE)
{
parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL);
scanner_context.mode = SCAN_MODE_BINDING;
break;
}
parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL);
scanner_context.mode = SCAN_MODE_PROPERTY_NAME;
continue;
}
if (context_p->token.type == LEXER_ASSIGN)
{
scanner_context.active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ARGUMENTS_UNMAPPED;
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PARAMETERS);
scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
#endif /* ENABLED (JERRY_ES2015) */
if (context_p->token.type == LEXER_EOS && stack_top == SCAN_STACK_SCRIPT_FUNCTION)
{
/* End of argument parsing. */
scanner_info_t *scanner_info_p = (scanner_info_t *) scanner_malloc (context_p, sizeof (scanner_info_t));
scanner_info_p->next_p = context_p->next_scanner_info_p;
scanner_info_p->source_p = NULL;
scanner_info_p->type = SCANNER_TYPE_END_ARGUMENTS;
scanner_context.end_arguments_p = scanner_info_p;
context_p->next_scanner_info_p = scanner_info_p;
context_p->source_p = source_p;
context_p->source_end_p = source_end_p;
context_p->line = 1;
context_p->column = 1;
scanner_filter_arguments (context_p, &scanner_context);
lexer_next_token (context_p);
scanner_check_directives (context_p, &scanner_context);
continue;
}
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_filter_arguments (context_p, &scanner_context);
lexer_next_token (context_p);
scanner_check_directives (context_p, &scanner_context);
continue;
}
case SCAN_MODE_PROPERTY_NAME:
{
JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL);
if (lexer_scan_identifier (context_p))
{
lexer_check_property_modifier (context_p);
}
#if ENABLED (JERRY_ES2015)
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) */
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
continue;
}
if (context_p->token.type == LEXER_PROPERTY_GETTER
#if ENABLED (JERRY_ES2015)
|| context_p->token.type == LEXER_KEYW_ASYNC
|| context_p->token.type == LEXER_MULTIPLY
#endif /* ENABLED (JERRY_ES2015) */
|| context_p->token.type == LEXER_PROPERTY_SETTER)
{
uint16_t literal_pool_flags = SCANNER_LITERAL_POOL_FUNCTION;
#if ENABLED (JERRY_ES2015)
if (context_p->token.type == LEXER_MULTIPLY)
{
literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR;
}
else if (context_p->token.type == LEXER_KEYW_ASYNC)
{
literal_pool_flags |= SCANNER_LITERAL_POOL_ASYNC;
if (lexer_consume_generator (context_p))
{
literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR;
}
}
#endif /* ENABLED (JERRY_ES2015) */
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
lexer_scan_identifier (context_p);
#if ENABLED (JERRY_ES2015)
if (context_p->token.type == LEXER_LEFT_SQUARE)
{
parser_stack_push_uint8 (context_p, GET_COMPUTED_PROPERTY_MODE (literal_pool_flags));
scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
if (literal_pool_flags & SCANNER_LITERAL_POOL_GENERATOR)
{
context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION;
}
#endif /* ENABLED (JERRY_ES2015) */
if (context_p->token.type != LEXER_LITERAL)
{
scanner_raise_error (context_p);
}
scanner_push_literal_pool (context_p, &scanner_context, literal_pool_flags);
scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS;
break;
}
if (context_p->token.type != LEXER_LITERAL)
{
scanner_raise_error (context_p);
}
#if ENABLED (JERRY_ES2015)
parser_line_counter_t start_line = context_p->token.line;
parser_line_counter_t start_column = context_p->token.column;
bool is_ident = (context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
#endif /* ENABLED (JERRY_ES2015) */
lexer_next_token (context_p);
#if ENABLED (JERRY_ES2015)
if (context_p->token.type == LEXER_LEFT_PAREN)
{
scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION);
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS;
continue;
}
if (is_ident
&& (context_p->token.type == LEXER_COMMA
|| context_p->token.type == LEXER_RIGHT_BRACE
|| context_p->token.type == LEXER_ASSIGN))
{
context_p->source_p = context_p->token.lit_location.char_p;
context_p->line = start_line;
context_p->column = start_column;
lexer_next_token (context_p);
JERRY_ASSERT (context_p->token.type != LEXER_LITERAL
|| context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
if (context_p->token.type != LEXER_LITERAL)
{
scanner_raise_error (context_p);
}
if (scanner_context.binding_type != SCANNER_BINDING_NONE)
{
scanner_context.mode = SCAN_MODE_BINDING;
continue;
}
scanner_add_reference (context_p, &scanner_context);
lexer_next_token (context_p);
if (context_p->token.type == LEXER_ASSIGN)
{
scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
continue;
}
#endif /* ENABLED (JERRY_ES2015) */
if (context_p->token.type != LEXER_COLON)
{
scanner_raise_error (context_p);
}
scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION;
#if ENABLED (JERRY_ES2015)
if (scanner_context.binding_type != SCANNER_BINDING_NONE)
{
scanner_context.mode = SCAN_MODE_BINDING;
}
#endif /* ENABLED (JERRY_ES2015) */
break;
}
#if ENABLED (JERRY_ES2015)
case SCAN_MODE_BINDING:
{
JERRY_ASSERT (scanner_context.binding_type == SCANNER_BINDING_VAR
|| scanner_context.binding_type == SCANNER_BINDING_LET
|| scanner_context.binding_type == SCANNER_BINDING_CONST
|| scanner_context.binding_type == SCANNER_BINDING_ARG
|| scanner_context.binding_type == SCANNER_BINDING_ARROW_ARG
|| scanner_context.binding_type == SCANNER_BINDING_CATCH);
if (type == LEXER_THREE_DOTS)
{
lexer_next_token (context_p);
type = (lexer_token_type_t) context_p->token.type;
}
if (type == LEXER_LEFT_SQUARE || type == LEXER_LEFT_BRACE)
{
scanner_push_destructuring_pattern (context_p, &scanner_context, scanner_context.binding_type, true);
if (type == LEXER_LEFT_SQUARE)
{
parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL);
break;
}
parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL);
scanner_context.mode = SCAN_MODE_PROPERTY_NAME;
continue;
}
if (type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION;
continue;
}
lexer_lit_location_t *literal_p = scanner_add_literal (context_p, &scanner_context);
scanner_context.mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
if (scanner_context.binding_type == SCANNER_BINDING_VAR)
{
if (!(literal_p->type & SCANNER_LITERAL_IS_VAR))
{
scanner_detect_invalid_var (context_p, &scanner_context, literal_p);
literal_p->type |= SCANNER_LITERAL_IS_VAR;
if (scanner_context.active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH)
{
literal_p->type |= SCANNER_LITERAL_NO_REG;
}
}
break;
}
if (scanner_context.binding_type == SCANNER_BINDING_ARROW_ARG)
{
literal_p->type |= SCANNER_LITERAL_IS_ARG | SCANNER_LITERAL_IS_ARROW_DESTRUCTURED_ARG;
if (literal_p->type & SCANNER_LITERAL_IS_USED)
{
literal_p->type |= SCANNER_LITERAL_ARROW_DESTRUCTURED_ARG_NO_REG;
break;
}
}
else
{
scanner_detect_invalid_let (context_p, literal_p);
if (scanner_context.binding_type == SCANNER_BINDING_LET)
{
literal_p->type |= SCANNER_LITERAL_IS_LET;
}
else if (scanner_context.binding_type == SCANNER_BINDING_CATCH)
{
literal_p->type |= SCANNER_LITERAL_IS_LOCAL;
}
else
{
literal_p->type |= SCANNER_LITERAL_IS_CONST;
if (scanner_context.binding_type == SCANNER_BINDING_ARG)
{
literal_p->type |= SCANNER_LITERAL_IS_ARG;
}
}
if (literal_p->type & SCANNER_LITERAL_IS_USED)
{
literal_p->type |= SCANNER_LITERAL_NO_REG;
break;
}
}
scanner_binding_item_t *binding_item_p;
binding_item_p = (scanner_binding_item_t *) scanner_malloc (context_p, sizeof (scanner_binding_item_t));
binding_item_p->next_p = scanner_context.active_binding_list_p->items_p;
binding_item_p->literal_p = literal_p;
scanner_context.active_binding_list_p->items_p = binding_item_p;
lexer_next_token (context_p);
if (context_p->token.type != LEXER_ASSIGN)
{
continue;
}
scanner_binding_literal_t binding_literal;
binding_literal.literal_p = literal_p;
parser_stack_push (context_p, &binding_literal, sizeof (scanner_binding_literal_t));
parser_stack_push_uint8 (context_p, SCAN_STACK_BINDING_INIT);
scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
#endif /* ENABLED (JERRY_ES2015) */
}
lexer_next_token (context_p);
}
scan_completed:
if (context_p->stack_top_uint8 != SCAN_STACK_SCRIPT
&& context_p->stack_top_uint8 != SCAN_STACK_SCRIPT_FUNCTION)
{
scanner_raise_error (context_p);
}
scanner_pop_literal_pool (context_p, &scanner_context);
#if ENABLED (JERRY_ES2015)
JERRY_ASSERT (scanner_context.active_binding_list_p == NULL);
#endif /* ENABLED (JERRY_ES2015) */
JERRY_ASSERT (scanner_context.active_literal_pool_p == NULL);
#ifndef JERRY_NDEBUG
scanner_context.context_status_flags |= PARSER_SCANNING_SUCCESSFUL;
#endif /* !JERRY_NDEBUG */
}
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;
}
#if ENABLED (JERRY_ES2015)
while (scanner_context.active_binding_list_p != NULL)
{
scanner_pop_binding_list (&scanner_context);
}
#endif /* ENABLED (JERRY_ES2015) */
/* The following loop may allocate memory, so it is enclosed in a try/catch. */
PARSER_TRY (context_p->try_buffer)
{
while (scanner_context.active_literal_pool_p != NULL)
{
scanner_pop_literal_pool (context_p, &scanner_context);
}
}
PARSER_CATCH
{
JERRY_ASSERT (context_p->error == PARSER_ERR_NO_ERROR);
while (scanner_context.active_literal_pool_p != NULL)
{
scanner_literal_pool_t *literal_pool_p = scanner_context.active_literal_pool_p;
scanner_context.active_literal_pool_p = literal_pool_p->prev_p;
parser_list_free (&literal_pool_p->literal_pool);
scanner_free (literal_pool_p, sizeof (scanner_literal_pool_t));
}
}
PARSER_TRY_END
#if ENABLED (JERRY_ES2015)
context_p->status_flags &= (uint32_t) ~PARSER_IS_GENERATOR_FUNCTION;
#endif /* ENABLED (JERRY_ES2015) */
}
PARSER_TRY_END
context_p->status_flags = scanner_context.context_status_flags;
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;
const uint8_t *source_start_p = (arg_list_p == NULL) ? source_p : arg_list_p;
while (info_p->type != SCANNER_TYPE_END)
{
const char *name_p = NULL;
bool print_location = false;
switch (info_p->type)
{
case SCANNER_TYPE_END_ARGUMENTS:
{
JERRY_DEBUG_MSG (" END_ARGUMENTS\n");
source_start_p = source_p;
break;
}
case SCANNER_TYPE_FUNCTION:
case SCANNER_TYPE_BLOCK:
{
const uint8_t *prev_source_p = info_p->source_p - 1;
const uint8_t *data_p;
if (info_p->type == SCANNER_TYPE_FUNCTION)
{
data_p = (const uint8_t *) (info_p + 1);
JERRY_DEBUG_MSG (" FUNCTION: flags: 0x%x declarations: %d",
(int) info_p->u8_arg,
(int) info_p->u16_arg);
}
else
{
data_p = (const uint8_t *) (info_p + 1);
JERRY_DEBUG_MSG (" BLOCK:");
}
JERRY_DEBUG_MSG (" source:%d\n", (int) (info_p->source_p - source_start_p));
while (data_p[0] != SCANNER_STREAM_TYPE_END)
{
switch (data_p[0] & SCANNER_STREAM_TYPE_MASK)
{
case SCANNER_STREAM_TYPE_VAR:
{
JERRY_DEBUG_MSG (" VAR ");
break;
}
#if ENABLED (JERRY_ES2015)
case SCANNER_STREAM_TYPE_LET:
{
JERRY_DEBUG_MSG (" LET ");
break;
}
case SCANNER_STREAM_TYPE_CONST:
{
JERRY_DEBUG_MSG (" CONST ");
break;
}
case SCANNER_STREAM_TYPE_LOCAL:
{
JERRY_DEBUG_MSG (" LOCAL ");
break;
}
case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG:
{
JERRY_DEBUG_MSG (" DESTRUCTURED_ARG ");
break;
}
#endif /* ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
case SCANNER_STREAM_TYPE_IMPORT:
{
JERRY_DEBUG_MSG (" IMPORT ");
break;
}
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
case SCANNER_STREAM_TYPE_ARG:
{
JERRY_DEBUG_MSG (" ARG ");
break;
}
case SCANNER_STREAM_TYPE_ARG_FUNC:
{
JERRY_DEBUG_MSG (" ARG_FUNC ");
break;
}
#if ENABLED (JERRY_ES2015)
case SCANNER_STREAM_TYPE_DESTRUCTURED_ARG_FUNC:
{
JERRY_DEBUG_MSG (" DESTRUCTURED_ARG_FUNC ");
break;
}
#endif /* ENABLED (JERRY_ES2015) */
case SCANNER_STREAM_TYPE_FUNC:
{
JERRY_DEBUG_MSG (" FUNC ");
break;
}
default:
{
JERRY_ASSERT ((data_p[0] & SCANNER_STREAM_TYPE_MASK) == SCANNER_STREAM_TYPE_HOLE);
JERRY_DEBUG_MSG (" HOLE\n");
data_p++;
continue;
}
}
size_t length;
if (!(data_p[0] & SCANNER_STREAM_UINT16_DIFF))
{
if (data_p[2] != 0)
{
prev_source_p += data_p[2];
length = 2 + 1;
}
else
{
memcpy (&prev_source_p, data_p + 2 + 1, sizeof (const uint8_t *));
length = 2 + 1 + sizeof (const uint8_t *);
}
}
else
{
int32_t diff = ((int32_t) data_p[2]) | ((int32_t) data_p[3]) << 8;
if (diff <= UINT8_MAX)
{
diff = -diff;
}
prev_source_p += diff;
length = 2 + 2;
}
if (data_p[0] & SCANNER_STREAM_NO_REG)
{
JERRY_DEBUG_MSG ("* ");
}
JERRY_DEBUG_MSG ("'%.*s'\n", data_p[1], (char *) prev_source_p);
prev_source_p += data_p[1];
data_p += length;
}
break;
}
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)
case SCANNER_TYPE_FOR_OF:
{
name_p = "FOR-OF";
print_location = true;
break;
}
#endif /* ENABLED (JERRY_ES2015) */
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)
case SCANNER_TYPE_INITIALIZER:
{
name_p = "INITIALIZER";
print_location = true;
break;
}
case SCANNER_TYPE_LET_EXPRESSION:
{
JERRY_DEBUG_MSG (" LET_EXPRESSION: source:%d\n",
(int) (info_p->source_p - source_start_p));
break;
}
case SCANNER_TYPE_ERR_REDECLARED:
{
JERRY_DEBUG_MSG (" ERR_REDECLARED: source:%d\n",
(int) (info_p->source_p - source_start_p));
break;
}
#endif /* ENABLED (JERRY_ES2015) */
}
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) */