Implement for[in/of]-let construct. (#3294)

This patch implements let/const support for all "for" statements.
It includes an algorithm for cloning declarative lexical environments.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2019-11-11 13:53:32 +01:00
committed by Dániel Bátyai
parent 58f71e6ffa
commit da69589f05
8 changed files with 503 additions and 110 deletions
+4
View File
@@ -544,6 +544,10 @@
VM_OC_PUSH_LIT_POS_BYTE | VM_OC_GET_LITERAL) \
CBC_OPCODE (CBC_EXT_PUSH_LITERAL_PUSH_NUMBER_NEG_BYTE, CBC_HAS_LITERAL_ARG | CBC_HAS_BYTE_ARG, 2, \
VM_OC_PUSH_LIT_NEG_BYTE | VM_OC_GET_LITERAL) \
CBC_OPCODE (CBC_EXT_CLONE_CONTEXT, CBC_NO_FLAG, 0, \
VM_OC_CLONE_CONTEXT) \
CBC_OPCODE (CBC_EXT_CLONE_FULL_CONTEXT, CBC_NO_FLAG, 0, \
VM_OC_CLONE_CONTEXT) \
CBC_OPCODE (CBC_EXT_RESOURCE_NAME, CBC_NO_FLAG, 0, \
VM_OC_RESOURCE_NAME) \
CBC_OPCODE (CBC_EXT_LINE, CBC_NO_FLAG, 0, \
+240 -107
View File
@@ -58,6 +58,7 @@ typedef enum
PARSER_STATEMENT_START,
PARSER_STATEMENT_BLOCK,
#if ENABLED (JERRY_ES2015)
PARSER_STATEMENT_BLOCK_SCOPE,
PARSER_STATEMENT_BLOCK_CONTEXT,
#endif /* ENABLED (JERRY_ES2015) */
PARSER_STATEMENT_LABEL,
@@ -79,6 +80,7 @@ typedef enum
PARSER_STATEMENT_FOR_IN,
#if ENABLED (JERRY_ES2015)
PARSER_STATEMENT_FOR_OF,
PARSER_STATEMENT_FOR_CONTEXT,
#endif /* ENABLED (JERRY_ES2015) */
PARSER_STATEMENT_WITH,
PARSER_STATEMENT_TRY,
@@ -234,14 +236,13 @@ parser_statement_length (uint8_t type) /**< type of statement */
{
static const uint8_t statement_lengths[] =
{
#if ENABLED (JERRY_ES2015)
/* PARSER_STATEMENT_BLOCK */
1,
#if ENABLED (JERRY_ES2015)
/* PARSER_STATEMENT_BLOCK_SCOPE */
(uint8_t) (sizeof (parser_block_statement_t) + 1),
/* PARSER_STATEMENT_BLOCK_CONTEXT */
(uint8_t) (sizeof (parser_block_statement_t) + sizeof (parser_block_context_t) + 1),
#else /* !ENABLED (JERRY_ES2015) */
/* PARSER_STATEMENT_BLOCK */
1,
#endif /* ENABLED (JERRY_ES2015) */
/* PARSER_STATEMENT_LABEL */
(uint8_t) (sizeof (parser_label_statement_t) + 1),
@@ -268,6 +269,8 @@ parser_statement_length (uint8_t type) /**< type of statement */
#if ENABLED (JERRY_ES2015)
/* PARSER_STATEMENT_FOR_OF */
(uint8_t) (sizeof (parser_for_in_of_statement_t) + sizeof (parser_loop_statement_t) + 1),
/* PARSER_STATEMENT_FOR_CONTEXT */
1,
#endif /* ENABLED (JERRY_ES2015) */
/* PARSER_STATEMENT_WITH */
(uint8_t) (sizeof (parser_with_statement_t) + 1),
@@ -342,6 +345,85 @@ parser_parse_enclosed_expr (parser_context_t *context_p) /**< context */
lexer_next_token (context_p);
} /* parser_parse_enclosed_expr */
#if ENABLED (JERRY_ES2015)
/**
* Create a block context.
*
* @return true - when a context is created, false - otherwise
*/
static bool
parser_push_block_context (parser_context_t *context_p) /**< context */
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK);
parser_block_statement_t block_statement;
block_statement.scope_stack_top = context_p->scope_stack_top;
block_statement.scope_stack_reg_top = context_p->scope_stack_reg_top;
bool is_context_needed = false;
if (scanner_is_context_needed (context_p))
{
parser_block_context_t block_context;
#ifndef JERRY_NDEBUG
PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */
parser_emit_cbc_forward_branch (context_p,
CBC_BLOCK_CREATE_CONTEXT,
&block_context.branch);
parser_stack_push (context_p, &block_context, sizeof (parser_block_context_t));
is_context_needed = true;
}
scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS);
parser_stack_push (context_p, &block_statement, sizeof (parser_block_statement_t));
parser_stack_push_uint8 (context_p, (is_context_needed ? PARSER_STATEMENT_BLOCK_CONTEXT
: PARSER_STATEMENT_BLOCK_SCOPE));
return is_context_needed;
} /* parser_push_block_context */
/**
* Pop block context.
*/
static void
parser_pop_block_context (parser_context_t *context_p) /**< context */
{
JERRY_ASSERT (context_p->stack_top_uint8 == PARSER_STATEMENT_BLOCK_SCOPE
|| context_p->stack_top_uint8 == PARSER_STATEMENT_BLOCK_CONTEXT);
uint8_t type = context_p->stack_top_uint8;
parser_block_statement_t block_statement;
parser_stack_pop_uint8 (context_p);
parser_stack_pop (context_p, &block_statement, sizeof (parser_block_statement_t));
context_p->scope_stack_top = block_statement.scope_stack_top;
context_p->scope_stack_reg_top = block_statement.scope_stack_reg_top;
if (type == PARSER_STATEMENT_BLOCK_SCOPE)
{
return;
}
PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
#ifndef JERRY_NDEBUG
PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */
parser_block_context_t block_context;
parser_stack_pop (context_p, &block_context, sizeof (parser_block_context_t));
parser_emit_cbc (context_p, CBC_CONTEXT_END);
parser_set_branch_to_current_position (context_p, &block_context.branch);
} /* parser_pop_block_context */
#endif /* ENABLED (JERRY_ES2015) */
/**
* Parse var statement.
*/
@@ -980,18 +1062,33 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
|| context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_OF);
bool is_for_in = (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN);
scanner_get_location (&start_location, context_p);
lexer_next_token (context_p);
bool is_let_const = (context_p->token.type == LEXER_KEYW_LET || context_p->token.type == LEXER_KEYW_CONST);
const uint8_t *source_p = context_p->source_p;
#else /* !ENABLED (JERRY_ES2015) */
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR_IN);
bool is_for_in = true;
scanner_get_location (&start_location, context_p);
#endif /* ENABLED (JERRY_ES2015) */
scanner_get_location (&start_location, context_p);
scanner_set_location (context_p, &((scanner_location_info_t *) context_p->next_scanner_info_p)->location);
/* The length of both 'in' and 'of' is two. */
const uint8_t *source_end_p = context_p->source_p - 2;
scanner_release_next (context_p, sizeof (scanner_location_info_t));
#if ENABLED (JERRY_ES2015)
if (is_let_const && (context_p->next_scanner_info_p->source_p == source_p))
{
is_let_const = parser_push_block_context (context_p);
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_FOR_CONTEXT);
}
#endif /* ENABLED (JERRY_ES2015) */
scanner_seek (context_p);
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR);
@@ -1015,6 +1112,13 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE);
for_in_of_statement.start_offset = context_p->byte_code_size;
#if ENABLED (JERRY_ES2015)
if (is_let_const)
{
parser_emit_cbc_ext (context_p, CBC_EXT_CLONE_CONTEXT);
}
#endif /* ENABLED (JERRY_ES2015) */
/* The expression parser must not read the 'in' or 'of' tokens. */
scanner_get_location (&end_location, context_p);
scanner_set_location (context_p, &start_location);
@@ -1024,52 +1128,72 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
scanner_seek (context_p);
lexer_next_token (context_p);
if (context_p->token.type == LEXER_KEYW_VAR)
switch (context_p->token.type)
{
uint16_t literal_index;
lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL);
JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
literal_index = context_p->lit_object.index;
lexer_next_token (context_p);
if (context_p->token.type == LEXER_ASSIGN)
#if ENABLED (JERRY_ES2015)
case LEXER_KEYW_LET:
case LEXER_KEYW_CONST:
#endif /* ENABLED (JERRY_ES2015) */
case LEXER_KEYW_VAR:
{
parser_branch_t branch;
uint16_t literal_index;
lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL);
JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
literal_index = context_p->lit_object.index;
/* Initialiser is never executed. */
parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &branch);
lexer_next_token (context_p);
parser_parse_expression_statement (context_p, PARSE_EXPR_NO_COMMA);
parser_set_branch_to_current_position (context_p, &branch);
if (context_p->token.type == LEXER_ASSIGN)
{
parser_branch_t branch;
/* Initialiser is never executed. */
parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &branch);
lexer_next_token (context_p);
parser_parse_expression_statement (context_p, PARSE_EXPR_NO_COMMA);
parser_set_branch_to_current_position (context_p, &branch);
}
parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
: CBC_EXT_FOR_OF_GET_NEXT);
#if ENABLED (JERRY_ES2015)
if (literal_index >= PARSER_REGISTER_START)
{
is_let_const = false;
}
parser_emit_cbc_literal (context_p,
is_let_const ? CBC_ASSIGN_LET_CONST : CBC_ASSIGN_SET_IDENT,
literal_index);
#else /* !ENABLED (JERRY_ES2015) */
parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index);
#endif /* ENABLED (JERRY_ES2015) */
break;
}
default:
{
uint16_t opcode;
parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
: CBC_EXT_FOR_OF_GET_NEXT);
parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, literal_index);
}
else
{
uint16_t opcode;
parser_parse_expression (context_p, PARSE_EXPR_LEFT_HAND_SIDE);
parser_parse_expression (context_p, PARSE_EXPR_LEFT_HAND_SIDE);
opcode = context_p->last_cbc_opcode;
opcode = context_p->last_cbc_opcode;
/* The CBC_EXT_FOR_IN_CREATE_CONTEXT flushed the opcode combiner. */
JERRY_ASSERT (opcode != CBC_PUSH_TWO_LITERALS
&& opcode != CBC_PUSH_THREE_LITERALS);
/* The CBC_EXT_FOR_IN_CREATE_CONTEXT flushed the opcode combiner. */
JERRY_ASSERT (opcode != CBC_PUSH_TWO_LITERALS
&& opcode != CBC_PUSH_THREE_LITERALS);
opcode = parser_check_left_hand_side_expression (context_p, opcode);
opcode = parser_check_left_hand_side_expression (context_p, opcode);
parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
: CBC_EXT_FOR_OF_GET_NEXT);
parser_flush_cbc (context_p);
parser_emit_cbc_ext (context_p, is_for_in ? CBC_EXT_FOR_IN_GET_NEXT
: CBC_EXT_FOR_OF_GET_NEXT);
parser_flush_cbc (context_p);
context_p->last_cbc_opcode = opcode;
context_p->last_cbc_opcode = opcode;
break;
}
}
if (context_p->token.type != LEXER_EOS)
@@ -1104,13 +1228,30 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
if (context_p->token.type != LEXER_SEMICOLON)
{
if (context_p->token.type == LEXER_KEYW_VAR)
switch (context_p->token.type)
{
parser_parse_var_statement (context_p);
}
else
{
parser_parse_expression_statement (context_p, PARSE_EXPR);
#if ENABLED (JERRY_ES2015)
case LEXER_KEYW_LET:
case LEXER_KEYW_CONST:
{
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
parser_push_block_context (context_p);
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_FOR_CONTEXT);
}
/* FALLTHRU */
}
#endif /* ENABLED (JERRY_ES2015) */
case LEXER_KEYW_VAR:
{
parser_parse_var_statement (context_p);
break;
}
default:
{
parser_parse_expression_statement (context_p, PARSE_EXPR);
break;
}
}
if (context_p->token.type != LEXER_SEMICOLON)
@@ -1194,6 +1335,24 @@ parser_parse_for_statement_end (parser_context_t *context_p) /**< context */
parser_stack_iterator_skip (&iterator, sizeof (parser_loop_statement_t));
parser_stack_iterator_read (&iterator, &for_statement, sizeof (parser_for_statement_t));
#if ENABLED (JERRY_ES2015)
bool has_block_context = false;
uint8_t next_statement_type;
parser_stack_iterator_skip (&iterator, sizeof (parser_for_statement_t));
parser_stack_iterator_read (&iterator, &next_statement_type, 1);
if (next_statement_type == PARSER_STATEMENT_FOR_CONTEXT)
{
parser_stack_iterator_skip (&iterator, 1);
parser_stack_iterator_read (&iterator, &next_statement_type, 1);
if (next_statement_type == PARSER_STATEMENT_BLOCK_CONTEXT)
{
has_block_context = true;
}
}
#endif
scanner_get_location (&location, context_p);
current_token = context_p->token;
@@ -1203,6 +1362,13 @@ parser_parse_for_statement_end (parser_context_t *context_p) /**< context */
parser_set_continues_to_current_position (context_p, loop.branch_list_p);
#if ENABLED (JERRY_ES2015)
if (has_block_context)
{
parser_emit_cbc_ext (context_p, CBC_EXT_CLONE_FULL_CONTEXT);
}
#endif
if (context_p->token.type != LEXER_RIGHT_PAREN)
{
parser_parse_expression_statement (context_p, PARSE_EXPR);
@@ -1251,6 +1417,15 @@ parser_parse_for_statement_end (parser_context_t *context_p) /**< context */
parser_emit_cbc_backward_branch (context_p, (uint16_t) opcode, for_statement.start_offset);
parser_set_breaks_to_current_position (context_p, loop.branch_list_p);
#if ENABLED (JERRY_ES2015)
if (context_p->stack_top_uint8 == PARSER_STATEMENT_FOR_CONTEXT)
{
parser_stack_pop_uint8 (context_p);
parser_pop_block_context (context_p);
parser_stack_iterator_init (context_p, &context_p->last_statement);
}
#endif
/* Calling scanner_seek is unnecessary because all
* info blocks inside the for statement should be processed. */
scanner_set_location (context_p, &location);
@@ -1324,13 +1499,6 @@ parser_parse_switch_statement_start (parser_context_t *context_p) /**< context *
parser_emit_cbc (context_p, CBC_POP);
parser_flush_cbc (context_p);
#if ENABLED (JERRY_ES2015)
parser_block_statement_t block_statement;
block_statement.scope_stack_top = context_p->scope_stack_top;
block_statement.scope_stack_reg_top = context_p->scope_stack_reg_top;
parser_stack_push (context_p, &block_statement, sizeof (parser_block_statement_t));
#endif /* ENABLED (JERRY_ES2015) */
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_BLOCK);
parser_stack_iterator_init (context_p, &context_p->last_statement);
return;
@@ -2483,39 +2651,19 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
case LEXER_LEFT_BRACE:
{
uint8_t block_type = PARSER_STATEMENT_BLOCK;
#if ENABLED (JERRY_ES2015)
parser_block_statement_t block_statement;
block_statement.scope_stack_top = context_p->scope_stack_top;
block_statement.scope_stack_reg_top = context_p->scope_stack_reg_top;
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK);
if (scanner_is_context_needed (context_p))
{
parser_block_context_t block_context;
#ifndef JERRY_NDEBUG
PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */
parser_emit_cbc_forward_branch (context_p,
CBC_BLOCK_CREATE_CONTEXT,
&block_context.branch);
parser_stack_push (context_p, &block_context, sizeof (parser_block_context_t));
block_type = PARSER_STATEMENT_BLOCK_CONTEXT;
}
scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS);
parser_push_block_context (context_p);
}
parser_stack_push (context_p, &block_statement, sizeof (parser_block_statement_t));
else
{
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_BLOCK);
}
#else /* !ENABLED (JERRY_ES2015) */
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_BLOCK);
#endif /* ENABLED (JERRY_ES2015) */
parser_stack_push_uint8 (context_p, block_type);
parser_stack_iterator_init (context_p, &context_p->last_statement);
lexer_next_token (context_p);
continue;
@@ -2810,38 +2958,14 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
if (context_p->stack_top_uint8 == PARSER_STATEMENT_BLOCK)
{
parser_stack_pop_uint8 (context_p);
#if ENABLED (JERRY_ES2015)
parser_block_statement_t block_statement;
parser_stack_pop (context_p, &block_statement, sizeof (parser_block_statement_t));
context_p->scope_stack_top = block_statement.scope_stack_top;
context_p->scope_stack_reg_top = block_statement.scope_stack_reg_top;
#endif /* ENABLED (JERRY_ES2015) */
parser_stack_iterator_init (context_p, &context_p->last_statement);
lexer_next_token (context_p);
}
#if ENABLED (JERRY_ES2015)
else if (context_p->stack_top_uint8 == PARSER_STATEMENT_BLOCK_CONTEXT)
else if (context_p->stack_top_uint8 == PARSER_STATEMENT_BLOCK_SCOPE
|| context_p->stack_top_uint8 == PARSER_STATEMENT_BLOCK_CONTEXT)
{
parser_block_statement_t block_statement;
parser_block_context_t block_context;
parser_stack_pop_uint8 (context_p);
parser_stack_pop (context_p, &block_statement, sizeof (parser_block_statement_t));
parser_stack_pop (context_p, &block_context, sizeof (parser_block_context_t));
context_p->scope_stack_top = block_statement.scope_stack_top;
context_p->scope_stack_reg_top = block_statement.scope_stack_reg_top;
PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
#ifndef JERRY_NDEBUG
PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_BLOCK_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */
parser_emit_cbc (context_p, CBC_CONTEXT_END);
parser_set_branch_to_current_position (context_p, &block_context.branch);
parser_pop_block_context (context_p);
parser_stack_iterator_init (context_p, &context_p->last_statement);
lexer_next_token (context_p);
@@ -3038,6 +3162,15 @@ consume_last_statement:
parser_set_breaks_to_current_position (context_p, loop.branch_list_p);
parser_set_branch_to_current_position (context_p, &for_in_of_statement.branch);
#if ENABLED (JERRY_ES2015)
if (context_p->stack_top_uint8 == PARSER_STATEMENT_FOR_CONTEXT)
{
parser_stack_pop_uint8 (context_p);
parser_pop_block_context (context_p);
parser_stack_iterator_init (context_p, &context_p->last_statement);
}
#endif /* ENABLED (JERRY_ES2015) */
continue;
}
+61 -3
View File
@@ -80,6 +80,10 @@ typedef enum
/* 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 */
#if ENABLED (JERRY_ES2015)
SCAN_STACK_FOR_LET_START, /**< start of "for" iterator with let statement */
SCAN_STACK_FOR_CONST_START, /**< start of "for" iterator with const statement */
#endif /* ENABLED (JERRY_ES2015) */
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 */
@@ -93,6 +97,7 @@ typedef enum
#if ENABLED (JERRY_ES2015)
SCAN_STACK_COMPUTED_PROPERTY, /**< computed property name */
SCAN_STACK_TEMPLATE_STRING, /**< template string */
SCAN_STACK_FOR_BLOCK_END, /**< end of "for" statement with let/const declaration */
SCAN_STACK_ARROW_ARGUMENTS, /**< might be arguments of an arrow function */
SCAN_STACK_ARROW_EXPRESSION, /**< expression body of an arrow function */
SCAN_STACK_CLASS_STATEMENT, /**< class statement */
@@ -517,6 +522,10 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
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;
@@ -540,7 +549,9 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
}
JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_LET
|| context_p->stack_top_uint8 == SCAN_STACK_CONST);
|| 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);
scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT;
return SCAN_NEXT_TOKEN;
@@ -670,6 +681,13 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
let_const_literal.literal_p->type |= SCANNER_LITERAL_NO_REG;
}
if (context_p->stack_top_uint8 == SCAN_STACK_FOR_LET_START
|| context_p->stack_top_uint8 == SCAN_STACK_FOR_CONST_START)
{
scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
return SCAN_KEEP_TOKEN;
}
JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_LET
|| context_p->stack_top_uint8 == SCAN_STACK_CONST);
/* FALLTHRU */
@@ -689,6 +707,10 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
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 ())
@@ -704,6 +726,11 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
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) */
@@ -725,6 +752,13 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context *
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);
@@ -1147,6 +1181,21 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
stack_mode = SCAN_STACK_FOR_VAR_START;
break;
}
#if ENABLED (JERRY_ES2015)
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 = context_p->source_p;
scanner_context_p->mode = SCAN_MODE_VAR_STATEMENT;
stack_mode = ((context_p->token.type == LEXER_KEYW_LET) ? SCAN_STACK_FOR_LET_START
: SCAN_STACK_FOR_CONST_START);
break;
}
#endif /* ENABLED (JERRY_ES2015) */
}
parser_stack_push (context_p, &for_statement, sizeof (scanner_for_statement_t));
@@ -1903,6 +1952,14 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */
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
@@ -2236,16 +2293,17 @@ scanner_scan_all (parser_context_t *context_p, /**< context */
lexer_lit_location_t *literal_p = scanner_add_literal (context_p, &scanner_context);
#if ENABLED (JERRY_ES2015)
if (stack_top == SCAN_STACK_LET || stack_top == SCAN_STACK_CONST)
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)
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;
}