Zoltan Herczeg 25b81c106c Implement statement parsing in the scanner. (#3137)
To implement let/const, the code affected by for statements needs to be identified,
and this patch implements the basic infrastructure for that. The short term benefit
is that scanner info blocks are not generated for do-while blocks.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
2019-09-20 12:15:16 +02:00

2082 lines
63 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 "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 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_STATEMENT_OR_TERMINATOR, /**< scanning statement or statement end */
SCAN_MODE_STATEMENT_END, /**< scanning statement end */
SCAN_MODE_VAR_STATEMENT, /**< scanning var statement */
SCAN_MODE_FUNCTION_ARGUMENTS, /**< scanning function arguments */
#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER)
SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS, /**< continue scanning function arguments */
#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */
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_SCRIPT, /**< script */
SCAN_STACK_EVAL_FUNCTION, /**< evaluated function */
SCAN_STACK_BLOCK_STATEMENT, /**< block statement group */
SCAN_STACK_FUNCTION_STATEMENT, /**< function statement */
SCAN_STACK_FUNCTION_EXPRESSION, /**< function expression */
SCAN_STACK_FUNCTION_PROPERTY, /**< function expression in an object literal or class */
SCAN_STACK_SWITCH_BLOCK, /**< block part of "switch" statement */
SCAN_STACK_IF_STATEMENT, /**< statement part of "if" statements */
SCAN_STACK_DO_STATEMENT, /**< statement part of "do" statements */
SCAN_STACK_DO_EXPRESSION, /**< expression part of "do" statements */
SCAN_STACK_WHILE_EXPRESSION, /**< expression part of "while" iterator */
SCAN_STACK_PAREN_EXPRESSION, /**< expression in brackets */
SCAN_STACK_STATEMENT_WITH_EXPR, /**< statement which starts with expression enclosed in brackets */
/* The SCANNER_IS_FOR_START macro needs to be updated when the following constants are reordered. */
SCAN_STACK_VAR, /**< var statement */
SCAN_STACK_FOR_VAR_START, /**< start of "for" iterator with var statement */
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_COLON_EXPRESSION, /**< colon expression group */
SCAN_STACK_CASE_STATEMENT, /**< colon statement group */
SCAN_STACK_TRY_STATEMENT, /**< try statement */
SCAN_STACK_CATCH_STATEMENT, /**< catch statement */
SCAN_STACK_SQUARE_BRACKETED_EXPRESSION, /**< square bracketed expression group */
SCAN_STACK_OBJECT_LITERAL, /**< object literal 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_STATEMENT, /**< class statement */
SCAN_STACK_CLASS_EXPRESSION, /**< class expression */
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;
/**
* Checks whether the stack top is a for statement start.
*/
#define SCANNER_IS_FOR_START(stack_top) \
((stack_top) >= SCAN_STACK_FOR_VAR_START && (stack_top) <= SCAN_STACK_FOR_START)
/**
* Scan mode types 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_FOR_OF)
#define SCANNER_IDENTIFIER_IS_OF() (lexer_compare_literal_to_identifier (context_p, "of", 2))
#else
#define SCANNER_IDENTIFIER_IS_OF() (false)
#endif /* ENABLED (JERRY_ES2015_FOR_OF) */
#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 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;
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:
{
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);
}
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:
{
#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 SCAN_KEEP_TOKEN;
}
#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_CLASS_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:
{
if (stack_top == SCAN_STACK_PAREN_EXPRESSION)
{
scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
parser_stack_pop_uint8 (context_p);
break;
}
#if ENABLED (JERRY_ES2015_ARROW_FUNCTION)
if (stack_top == SCAN_STACK_ARROW_EXPRESSION)
{
scanner_process_arrow (context_p, scanner_context_p);
return SCAN_KEEP_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015_ARROW_FUNCTION) */
/* 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 */
{
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 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 */
{
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 SCAN_NEXT_TOKEN;
}
case LEXER_COMMA:
{
switch (stack_top)
{
case SCAN_STACK_OBJECT_LITERAL:
{
scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME;
return SCAN_KEEP_TOKEN;
}
case SCAN_STACK_VAR:
case SCAN_STACK_FOR_VAR_START:
{
scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT;
return SCAN_NEXT_TOKEN;
}
#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER)
case SCAN_STACK_FUNCTION_PARAMETERS:
{
scanner_context_p->mode = SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS;
parser_stack_pop_uint8 (context_p);
return SCAN_NEXT_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */
default:
{
break;
}
}
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
return SCAN_NEXT_TOKEN;
}
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 SCAN_NEXT_TOKEN;
}
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_OR_TERMINATOR;
return SCAN_NEXT_TOKEN;
}
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 SCAN_NEXT_TOKEN;
}
switch (stack_top)
{
case SCAN_STACK_VAR:
{
parser_stack_pop_uint8 (context_p);
return SCAN_KEEP_TOKEN;
}
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 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;
}
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_FOR_VAR_START:
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_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_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));
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;
}
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_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 SCAN_NEXT_TOKEN;
}
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;
}
#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_FUNCTION_PROPERTY)
{
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)
{
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;
return SCAN_NEXT_TOKEN;
}
#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 SCAN_NEXT_TOKEN;
}
#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 SCAN_KEEP_TOKEN;
}
#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 SCAN_KEEP_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015_CLASS) */
#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER)
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_EVAL_FUNCTION))
{
break;
}
scanner_context_p->mode = SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS;
return SCAN_KEEP_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */
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 true for continue, false for break
*/
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:
{
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);
}
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_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;
lexer_next_token (context_p);
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
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;
break;
}
}
parser_stack_push (context_p, &for_statement, sizeof (scanner_for_statement_t));
parser_stack_push_uint8 (context_p, stack_mode);
return (stack_mode == SCAN_STACK_FOR_START) ? SCAN_KEEP_TOKEN : SCAN_NEXT_TOKEN;
}
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;
}
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_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);
if (context_p->token.type != LEXER_LITERAL
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
scanner_raise_error (context_p);
}
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_CLASS)
case LEXER_KEYW_CLASS:
{
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_CLASS) */
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
case LEXER_KEYW_IMPORT:
{
if (stack_top != SCAN_STACK_SCRIPT)
{
scanner_raise_error (context_p);
}
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_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 SCAN_NEXT_TOKEN;
}
case LEXER_KEYW_EXPORT:
{
if (stack_top != SCAN_STACK_SCRIPT)
{
scanner_raise_error (context_p);
}
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_next_token (context_p);
}
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_CLASS)
if (context_p->token.type == LEXER_KEYW_CLASS)
{
scanner_context_p->mode = SCAN_MODE_STATEMENT;
return SCAN_KEEP_TOKEN;
}
#endif /* ENABLED (JERRY_ES2015_CLASS) */
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
return SCAN_KEEP_TOKEN;
}
scanner_context_p->mode = SCAN_MODE_STATEMENT_END;
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 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_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 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;
}
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)
{
lexer_next_token (context_p);
if (context_p->token.type == LEXER_COLON)
{
scanner_context_p->mode = SCAN_MODE_STATEMENT;
return SCAN_NEXT_TOKEN;
}
#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 SCAN_KEEP_TOKEN;
} /* scanner_scan_statement */
/**
* Scan statement terminator.
*
* @return true for continue, false for break
*/
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_EVAL_FUNCTION:
{
if (type == LEXER_EOS)
{
return SCAN_NEXT_TOKEN;
}
break;
}
case SCAN_STACK_BLOCK_STATEMENT:
#if ENABLED (JERRY_ES2015_CLASS)
case SCAN_STACK_CLASS_STATEMENT:
#endif /* ENABLED (JERRY_ES2015_CLASS) */
case SCAN_STACK_FUNCTION_STATEMENT:
{
if (type != LEXER_RIGHT_BRACE)
{
break;
}
terminator_found = true;
parser_stack_pop_uint8 (context_p);
lexer_next_token (context_p);
continue;
}
case SCAN_STACK_FUNCTION_EXPRESSION:
{
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;
}
case SCAN_STACK_FUNCTION_PROPERTY:
{
if (type != LEXER_RIGHT_BRACE)
{
break;
}
parser_stack_pop_uint8 (context_p);
#if ENABLED (JERRY_ES2015_CLASS)
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_CLASS) */
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;
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_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;
}
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);
/* 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);
}
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);
}
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_PAREN)
{
scanner_raise_error (context_p);
}
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LEFT_BRACE)
{
scanner_raise_error (context_p);
}
parser_stack_push_uint8 (context_p, SCAN_STACK_CATCH_STATEMENT);
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
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.active_switch_statement.last_case_p = NULL;
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;
scanner_context.mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
parser_stack_push_uint8 (context_p, SCAN_STACK_SCRIPT);
lexer_next_token (context_p);
}
else
{
context_p->source_p = arg_list_p;
context_p->source_end_p = arg_list_end_p;
scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS;
parser_stack_push_uint8 (context_p, SCAN_STACK_EVAL_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_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;
/* 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, LEXER_SCAN_CLASS_PROPERTY);
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_compare_literal_to_identifier (context_p, "static", 6))
{
lexer_scan_identifier (context_p, LEXER_SCAN_CLASS_PROPERTY);
}
parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY);
scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS;
if (lexer_compare_literal_to_identifier (context_p, "get", 3)
|| lexer_compare_literal_to_identifier (context_p, "set", 3))
{
lexer_scan_identifier (context_p, LEXER_SCAN_CLASS_PROPERTY | LEXER_SCAN_CLASS_LEFT_PAREN);
if (context_p->token.type == LEXER_LEFT_PAREN)
{
continue;
}
}
#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) */
lexer_next_token (context_p);
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_FUNCTION_EXPRESSION);
scanner_context.mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
}
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) != 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 (type != LEXER_LITERAL
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
scanner_raise_error (context_p);
}
lexer_next_token (context_p);
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 (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;
}
JERRY_ASSERT (stack_top == SCAN_STACK_VAR);
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_EVAL_FUNCTION
|| stack_top == SCAN_STACK_FUNCTION_STATEMENT
|| stack_top == SCAN_STACK_FUNCTION_EXPRESSION
|| stack_top == SCAN_STACK_FUNCTION_PROPERTY);
if (type != LEXER_LEFT_PAREN)
{
scanner_raise_error (context_p);
}
lexer_next_token (context_p);
#if ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER)
/* FALLTHRU */
}
case SCAN_MODE_CONTINUE_FUNCTION_ARGUMENTS:
{
#endif /* ENABLED (JERRY_ES2015_FUNCTION_PARAMETER_INITIALIZER) */
if (context_p->token.type != LEXER_RIGHT_PAREN && context_p->token.type != LEXER_EOS)
{
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_EOS && stack_top == SCAN_STACK_EVAL_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;
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_context.mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
lexer_next_token (context_p);
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_context.mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
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_FUNCTION_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;
break;
}
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_FUNCTION_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);
}
scan_completed:
if (context_p->stack_top_uint8 != SCAN_STACK_SCRIPT
&& context_p->stack_top_uint8 != SCAN_STACK_EVAL_FUNCTION)
{
scanner_raise_error (context_p);
}
#ifndef JERRY_NDEBUG
context_p->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;
}
}
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;
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_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) */