Implement for-await-of statement. (#3946)

AsyncIteratorClose has not supported yet.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2020-06-30 11:21:50 +02:00
committed by GitHub
parent 0b404ea893
commit 5535ea88ac
20 changed files with 729 additions and 199 deletions
+1 -1
View File
@@ -27,7 +27,7 @@ JERRY_STATIC_ASSERT ((sizeof (cbc_uint16_arguments_t) % sizeof (jmem_cpointer_t)
*/
JERRY_STATIC_ASSERT (CBC_END == 238,
number_of_cbc_opcodes_changed);
JERRY_STATIC_ASSERT (CBC_EXT_END == 121,
JERRY_STATIC_ASSERT (CBC_EXT_END == 127,
number_of_cbc_ext_opcodes_changed);
#if ENABLED (JERRY_PARSER)
+14 -8
View File
@@ -196,6 +196,8 @@
#define PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION 4
/* PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION 4
/* PARSER_FOR_AWAIT_OF_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_FOR_AWAIT_OF_CONTEXT_STACK_ALLOCATION 4
/* PARSER_WITH_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_WITH_CONTEXT_STACK_ALLOCATION 1
/* PARSER_BLOCK_CONTEXT_STACK_ALLOCATION must be <= 3 */
@@ -536,20 +538,28 @@
-1 + PARSER_WITH_CONTEXT_STACK_ALLOCATION, VM_OC_WITH) \
CBC_OPCODE (CBC_EXT_FOR_IN_GET_NEXT, CBC_NO_FLAG, 1, \
VM_OC_FOR_IN_GET_NEXT | VM_OC_PUT_STACK) \
CBC_FORWARD_BRANCH (CBC_EXT_FOR_IN_CREATE_CONTEXT, \
-1 + PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION, VM_OC_FOR_IN_CREATE_CONTEXT) \
CBC_FORWARD_BRANCH (CBC_EXT_FOR_IN_INIT, \
-1 + PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION, VM_OC_FOR_IN_INIT) \
CBC_OPCODE (CBC_EXT_SET_GETTER, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_SET_GETTER | VM_OC_NON_STATIC_FLAG | VM_OC_GET_LITERAL_LITERAL) \
CBC_BACKWARD_BRANCH (CBC_EXT_BRANCH_IF_FOR_IN_HAS_NEXT, 0, \
VM_OC_FOR_IN_HAS_NEXT) \
CBC_OPCODE (CBC_EXT_FOR_OF_GET_NEXT, CBC_NO_FLAG, 1, \
VM_OC_FOR_OF_GET_NEXT | VM_OC_PUT_STACK) \
CBC_FORWARD_BRANCH (CBC_EXT_FOR_OF_CREATE_CONTEXT, \
-1 + PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION, VM_OC_FOR_OF_CREATE_CONTEXT) \
CBC_FORWARD_BRANCH (CBC_EXT_FOR_OF_INIT, \
-1 + PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION, VM_OC_FOR_OF_INIT) \
CBC_OPCODE (CBC_EXT_PUSH_NAMED_FUNC_EXPRESSION, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 1, \
VM_OC_PUSH_NAMED_FUNC_EXPR | VM_OC_GET_LITERAL_LITERAL) \
CBC_BACKWARD_BRANCH (CBC_EXT_BRANCH_IF_FOR_OF_HAS_NEXT, 0, \
VM_OC_FOR_OF_HAS_NEXT) \
CBC_OPCODE (CBC_EXT_CLONE_CONTEXT, CBC_NO_FLAG, 0, \
VM_OC_CLONE_CONTEXT) \
CBC_FORWARD_BRANCH (CBC_EXT_FOR_AWAIT_OF_INIT, \
-1 + PARSER_FOR_AWAIT_OF_CONTEXT_STACK_ALLOCATION, VM_OC_FOR_AWAIT_OF_INIT) \
CBC_OPCODE (CBC_EXT_CLONE_FULL_CONTEXT, CBC_NO_FLAG, 0, \
VM_OC_CLONE_CONTEXT) \
CBC_BACKWARD_BRANCH (CBC_EXT_BRANCH_IF_FOR_AWAIT_OF_HAS_NEXT, 0, \
VM_OC_FOR_AWAIT_OF_HAS_NEXT) \
CBC_OPCODE (CBC_EXT_SET_SETTER, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_SET_SETTER | VM_OC_NON_STATIC_FLAG | VM_OC_GET_LITERAL_LITERAL) \
CBC_FORWARD_BRANCH (CBC_EXT_TRY_CREATE_CONTEXT, PARSER_TRY_CONTEXT_STACK_ALLOCATION, \
@@ -588,10 +598,6 @@
VM_OC_STRING_CONCAT | VM_OC_GET_LITERAL_LITERAL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_EXT_GET_TAGGED_TEMPLATE_LITERAL, CBC_HAS_BYTE_ARG, 1, \
VM_OC_GET_TEMPLATE_OBJECT | VM_OC_PUT_STACK) \
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_LINE, CBC_NO_FLAG, 0, \
VM_OC_LINE) \
CBC_OPCODE (CBC_EXT_ERROR, CBC_NO_FLAG, 0, \
+88 -20
View File
@@ -60,6 +60,7 @@ typedef enum
PARSER_STATEMENT_FOR_IN,
#if ENABLED (JERRY_ESNEXT)
PARSER_STATEMENT_FOR_OF,
PARSER_STATEMENT_FOR_AWAIT_OF,
#endif /* ENABLED (JERRY_ESNEXT) */
PARSER_STATEMENT_WITH,
PARSER_STATEMENT_TRY,
@@ -119,6 +120,8 @@ static const uint8_t parser_statement_flags[] =
#if ENABLED (JERRY_ESNEXT)
/* PARSER_STATEMENT_FOR_OF */
PARSER_STATM_BREAK_TARGET | PARSER_STATM_CONTINUE_TARGET | PARSER_STATM_SINGLE_STATM | PARSER_STATM_CONTEXT_BREAK,
/* PARSER_STATEMENT_FOR_AWAIT_OF */
PARSER_STATM_BREAK_TARGET | PARSER_STATM_CONTINUE_TARGET | PARSER_STATM_SINGLE_STATM | PARSER_STATM_CONTEXT_BREAK,
#endif /* ENABLED (JERRY_ESNEXT) */
/* PARSER_STATEMENT_WITH */
PARSER_STATM_CONTEXT_BREAK | PARSER_STATM_SINGLE_STATM,
@@ -291,6 +294,8 @@ parser_statement_length (uint8_t type) /**< type of statement */
#if ENABLED (JERRY_ESNEXT)
/* PARSER_STATEMENT_FOR_OF */
(uint8_t) (sizeof (parser_for_in_of_statement_t) + sizeof (parser_loop_statement_t) + 1),
/* PARSER_STATEMENT_FOR_AWAIT_OF */
(uint8_t) (sizeof (parser_for_in_of_statement_t) + sizeof (parser_loop_statement_t) + 1),
#endif /* ENABLED (JERRY_ESNEXT) */
/* PARSER_STATEMENT_WITH */
(uint8_t) (sizeof (parser_with_statement_t) + 1 + 1),
@@ -1198,8 +1203,30 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_FOR);
lexer_next_token (context_p);
#if ENABLED (JERRY_ESNEXT)
bool is_for_await = false;
if (context_p->token.type == LEXER_KEYW_AWAIT)
{
if (JERRY_UNLIKELY (context_p->token.lit_location.has_escape))
{
parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD);
}
lexer_next_token (context_p);
is_for_await = true;
}
#endif /* ENABLED (JERRY_ESNEXT) */
if (context_p->token.type != LEXER_LEFT_PAREN)
{
#if ENABLED (JERRY_ESNEXT)
if (context_p->token.type == LEXER_LITERAL
&& context_p->token.keyword_type == LEXER_KEYW_AWAIT
&& !context_p->token.lit_location.has_escape)
{
parser_raise_error (context_p, PARSER_ERR_FOR_AWAIT_NO_ASYNC);
}
#endif /* ENABLED (JERRY_ESNEXT) */
parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED);
}
@@ -1274,6 +1301,16 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
const uint8_t *source_end_p = context_p->source_p - 2;
scanner_seek (context_p);
#if ENABLED (JERRY_ESNEXT)
if (is_for_in && is_for_await)
{
context_p->token.line = context_p->line;
context_p->token.column = context_p->column - 2;
parser_raise_error (context_p, PARSER_ERR_FOR_AWAIT_NO_OF);
}
#endif /* ENABLED (JERRY_ESNEXT) */
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR);
@@ -1288,10 +1325,16 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
: PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */
parser_emit_cbc_ext_forward_branch (context_p,
is_for_in ? CBC_EXT_FOR_IN_CREATE_CONTEXT
: CBC_EXT_FOR_OF_CREATE_CONTEXT,
&for_in_of_statement.branch);
cbc_ext_opcode_t init_opcode = CBC_EXT_FOR_IN_INIT;
#if ENABLED (JERRY_ESNEXT)
if (!is_for_in)
{
init_opcode = is_for_await ? CBC_EXT_FOR_AWAIT_OF_INIT : CBC_EXT_FOR_OF_INIT;
}
#endif /* ENABLED (JERRY_ESNEXT) */
parser_emit_cbc_ext_forward_branch (context_p, init_opcode, &for_in_of_statement.branch);
JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE);
for_in_of_statement.start_offset = context_p->byte_code_size;
@@ -1443,12 +1486,17 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
parser_stack_push (context_p, &for_in_of_statement, sizeof (parser_for_in_of_statement_t));
parser_stack_push (context_p, &loop, sizeof (parser_loop_statement_t));
uint8_t for_type = PARSER_STATEMENT_FOR_IN;
#if ENABLED (JERRY_ESNEXT)
parser_stack_push_uint8 (context_p, is_for_in ? PARSER_STATEMENT_FOR_IN
: PARSER_STATEMENT_FOR_OF);
#else /* !ENABLED (JERRY_ESNEXT) */
parser_stack_push_uint8 (context_p, PARSER_STATEMENT_FOR_IN);
if (!is_for_in)
{
for_type = is_for_await ? PARSER_STATEMENT_FOR_AWAIT_OF : PARSER_STATEMENT_FOR_OF;
}
#endif /* ENABLED (JERRY_ESNEXT) */
parser_stack_push_uint8 (context_p, for_type);
parser_stack_iterator_init (context_p, &context_p->last_statement);
return;
}
@@ -1515,6 +1563,13 @@ parser_parse_for_statement_start (parser_context_t *context_p) /**< context */
}
}
#if ENABLED (JERRY_ESNEXT)
if (is_for_await)
{
parser_raise_error (context_p, PARSER_ERR_FOR_AWAIT_NO_OF);
}
#endif /* ENABLED (JERRY_ESNEXT) */
JERRY_ASSERT (context_p->next_scanner_info_p->source_p != context_p->source_p
|| context_p->next_scanner_info_p->type == SCANNER_TYPE_FOR);
@@ -3286,15 +3341,14 @@ consume_last_statement:
case PARSER_STATEMENT_FOR_IN:
#if ENABLED (JERRY_ESNEXT)
case PARSER_STATEMENT_FOR_OF:
case PARSER_STATEMENT_FOR_AWAIT_OF:
#endif /* ENABLED (JERRY_ESNEXT) */
{
parser_for_in_of_statement_t for_in_of_statement;
parser_loop_statement_t loop;
#if ENABLED (JERRY_ESNEXT)
bool is_for_in = (context_p->stack_top_uint8 == PARSER_STATEMENT_FOR_IN);
#else
bool is_for_in = true;
uint8_t for_type = context_p->stack_top_uint8;
#endif /* ENABLED (JERRY_ESNEXT) */
parser_stack_pop_uint8 (context_p);
@@ -3305,18 +3359,32 @@ consume_last_statement:
parser_set_continues_to_current_position (context_p, loop.branch_list_p);
parser_flush_cbc (context_p);
PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, is_for_in ? PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION
: PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION);
uint16_t stack_allocation = PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION;
#if ENABLED (JERRY_ESNEXT)
if (for_type != PARSER_STATEMENT_FOR_IN)
{
stack_allocation = (for_type == PARSER_STATEMENT_FOR_OF ? PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION
: PARSER_FOR_AWAIT_OF_CONTEXT_STACK_ALLOCATION);
}
#endif /* ENABLED (JERRY_ESNEXT) */
PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, stack_allocation);
#ifndef JERRY_NDEBUG
PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth,
is_for_in ? PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION
: PARSER_FOR_OF_CONTEXT_STACK_ALLOCATION);
PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, stack_allocation);
#endif /* !JERRY_NDEBUG */
parser_emit_cbc_ext_backward_branch (context_p,
is_for_in ? CBC_EXT_BRANCH_IF_FOR_IN_HAS_NEXT
: CBC_EXT_BRANCH_IF_FOR_OF_HAS_NEXT,
for_in_of_statement.start_offset);
cbc_ext_opcode_t opcode = CBC_EXT_BRANCH_IF_FOR_IN_HAS_NEXT;
#if ENABLED (JERRY_ESNEXT)
if (for_type != PARSER_STATEMENT_FOR_IN)
{
opcode = (for_type == PARSER_STATEMENT_FOR_OF ? CBC_EXT_BRANCH_IF_FOR_OF_HAS_NEXT
: CBC_EXT_BRANCH_IF_FOR_AWAIT_OF_HAS_NEXT);
}
#endif /* ENABLED (JERRY_ESNEXT) */
parser_emit_cbc_ext_backward_branch (context_p, opcode, for_in_of_statement.start_offset);
parser_set_breaks_to_current_position (context_p, loop.branch_list_p);
parser_set_branch_to_current_position (context_p, &for_in_of_statement.branch);
+8
View File
@@ -956,6 +956,14 @@ parser_error_to_string (parser_error_t error) /**< error code */
{
return "for in-of loop variable declaration may not have an initializer.";
}
case PARSER_ERR_FOR_AWAIT_NO_ASYNC:
{
return "for-await-of is only allowed inside async functions and generators.";
}
case PARSER_ERR_FOR_AWAIT_NO_OF:
{
return "only 'of' form is allowed for for-await loops.";
}
case PARSER_ERR_DUPLICATED_PROTO:
{
return "Duplicate __proto__ fields are not allowed in object literals.";
+2
View File
@@ -82,6 +82,8 @@ typedef enum
PARSER_ERR_YIELD_NOT_ALLOWED, /**< yield expression is not allowed */
PARSER_ERR_AWAIT_NOT_ALLOWED, /**< await expression is not allowed */
PARSER_ERR_FOR_IN_OF_DECLARATION, /**< variable declaration in for-in or for-of loop */
PARSER_ERR_FOR_AWAIT_NO_ASYNC, /**< for-await-of is only allowed inside async functions */
PARSER_ERR_FOR_AWAIT_NO_OF, /**< only 'of' form is allowed for for-await loops */
PARSER_ERR_DUPLICATED_PROTO, /**< duplicated __proto__ fields are not allowed */
#endif /* ENABLED (JERRY_ESNEXT) */
PARSER_ERR_DELETE_IDENT_NOT_ALLOWED, /**< identifier delete is not allowed in strict mode */
+8
View File
@@ -1181,6 +1181,14 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */
case LEXER_KEYW_FOR:
{
lexer_next_token (context_p);
#if ENABLED (JERRY_ESNEXT)
if (context_p->token.type == LEXER_KEYW_AWAIT)
{
lexer_next_token (context_p);
}
#endif /* ENABLED (JERRY_ESNEXT) */
if (context_p->token.type != LEXER_LEFT_PAREN)
{
scanner_raise_error (context_p);