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