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:
@@ -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)
|
||||
|
||||
@@ -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, \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.";
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user