diff --git a/jerry-core/include/jerryscript-snapshot.h b/jerry-core/include/jerryscript-snapshot.h index 263d5cd0f..291dd5755 100644 --- a/jerry-core/include/jerryscript-snapshot.h +++ b/jerry-core/include/jerryscript-snapshot.h @@ -30,7 +30,7 @@ extern "C" /** * Jerry snapshot format version. */ -#define JERRY_SNAPSHOT_VERSION (43u) +#define JERRY_SNAPSHOT_VERSION (44u) /** * Flags for jerry_generate_snapshot and jerry_generate_function_snapshot. diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index 5453fb331..194d90d09 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -707,9 +707,11 @@ CBC_OPCODE (CBC_EXT_CREATE_GENERATOR, CBC_NO_FLAG, 1, \ VM_OC_CREATE_GENERATOR) \ CBC_OPCODE (CBC_EXT_YIELD, CBC_NO_FLAG, 0, \ - VM_OC_YIELD | VM_OC_GET_STACK) \ + VM_OC_YIELD) \ CBC_OPCODE (CBC_EXT_YIELD_ITERATOR, CBC_NO_FLAG, 0, \ - VM_OC_YIELD | VM_OC_GET_STACK) \ + VM_OC_YIELD) \ + CBC_OPCODE (CBC_EXT_AWAIT, CBC_NO_FLAG, 0, \ + VM_OC_AWAIT) \ CBC_OPCODE (CBC_EXT_RETURN, CBC_NO_FLAG, -1, \ VM_OC_EXT_RETURN | VM_OC_GET_STACK) \ CBC_OPCODE (CBC_EXT_RETURN_PROMISE, CBC_NO_FLAG, -1, \ diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c index f66100334..54b9972e5 100644 --- a/jerry-core/parser/js/js-lexer.c +++ b/jerry-core/parser/js/js-lexer.c @@ -817,6 +817,29 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */ if (JERRY_LIKELY (keyword_p->type < LEXER_FIRST_NON_RESERVED_KEYWORD)) { +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (keyword_p->type == LEXER_KEYW_AWAIT)) + { + if (!(context_p->status_flags & PARSER_IS_ASYNC_FUNCTION) + && !(context_p->global_status_flags & ECMA_PARSE_MODULE)) + { + break; + } + + if (context_p->status_flags & PARSER_DISALLOW_AWAIT_YIELD) + { + if (ident_start_p == buffer_p) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD); + } + parser_raise_error (context_p, PARSER_ERR_AWAIT_NOT_ALLOWED); + } + + context_p->token.type = (uint8_t) LEXER_KEYW_AWAIT; + break; + } +#endif /* ENABLED (JERRY_ES2015) */ + if (ident_start_p == buffer_p) { /* Escape sequences are not allowed in a keyword. */ @@ -828,30 +851,31 @@ lexer_parse_identifier (parser_context_t *context_p, /**< context */ } #if ENABLED (JERRY_ES2015) - if (keyword_p->type == LEXER_KEYW_YIELD && (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION)) + if (keyword_p->type == LEXER_KEYW_LET && (context_p->status_flags & PARSER_IS_STRICT)) { if (ident_start_p == buffer_p) { parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD); } - if (context_p->status_flags & PARSER_DISALLOW_YIELD) + context_p->token.type = (uint8_t) LEXER_KEYW_LET; + break; + } + + if (keyword_p->type == LEXER_KEYW_YIELD && (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION)) + { + if (context_p->status_flags & PARSER_DISALLOW_AWAIT_YIELD) { + if (ident_start_p == buffer_p) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD); + } parser_raise_error (context_p, PARSER_ERR_YIELD_NOT_ALLOWED); } context_p->token.type = (uint8_t) LEXER_KEYW_YIELD; break; } - - if (keyword_p->type == LEXER_KEYW_LET && ident_start_p != buffer_p) - { - if (context_p->status_flags & PARSER_IS_STRICT) - { - context_p->token.type = (uint8_t) LEXER_KEYW_LET; - } - break; - } #endif /* ENABLED (JERRY_ES2015) */ if (keyword_p->type >= LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD @@ -1948,8 +1972,11 @@ lexer_check_yield_no_arg (parser_context_t *context_p) /**< context */ bool lexer_consume_generator (parser_context_t *context_p) /**< context */ { - JERRY_ASSERT (context_p->token.flags & LEXER_NO_SKIP_SPACES); - JERRY_ASSERT (context_p->token.type == LEXER_KEYW_ASYNC); + if (!(context_p->token.flags & LEXER_NO_SKIP_SPACES)) + { + lexer_skip_spaces (context_p); + context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES); + } if (context_p->source_p >= context_p->source_end_p || context_p->source_p[0] != LIT_CHAR_ASTERISK @@ -1964,6 +1991,54 @@ lexer_consume_generator (parser_context_t *context_p) /**< context */ return true; } /* lexer_consume_generator */ +/** + * Update await / yield keywords after an arrow function with expression. + */ +void +lexer_update_await_yield (parser_context_t *context_p, /**< context */ + uint32_t status_flags) /**< parser status flags after restore */ +{ + if (!(status_flags & PARSER_IS_STRICT)) + { + if (status_flags & PARSER_IS_GENERATOR_FUNCTION) + { + if (context_p->token.type == LEXER_LITERAL + && context_p->token.keyword_type == LEXER_KEYW_YIELD) + { + context_p->token.type = LEXER_KEYW_YIELD; + } + } + else + { + if (context_p->token.type == LEXER_KEYW_YIELD) + { + JERRY_ASSERT (context_p->token.keyword_type == LEXER_KEYW_YIELD); + context_p->token.type = LEXER_LITERAL; + } + } + } + + if (!(context_p->global_status_flags & ECMA_PARSE_MODULE)) + { + if (status_flags & PARSER_IS_ASYNC_FUNCTION) + { + if (context_p->token.type == LEXER_LITERAL + && context_p->token.keyword_type == LEXER_KEYW_AWAIT) + { + context_p->token.type = LEXER_KEYW_AWAIT; + } + } + else + { + if (context_p->token.type == LEXER_KEYW_AWAIT) + { + JERRY_ASSERT (context_p->token.keyword_type == LEXER_KEYW_AWAIT); + context_p->token.type = LEXER_LITERAL; + } + } + } +} /* lexer_update_await_yield */ + #endif /* ENABLED (JERRY_ES2015) */ /** @@ -2853,6 +2928,16 @@ lexer_expect_identifier (parser_context_t *context_p, /**< context */ } #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ +#if ENABLED (JERRY_ES2015) + if (context_p->token.type == LEXER_KEYW_YIELD) + { + parser_raise_error (context_p, PARSER_ERR_YIELD_NOT_ALLOWED); + } + if (context_p->token.type == LEXER_KEYW_AWAIT) + { + parser_raise_error (context_p, PARSER_ERR_AWAIT_NOT_ALLOWED); + } +#endif /* ENABLED (JERRY_ES2015) */ parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); } /* lexer_expect_identifier */ diff --git a/jerry-core/parser/js/js-lexer.h b/jerry-core/parser/js/js-lexer.h index 8fd4af206..ac1f5ad05 100644 --- a/jerry-core/parser/js/js-lexer.h +++ b/jerry-core/parser/js/js-lexer.h @@ -58,6 +58,9 @@ typedef enum LEXER_BIT_NOT, /**< "~" */ LEXER_KEYW_VOID, /**< void */ LEXER_KEYW_TYPEOF, /**< typeof */ +#if ENABLED (JERRY_ES2015) + LEXER_KEYW_AWAIT, /**< await */ +#endif /* ENABLED (JERRY_ES2015) */ LEXER_KEYW_DELETE, /**< delete */ LEXER_INCREASE, /**< "++" */ LEXER_DECREASE, /**< "--" */ @@ -164,9 +167,6 @@ typedef enum LEXER_KEYW_EXPORT, /**< export */ LEXER_KEYW_IMPORT, /**< import */ LEXER_KEYW_ENUM, /**< enum */ -#if ENABLED (JERRY_ES2015) - LEXER_KEYW_AWAIT, /**< await */ -#endif /* ENABLED (JERRY_ES2015) */ /* These are virtual tokens. */ LEXER_EXPRESSION_START, /**< expression start */ @@ -177,7 +177,6 @@ typedef enum LEXER_ASSIGN_CONST, /**< a const binding is reassigned */ LEXER_CLASS_CONSTRUCTOR, /**< special value for class constructor method */ LEXER_INVALID_PATTERN, /**< special value for invalid destructuring pattern */ - LEXER_ARROW_LEFT_PAREN, /**< start of arrow function argument list */ #endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015) diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 37392fbac..380d45a06 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -644,8 +644,14 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */ } } + status_flags &= (uint32_t) ~(PARSER_IS_GENERATOR_FUNCTION + | PARSER_IS_ASYNC_FUNCTION + | PARSER_DISALLOW_AWAIT_YIELD); + if (context_p->token.type == LEXER_KEYW_ASYNC) { + status_flags |= PARSER_IS_ASYNC_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; + if (!lexer_consume_generator (context_p)) { lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); @@ -655,11 +661,7 @@ parser_parse_class_literal (parser_context_t *context_p, /**< context */ if (context_p->token.type == LEXER_MULTIPLY) { lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); - status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD; - } - else - { - status_flags &= (uint32_t) ~(PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD); + status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; } if (context_p->token.type == LEXER_RIGHT_SQUARE) @@ -1006,17 +1008,19 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ break; } case LEXER_KEYW_ASYNC: - { - lexer_consume_generator (context_p); - /* FALLTHRU */ - } case LEXER_MULTIPLY: { uint32_t status_flags = PARSER_FUNCTION_CLOSURE; + if (context_p->token.type == LEXER_KEYW_ASYNC) + { + status_flags |= PARSER_IS_ASYNC_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; + lexer_consume_generator (context_p); + } + if (context_p->token.type == LEXER_MULTIPLY) { - status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD; + status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; } lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); @@ -1164,8 +1168,15 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */ uint16_t function_literal_index; int32_t function_name_index = -1; +#if !ENABLED (JERRY_ES2015) + JERRY_ASSERT (status_flags & PARSER_IS_FUNC_EXPRESSION); +#endif /* !ENABLED (JERRY_ES2015) */ + +#if ENABLED (JERRY_ES2015) if (status_flags & PARSER_IS_FUNC_EXPRESSION) { +#endif /* !ENABLED (JERRY_ES2015) */ + #if ENABLED (JERRY_DEBUGGER) parser_line_counter_t debugger_line = context_p->token.line; parser_line_counter_t debugger_column = context_p->token.column; @@ -1174,16 +1185,21 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */ #if ENABLED (JERRY_ES2015) uint32_t parent_status_flags = context_p->status_flags; - if (lexer_check_next_character (context_p, LIT_CHAR_ASTERISK)) + context_p->status_flags &= (uint32_t) ~(PARSER_IS_ASYNC_FUNCTION + | PARSER_IS_GENERATOR_FUNCTION + | PARSER_DISALLOW_AWAIT_YIELD); + + if (status_flags & PARSER_IS_ASYNC_FUNCTION) + { + /* The name of the function cannot be await. */ + context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; + } + + if (lexer_consume_generator (context_p)) { /* The name of the function cannot be yield. */ - context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD; - status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD; - lexer_consume_next_character (context_p); - } - else - { - context_p->status_flags &= (uint32_t) ~(PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD); + context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; + status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; } #endif /* ENABLED (JERRY_ES2015) */ @@ -1225,8 +1241,8 @@ parser_parse_function_expression (parser_context_t *context_p, /**< context */ #if ENABLED (JERRY_ES2015) context_p->status_flags = parent_status_flags; -#endif /* ENABLED (JERRY_ES2015) */ } +#endif /* ENABLED (JERRY_ES2015) */ if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) { @@ -1486,13 +1502,28 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ while (true) { /* Convert plus and minus binary operators to unary operators. */ - if (context_p->token.type == LEXER_ADD) + switch (context_p->token.type) { - context_p->token.type = LEXER_PLUS; - } - else if (context_p->token.type == LEXER_SUBTRACT) - { - context_p->token.type = LEXER_NEGATE; + case LEXER_ADD: + { + context_p->token.type = LEXER_PLUS; + break; + } + case LEXER_SUBTRACT: + { + context_p->token.type = LEXER_NEGATE; + break; + } +#if ENABLED (JERRY_ES2015) + case LEXER_KEYW_AWAIT: + { + if (JERRY_UNLIKELY (context_p->token.lit_location.has_escape)) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD); + } + break; + } +#endif /* ENABLED (JERRY_ES2015) */ } /* Bracketed expressions are primary expressions. At this @@ -1561,30 +1592,41 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ case LEXER_LITERAL: { #if ENABLED (JERRY_ES2015) - if (context_p->next_scanner_info_p->source_p == context_p->source_p) + if (JERRY_UNLIKELY (context_p->next_scanner_info_p->source_p == context_p->source_p)) { JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION); + uint32_t arrow_status_flags = (PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION); + if (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_ASYNC) { JERRY_ASSERT (lexer_token_is_async (context_p)); JERRY_ASSERT (!(context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_STATEMENT)); + uint32_t saved_status_flags = context_p->status_flags; + + context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; lexer_next_token (context_p); + context_p->status_flags = saved_status_flags; if (context_p->token.type == LEXER_KEYW_FUNCTION) { - parser_parse_function_expression (context_p, PARSER_FUNCTION_CLOSURE | PARSER_IS_FUNC_EXPRESSION); + uint32_t status_flags = (PARSER_FUNCTION_CLOSURE + | PARSER_IS_FUNC_EXPRESSION + | PARSER_IS_ASYNC_FUNCTION + | PARSER_DISALLOW_AWAIT_YIELD); + parser_parse_function_expression (context_p, status_flags); break; } - if (context_p->token.type == LEXER_LEFT_PAREN) - { - context_p->token.type = LEXER_ARROW_LEFT_PAREN; - } + + arrow_status_flags = (PARSER_IS_FUNCTION + | PARSER_IS_ARROW_FUNCTION + | PARSER_IS_ASYNC_FUNCTION + | PARSER_DISALLOW_AWAIT_YIELD); } parser_check_assignment_expr (context_p); - parser_parse_function_expression (context_p, PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION); + parser_parse_function_expression (context_p, arrow_status_flags); return parser_abort_parsing_after_arrow (context_p); } #endif /* ENABLED (JERRY_ES2015) */ @@ -1789,14 +1831,18 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ parser_check_assignment_expr (context_p); - context_p->token.type = LEXER_ARROW_LEFT_PAREN; parser_parse_function_expression (context_p, PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION); return parser_abort_parsing_after_arrow (context_p); } case LEXER_KEYW_YIELD: { JERRY_ASSERT ((context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION) - && !(context_p->status_flags & PARSER_DISALLOW_YIELD)); + && !(context_p->status_flags & PARSER_DISALLOW_AWAIT_YIELD)); + + if (context_p->token.lit_location.has_escape) + { + parser_raise_error (context_p, PARSER_ERR_INVALID_KEYWORD); + } parser_check_assignment_expr (context_p); lexer_next_token (context_p); @@ -2216,6 +2262,12 @@ parser_process_unary_expression (parser_context_t *context_p, /**< context */ } parser_emit_unary_lvalue_opcode (context_p, (cbc_opcode_t) token); } +#if ENABLED (JERRY_ES2015) + else if (JERRY_UNLIKELY (token == LEXER_KEYW_AWAIT)) + { + parser_emit_cbc_ext (context_p, CBC_EXT_AWAIT); + } +#endif /* ENABLED (JERRY_ES2015) */ else { token = (uint8_t) (LEXER_UNARY_OP_TOKEN_TO_OPCODE (token)); diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index 6aaf143a1..5f8cd9f83 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -63,7 +63,7 @@ typedef enum PARSER_IS_ARROW_FUNCTION = (1u << 13), /**< an arrow function is parsed */ PARSER_IS_GENERATOR_FUNCTION = (1u << 14), /**< a generator function is parsed */ PARSER_IS_ASYNC_FUNCTION = (1u << 15), /**< an async function is parsed */ - PARSER_DISALLOW_YIELD = (1u << 16), /**< throw SyntaxError for yield expression */ + PARSER_DISALLOW_AWAIT_YIELD = (1u << 16), /**< throw SyntaxError for await / yield keywords */ PARSER_FUNCTION_IS_PARSING_ARGS = (1u << 17), /**< set when parsing function arguments */ PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM = (1u << 18), /**< function has a non simple parameter */ PARSER_FUNCTION_HAS_REST_PARAM = (1u << 19), /**< function has rest parameter */ @@ -681,6 +681,7 @@ bool lexer_check_arrow (parser_context_t *context_p); bool lexer_check_arrow_param (parser_context_t *context_p); bool lexer_check_yield_no_arg (parser_context_t *context_p); bool lexer_consume_generator (parser_context_t *context_p); +void lexer_update_await_yield (parser_context_t *context_p, uint32_t status_flags); #endif /* ENABLED (JERRY_ES2015) */ void lexer_parse_string (parser_context_t *context_p, lexer_string_options_t opts); void lexer_expect_identifier (parser_context_t *context_p, uint8_t literal_type); diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 4b63d5c56..38182f95f 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -684,10 +684,9 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */ #if ENABLED (JERRY_ES2015) bool is_generator_function = false; - if (lexer_check_next_character (context_p, LIT_CHAR_ASTERISK)) + if (lexer_consume_generator (context_p)) { is_generator_function = true; - lexer_consume_next_character (context_p); } #endif /* ENABLED (JERRY_ES2015) */ @@ -715,10 +714,17 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */ status_flags |= PARSER_HAS_NON_STRICT_ARG; } + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION); + #if ENABLED (JERRY_ES2015) if (is_generator_function) { - status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD; + status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; + } + + if (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_ASYNC) + { + status_flags |= PARSER_IS_ASYNC_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; } #endif /* ENABLED (JERRY_ES2015) */ @@ -3054,12 +3060,23 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ if (JERRY_UNLIKELY (lexer_token_is_async (context_p)) && context_p->next_scanner_info_p->source_p == context_p->source_p) { - JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION); + bool is_statement = true; - if (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_STATEMENT) + if (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION) { - JERRY_ASSERT (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_ASYNC); + is_statement = (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_STATEMENT) != 0; + JERRY_ASSERT (!is_statement || (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_ASYNC)); + } + else + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_ASYNC_FUNCTION); + + scanner_release_next (context_p, sizeof (scanner_info_t)); + } + + if (is_statement) + { if (parser_statement_flags[context_p->stack_top_uint8] & PARSER_STATM_SINGLE_STATM) { parser_raise_error (context_p, PARSER_ERR_LEXICAL_SINGLE_STATEMENT); diff --git a/jerry-core/parser/js/js-parser-util.c b/jerry-core/parser/js/js-parser-util.c index 65c58c1ea..14b56057e 100644 --- a/jerry-core/parser/js/js-parser-util.c +++ b/jerry-core/parser/js/js-parser-util.c @@ -951,7 +951,11 @@ parser_error_to_string (parser_error_t error) /**< error code */ } case PARSER_ERR_YIELD_NOT_ALLOWED: { - return "Incorrect use of yield keyword."; + return "Yield expression is not allowed here."; + } + case PARSER_ERR_AWAIT_NOT_ALLOWED: + { + return "Await expression is not allowed here."; } case PARSER_ERR_FOR_IN_OF_DECLARATION: { diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index d42555340..6778ce94a 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -1718,10 +1718,10 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ bool has_duplicated_arg_names = false; /* TODO: Currently async iterators are not supported, so generators ignore the async modifier. */ - if ((context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_ASYNC) - && !(context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION)) + uint32_t mask = (PARSER_IS_GENERATOR_FUNCTION | PARSER_IS_ASYNC_FUNCTION); + if ((context_p->status_flags & mask) == mask) { - context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION; + context_p->status_flags &= (uint32_t) ~PARSER_IS_ASYNC_FUNCTION; } #endif /* ENABLED (JERRY_ES2015) */ @@ -1734,7 +1734,7 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ parser_emit_cbc (context_p, CBC_POP); } - context_p->status_flags &= (uint32_t) ~PARSER_DISALLOW_YIELD; + context_p->status_flags &= (uint32_t) ~PARSER_DISALLOW_AWAIT_YIELD; #endif /* ENABLED (JERRY_ES2015) */ scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS); return; @@ -1972,7 +1972,7 @@ parser_parse_function_arguments (parser_context_t *context_p, /**< context */ } } - context_p->status_flags &= (uint32_t) ~(PARSER_DISALLOW_YIELD | PARSER_FUNCTION_IS_PARSING_ARGS); + context_p->status_flags &= (uint32_t) ~(PARSER_DISALLOW_AWAIT_YIELD | PARSER_FUNCTION_IS_PARSING_ARGS); #endif /* ENABLED (JERRY_ES2015) */ scanner_create_variables (context_p, SCANNER_CREATE_VARS_IS_FUNCTION_BODY); @@ -2529,7 +2529,7 @@ parser_parse_arrow_function (parser_context_t *context_p, /**< context */ } #endif /* ENABLED (JERRY_DEBUGGER) */ - if (context_p->token.type == LEXER_ARROW_LEFT_PAREN) + if (context_p->token.type == LEXER_LEFT_PAREN) { lexer_next_token (context_p); parser_parse_function_arguments (context_p, LEXER_RIGHT_PAREN); @@ -2581,6 +2581,8 @@ parser_parse_arrow_function (parser_context_t *context_p, /**< context */ } } parser_flush_cbc (context_p); + + lexer_update_await_yield (context_p, saved_context.status_flags); } compiled_code_p = parser_post_processing (context_p); diff --git a/jerry-core/parser/js/js-parser.h b/jerry-core/parser/js/js-parser.h index 05a3b8fde..c883ac09f 100644 --- a/jerry-core/parser/js/js-parser.h +++ b/jerry-core/parser/js/js-parser.h @@ -79,7 +79,8 @@ typedef enum PARSER_ERR_ARGUMENTS_NOT_ALLOWED, /**< arguments is not allowed here in strict mode */ #if ENABLED (JERRY_ES2015) PARSER_ERR_USE_STRICT_NOT_ALLOWED, /**< use strict directive is not allowed */ - PARSER_ERR_YIELD_NOT_ALLOWED, /**< yield keyword is not allowed */ + 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_DUPLICATED_PROTO, /**< duplicated __proto__ fields are not allowed */ #endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/parser/js/js-scanner-internal.h b/jerry-core/parser/js/js-scanner-internal.h index 8cc94e0ee..3dbaf97a8 100644 --- a/jerry-core/parser/js/js-scanner-internal.h +++ b/jerry-core/parser/js/js-scanner-internal.h @@ -95,10 +95,13 @@ typedef enum SCAN_STACK_CATCH_STATEMENT, /**< catch statement */ SCAN_STACK_ARRAY_LITERAL, /**< array literal or destructuring assignment or binding */ SCAN_STACK_OBJECT_LITERAL, /**< object literal group */ - SCAN_STACK_PROPERTY_ACCESSOR, /**< property accessor in squarey brackets */ + SCAN_STACK_PROPERTY_ACCESSOR, /**< property accessor in square brackets */ #if ENABLED (JERRY_ES2015) + /* These four must be in this order. */ SCAN_STACK_COMPUTED_PROPERTY, /**< computed property name */ - SCAN_STACK_COMPUTED_GENERATOR_FUNCTION, /**< computed property name */ + SCAN_STACK_COMPUTED_GENERATOR, /**< computed generator function */ + SCAN_STACK_COMPUTED_ASYNC, /**< computed async function */ + SCAN_STACK_COMPUTED_ASYNC_GENERATOR, /**< computed async function */ SCAN_STACK_TEMPLATE_STRING, /**< template string */ SCAN_STACK_TAGGED_TEMPLATE_LITERAL, /**< tagged template literal */ SCAN_STACK_PRIVATE_BLOCK_EARLY, /**< private block for single statements (force early declarations) */ @@ -115,6 +118,20 @@ typedef enum #endif /* ENABLED (JERRY_ES2015) */ } scan_stack_modes_t; +/** + * Scanner context flag types. + */ +typedef enum +{ + SCANNER_CONTEXT_NO_FLAGS = 0, /**< no flags are set */ +#if ENABLED (JERRY_ES2015) + SCANNER_CONTEXT_THROW_ERR_ASYNC_FUNCTION = (1 << 0), /**< throw async function error */ +#endif /* ENABLED (JERRY_ES2015) */ +#if ENABLED (JERRY_DEBUGGER) + SCANNER_CONTEXT_DEBUGGER_ENABLED = (1 << 1), /**< debugger is enabled */ +#endif /* ENABLED (JERRY_DEBUGGER) */ +} scanner_context_flags_t; + /** * Checks whether the stack top is a for statement start. */ @@ -269,6 +286,7 @@ typedef enum SCANNER_LITERAL_POOL_FUNCTION_STATEMENT = (1 << 8), /**< function statement */ SCANNER_LITERAL_POOL_GENERATOR = (1 << 9), /**< generator function */ SCANNER_LITERAL_POOL_ASYNC = (1 << 10), /**< async function */ + SCANNER_LITERAL_POOL_ASYNC_ARROW = (1 << 11), /**< can be an async arrow function */ #endif /* ENABLED (JERRY_ES2015) */ } scanner_literal_pool_flags_t; @@ -278,6 +296,18 @@ typedef enum #define SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS \ (SCANNER_LITERAL_POOL_FUNCTION | SCANNER_LITERAL_POOL_NO_ARGUMENTS) +/** + * Getting the generator and async properties of literal pool status flags. + */ +#define SCANNER_FROM_LITERAL_POOL_TO_COMPUTED(status_flags) \ + ((uint8_t) ((((status_flags) >> 9) & 0x3) + SCAN_STACK_COMPUTED_PROPERTY)) + +/** + * Setting the generator and async properties of literal pool status flags. + */ +#define SCANNER_FROM_COMPUTED_TO_LITERAL_POOL(mode) \ + (((mode) - SCAN_STACK_COMPUTED_PROPERTY) << 9) + /** * Local literal pool. */ @@ -297,11 +327,11 @@ struct scanner_context_t { uint32_t context_status_flags; /**< original status flags of the context */ uint8_t mode; /**< scanner mode */ -#if ENABLED (JERRY_DEBUGGER) - uint8_t debugger_enabled; /**< debugger is enabled */ -#endif /* ENABLED (JERRY_DEBUGGER) */ #if ENABLED (JERRY_ES2015) uint8_t binding_type; /**< current destructuring binding type */ +#endif /* ENABLED (JERRY_ES2015) */ + uint16_t status_flags; /**< scanner status flags */ +#if ENABLED (JERRY_ES2015) scanner_binding_list_t *active_binding_list_p; /**< currently active binding list */ #endif /* ENABLED (JERRY_ES2015) */ scanner_literal_pool_t *active_literal_pool_p; /**< currently active literal pool */ diff --git a/jerry-core/parser/js/js-scanner-ops.c b/jerry-core/parser/js/js-scanner-ops.c index 5caa26489..0270d0120 100644 --- a/jerry-core/parser/js/js-scanner-ops.c +++ b/jerry-core/parser/js/js-scanner-ops.c @@ -108,14 +108,24 @@ scanner_check_arrow (parser_context_t *context_p, /**< context */ } scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p; + uint16_t status_flags = literal_pool_p->status_flags; - literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS; - literal_pool_p->status_flags &= (uint16_t) ~(SCANNER_LITERAL_POOL_IN_WITH | SCANNER_LITERAL_POOL_GENERATOR); + status_flags |= SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS; + status_flags &= (uint16_t) ~(SCANNER_LITERAL_POOL_IN_WITH + | SCANNER_LITERAL_POOL_GENERATOR + | SCANNER_LITERAL_POOL_ASYNC); - context_p->status_flags &= (uint32_t) ~PARSER_IS_GENERATOR_FUNCTION; + context_p->status_flags &= (uint32_t) ~(PARSER_IS_GENERATOR_FUNCTION | PARSER_IS_ASYNC_FUNCTION); + + if (status_flags & SCANNER_LITERAL_POOL_ASYNC_ARROW) + { + status_flags |= SCANNER_LITERAL_POOL_ASYNC; + context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION; + } + + literal_pool_p->status_flags = status_flags; scanner_filter_arguments (context_p, scanner_context_p); - scanner_check_arrow_body (context_p, scanner_context_p); } /* scanner_check_arrow */ @@ -127,10 +137,19 @@ scanner_scan_simple_arrow (parser_context_t *context_p, /**< context */ scanner_context_t *scanner_context_p, /**< scanner context */ const uint8_t *source_p) /**< identifier end position */ { - scanner_literal_pool_t *literal_pool_p; - literal_pool_p = scanner_push_literal_pool (context_p, - scanner_context_p, - SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS); + uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS; + + context_p->status_flags &= (uint32_t) ~(PARSER_IS_GENERATOR_FUNCTION | PARSER_IS_ASYNC_FUNCTION); + + if (scanner_context_p->async_source_p != NULL) + { + JERRY_ASSERT (scanner_context_p->async_source_p == source_p); + + status_flags |= SCANNER_LITERAL_POOL_ASYNC; + context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION; + } + + scanner_literal_pool_t *literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, status_flags); literal_pool_p->source_p = source_p; lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p); @@ -141,8 +160,6 @@ scanner_scan_simple_arrow (parser_context_t *context_p, /**< context */ PARSER_PLUS_EQUAL_LC (context_p->column, 2); context_p->token.flags = (uint8_t) (context_p->token.flags & ~LEXER_NO_SKIP_SPACES); - context_p->status_flags &= (uint32_t) ~PARSER_IS_GENERATOR_FUNCTION; - scanner_check_arrow_body (context_p, scanner_context_p); } /* scanner_scan_simple_arrow */ @@ -266,7 +283,6 @@ scanner_check_async_function (parser_context_t *context_p, /**< context */ } scanner_scan_simple_arrow (context_p, scanner_context_p, scanner_context_p->async_source_p); - scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ASYNC; scanner_context_p->async_source_p = NULL; return false; } @@ -475,7 +491,7 @@ scanner_scan_bracket (parser_context_t *context_p, /**< context */ if (JERRY_UNLIKELY (scanner_context_p->async_source_p != NULL)) { - status_flags |= SCANNER_LITERAL_POOL_ASYNC; + status_flags |= SCANNER_LITERAL_POOL_ASYNC_ARROW; arrow_source_p = scanner_context_p->async_source_p; scanner_context_p->async_source_p = NULL; } diff --git a/jerry-core/parser/js/js-scanner-util.c b/jerry-core/parser/js/js-scanner-util.c index 521bee3a3..f2d623563 100644 --- a/jerry-core/parser/js/js-scanner-util.c +++ b/jerry-core/parser/js/js-scanner-util.c @@ -76,7 +76,7 @@ scanner_raise_error (parser_context_t *context_p) /**< context */ * Raise a variable redeclaration error. */ void -scanner_raise_redeclaration_error (parser_context_t *context_p) +scanner_raise_redeclaration_error (parser_context_t *context_p) /**< context */ { scanner_info_t *info_p = scanner_insert_info (context_p, context_p->source_p, sizeof (scanner_info_t)); info_p->type = SCANNER_TYPE_ERR_REDECLARED; @@ -403,13 +403,31 @@ scanner_push_literal_pool (parser_context_t *context_p, /**< context */ status_flags |= SCANNER_LITERAL_POOL_NO_ARGUMENTS; #if ENABLED (JERRY_ES2015) - const uint16_t copied_flags = SCANNER_LITERAL_POOL_IN_WITH | SCANNER_LITERAL_POOL_GENERATOR; + const uint16_t copied_flags = (SCANNER_LITERAL_POOL_IN_WITH + | SCANNER_LITERAL_POOL_GENERATOR + | SCANNER_LITERAL_POOL_ASYNC); #else /* !ENABLED (JERRY_ES2015) */ const uint16_t copied_flags = SCANNER_LITERAL_POOL_IN_WITH; #endif /* ENABLED (JERRY_ES2015) */ status_flags |= (uint16_t) (prev_literal_pool_p->status_flags & copied_flags); } +#if ENABLED (JERRY_ES2015) + else + { + context_p->status_flags &= (uint32_t) ~(PARSER_IS_GENERATOR_FUNCTION | PARSER_IS_ASYNC_FUNCTION); + + if (status_flags & SCANNER_LITERAL_POOL_GENERATOR) + { + context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION; + } + + if (status_flags & SCANNER_LITERAL_POOL_ASYNC) + { + context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION; + } + } +#endif /* ENABLED (JERRY_ES2015) */ if (prev_literal_pool_p != NULL) { @@ -486,7 +504,7 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ } #if ENABLED (JERRY_DEBUGGER) - if (scanner_context_p->debugger_enabled) + if (scanner_context_p->status_flags & SCANNER_CONTEXT_DEBUGGER_ENABLED) { /* When debugger is enabled, identifiers are not stored in registers. However, * this does not affect 'eval' detection, so 'arguments' object is not created. */ @@ -899,6 +917,15 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ { context_p->status_flags &= (uint32_t) ~PARSER_IS_GENERATOR_FUNCTION; } + + if (prev_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_ASYNC) + { + context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION; + } + else + { + context_p->status_flags &= (uint32_t) ~PARSER_IS_ASYNC_FUNCTION; + } #endif /* ENABLED (JERRY_ES2015) */ } @@ -1611,7 +1638,8 @@ scanner_cleanup (parser_context_t *context_p) /**< context */ JERRY_ASSERT (scanner_info_p->type == SCANNER_TYPE_END_ARGUMENTS || scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION || scanner_info_p->type == SCANNER_TYPE_CLASS_CONSTRUCTOR - || scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED); + || scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED + || scanner_info_p->type == SCANNER_TYPE_ERR_ASYNC_FUNCTION); #else /* !ENABLED (JERRY_ES2015) */ JERRY_ASSERT (scanner_info_p->type == SCANNER_TYPE_END_ARGUMENTS); #endif /* ENABLED (JERRY_ES2015) */ diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index 38866f59c..45f643423 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -50,12 +50,19 @@ typedef enum #if ENABLED (JERRY_ES2015) -/** - * Returns the correct computed property mode based on the literal_pool_flags. - */ -#define GET_COMPUTED_PROPERTY_MODE(literal_pool_flags) \ - (((literal_pool_flags) & SCANNER_LITERAL_POOL_GENERATOR) ? SCAN_STACK_COMPUTED_GENERATOR_FUNCTION \ - : SCAN_STACK_COMPUTED_PROPERTY) +JERRY_STATIC_ASSERT (SCANNER_FROM_LITERAL_POOL_TO_COMPUTED (SCANNER_LITERAL_POOL_GENERATOR) + == SCAN_STACK_COMPUTED_GENERATOR, + scanner_invalid_conversion_from_literal_pool_generator_to_computed_generator); +JERRY_STATIC_ASSERT (SCANNER_FROM_LITERAL_POOL_TO_COMPUTED (SCANNER_LITERAL_POOL_ASYNC) + == SCAN_STACK_COMPUTED_ASYNC, + scanner_invalid_conversion_from_literal_pool_async_to_computed_async); + +JERRY_STATIC_ASSERT (SCANNER_FROM_COMPUTED_TO_LITERAL_POOL (SCAN_STACK_COMPUTED_GENERATOR) + == SCANNER_LITERAL_POOL_GENERATOR, + scanner_invalid_conversion_from_computed_generator_to_literal_pool_generator); +JERRY_STATIC_ASSERT (SCANNER_FROM_COMPUTED_TO_LITERAL_POOL (SCAN_STACK_COMPUTED_ASYNC) + == SCANNER_LITERAL_POOL_ASYNC, + scanner_invalid_conversion_from_computed_async_to_literal_pool_async); #endif /* ENABLED (JERRY_ES2015) */ @@ -93,23 +100,24 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ } case LEXER_KEYW_FUNCTION: { - scanner_push_literal_pool (context_p, scanner_context_p, SCANNER_LITERAL_POOL_FUNCTION); + uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION; #if ENABLED (JERRY_ES2015) - context_p->status_flags &= (uint32_t) ~PARSER_IS_GENERATOR_FUNCTION; -#endif /* ENABLED (JERRY_ES2015) */ - - lexer_next_token (context_p); - -#if ENABLED (JERRY_ES2015) - if (context_p->token.type == LEXER_MULTIPLY) + if (scanner_context_p->async_source_p != NULL) { - scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_GENERATOR; - context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION; - lexer_next_token (context_p); + status_flags |= SCANNER_LITERAL_POOL_ASYNC; + } + + if (lexer_consume_generator (context_p)) + { + status_flags |= SCANNER_LITERAL_POOL_GENERATOR; } #endif /* ENABLED (JERRY_ES2015) */ + scanner_push_literal_pool (context_p, scanner_context_p, status_flags); + + lexer_next_token (context_p); + if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) { @@ -957,7 +965,9 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * } return SCAN_NEXT_TOKEN; } - case SCAN_STACK_COMPUTED_GENERATOR_FUNCTION: + case SCAN_STACK_COMPUTED_GENERATOR: + case SCAN_STACK_COMPUTED_ASYNC: + case SCAN_STACK_COMPUTED_ASYNC_GENERATOR: { if (type != LEXER_RIGHT_SQUARE) { @@ -970,10 +980,11 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL || context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_PROPERTY); - scanner_push_literal_pool (context_p, - scanner_context_p, - SCANNER_LITERAL_POOL_FUNCTION | SCANNER_LITERAL_POOL_GENERATOR); - context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION; + uint16_t status_flags = (uint16_t) (SCANNER_LITERAL_POOL_FUNCTION + | SCANNER_LITERAL_POOL_GENERATOR + | SCANNER_FROM_COMPUTED_TO_LITERAL_POOL (stack_top)); + + scanner_push_literal_pool (context_p, scanner_context_p, status_flags); scanner_context_p->mode = SCAN_MODE_FUNCTION_ARGUMENTS; return SCAN_KEEP_TOKEN; @@ -1015,6 +1026,7 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * { scanner_pop_literal_pool (context_p, scanner_context_p); parser_stack_pop_uint8 (context_p); + lexer_update_await_yield (context_p, context_p->status_flags); scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END; return SCAN_KEEP_TOKEN; } @@ -1358,24 +1370,24 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ } case LEXER_KEYW_FUNCTION: { - lexer_next_token (context_p); - #if ENABLED (JERRY_ES2015) uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION | SCANNER_LITERAL_POOL_FUNCTION_STATEMENT; + if (scanner_context_p->async_source_p != NULL) + { + scanner_context_p->status_flags |= SCANNER_CONTEXT_THROW_ERR_ASYNC_FUNCTION; + status_flags |= SCANNER_LITERAL_POOL_ASYNC; + } +#endif /* ENABLED (JERRY_ES2015) */ + + lexer_next_token (context_p); + +#if ENABLED (JERRY_ES2015) if (context_p->token.type == LEXER_MULTIPLY) { status_flags |= SCANNER_LITERAL_POOL_GENERATOR; lexer_next_token (context_p); - /* This flag should be set after the function name is read. */ - context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION; } - else - { - context_p->status_flags &= (uint32_t) ~PARSER_IS_GENERATOR_FUNCTION; - } -#else /* !ENABLED (JERRY_ES2015) */ - uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION; #endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type != LEXER_LITERAL @@ -1397,8 +1409,12 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ } literal_p->type |= SCANNER_LITERAL_IS_FUNC | SCANNER_LITERAL_IS_FUNC_DECLARATION; + + scanner_context_p->status_flags &= (uint16_t) ~SCANNER_CONTEXT_THROW_ERR_ASYNC_FUNCTION; #else literal_p->type |= SCANNER_LITERAL_IS_VAR | SCANNER_LITERAL_IS_FUNC; + + uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION; #endif /* ENABLED (JERRY_ES2015) */ scanner_push_literal_pool (context_p, scanner_context_p, status_flags); @@ -2254,8 +2270,12 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ #endif /* ENABLED (JERRY_PARSER_DUMP_BYTE_CODE) */ scanner_context.context_status_flags = context_p->status_flags; + scanner_context.status_flags = SCANNER_CONTEXT_NO_FLAGS; #if ENABLED (JERRY_DEBUGGER) - scanner_context.debugger_enabled = (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) ? 1 : 0; + if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) + { + scanner_context.status_flags |= SCANNER_CONTEXT_DEBUGGER_ENABLED; + } #endif /* ENABLED (JERRY_DEBUGGER) */ #if ENABLED (JERRY_ES2015) scanner_context.binding_type = SCANNER_BINDING_NONE; @@ -2310,6 +2330,13 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ status_flags |= SCANNER_LITERAL_POOL_IS_STRICT; } +#if ENABLED (JERRY_ES2015) + if (context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION) + { + status_flags |= SCANNER_LITERAL_POOL_GENERATOR; + } +#endif /* ENABLED (JERRY_ES2015) */ + scanner_push_literal_pool (context_p, &scanner_context, status_flags); scanner_context.mode = SCAN_MODE_FUNCTION_ARGUMENTS; parser_stack_push_uint8 (context_p, SCAN_STACK_SCRIPT_FUNCTION); @@ -2459,7 +2486,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ if (context_p->token.type == LEXER_LEFT_SQUARE) { - parser_stack_push_uint8 (context_p, GET_COMPUTED_PROPERTY_MODE (literal_pool_flags)); + parser_stack_push_uint8 (context_p, SCANNER_FROM_LITERAL_POOL_TO_COMPUTED (literal_pool_flags)); scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; break; } @@ -2889,15 +2916,10 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ #if ENABLED (JERRY_ES2015) if (context_p->token.type == LEXER_LEFT_SQUARE) { - parser_stack_push_uint8 (context_p, GET_COMPUTED_PROPERTY_MODE (literal_pool_flags)); + parser_stack_push_uint8 (context_p, SCANNER_FROM_LITERAL_POOL_TO_COMPUTED (literal_pool_flags)); scanner_context.mode = SCAN_MODE_PRIMARY_EXPRESSION; break; } - - if (literal_pool_flags & SCANNER_LITERAL_POOL_GENERATOR) - { - context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION; - } #endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type != LEXER_LITERAL) @@ -3150,9 +3172,20 @@ scan_completed: } #endif /* ENABLED (JERRY_ES2015) */ - /* The following loop may allocate memory, so it is enclosed in a try/catch. */ + /* The following code may allocate memory, so it is enclosed in a try/catch. */ PARSER_TRY (context_p->try_buffer) { +#if ENABLED (JERRY_ES2015) + if (scanner_context.status_flags & SCANNER_CONTEXT_THROW_ERR_ASYNC_FUNCTION) + { + JERRY_ASSERT (scanner_context.async_source_p != NULL); + + scanner_info_t *info_p; + info_p = scanner_insert_info (context_p, scanner_context.async_source_p, sizeof (scanner_info_t)); + info_p->type = SCANNER_TYPE_ERR_ASYNC_FUNCTION; + } +#endif /* ENABLED (JERRY_ES2015) */ + while (scanner_context.active_literal_pool_p != NULL) { scanner_pop_literal_pool (context_p, &scanner_context); @@ -3426,6 +3459,12 @@ scan_completed: (int) (info_p->source_p - source_start_p)); break; } + case SCANNER_TYPE_ERR_ASYNC_FUNCTION: + { + JERRY_DEBUG_MSG (" ERR_ASYNC_FUNCTION: source:%d\n", + (int) (info_p->source_p - source_start_p)); + break; + } #endif /* ENABLED (JERRY_ES2015) */ } diff --git a/jerry-core/parser/js/js-scanner.h b/jerry-core/parser/js/js-scanner.h index db1186978..675d3a75b 100644 --- a/jerry-core/parser/js/js-scanner.h +++ b/jerry-core/parser/js/js-scanner.h @@ -49,6 +49,7 @@ typedef enum SCANNER_TYPE_CLASS_CONSTRUCTOR, /**< class constructor */ SCANNER_TYPE_LET_EXPRESSION, /**< let expression */ SCANNER_TYPE_ERR_REDECLARED, /**< syntax error: a variable is redeclared */ + SCANNER_TYPE_ERR_ASYNC_FUNCTION, /**< an invalid async function follows */ #endif /* ENABLED (JERRY_ES2015) */ } scanner_info_type_t; diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 33315920c..05e43dc81 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -1990,8 +1990,12 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { frame_ctx_p->call_operation = VM_EXEC_RETURN; frame_ctx_p->byte_code_p = byte_code_p; - frame_ctx_p->stack_top_p = stack_top_p; - return left_value; + frame_ctx_p->stack_top_p = --stack_top_p; + return *stack_top_p; + } + case VM_OC_AWAIT: + { + continue; } case VM_OC_EXT_RETURN: { diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index 6cf42f89a..a47ade919 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -265,6 +265,7 @@ typedef enum VM_OC_SPREAD_ARGUMENTS, /**< perform function call/construct with spreaded arguments */ VM_OC_CREATE_GENERATOR, /**< create a generator object */ VM_OC_YIELD, /**< yield operation */ + VM_OC_AWAIT, /**< await operation */ VM_OC_EXT_RETURN, /**< return which also clears the stack */ VM_OC_RETURN_PROMISE, /**< return from an async function */ VM_OC_STRING_CONCAT, /**< string concatenation */ @@ -329,6 +330,7 @@ typedef enum VM_OC_SPREAD_ARGUMENTS = VM_OC_NONE, /**< perform function call/construct with spreaded arguments */ VM_OC_CREATE_GENERATOR = VM_OC_NONE, /**< create a generator object */ VM_OC_YIELD = VM_OC_NONE, /**< yield operation */ + VM_OC_AWAIT = VM_OC_NONE, /**< await operation */ VM_OC_EXT_RETURN = VM_OC_NONE, /**< return which also clears the stack */ VM_OC_RETURN_PROMISE = VM_OC_NONE, /**< return from an async function */ VM_OC_STRING_CONCAT = VM_OC_NONE, /**< string concatenation */ diff --git a/tests/jerry/es2015/function-await1.js b/tests/jerry/es2015/function-await1.js new file mode 100644 index 000000000..e616b0571 --- /dev/null +++ b/tests/jerry/es2015/function-await1.js @@ -0,0 +1,138 @@ +// 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. + +/* This test checks await expressions (nothing else). */ + +function check_syntax_error (code) +{ + try { + eval (code) + assert (false) + } catch (e) { + assert (e instanceof SyntaxError) + } +} + +check_syntax_error("(async function await() {})") +check_syntax_error("(async function *await() {})") +check_syntax_error("async function f(await) {}") +check_syntax_error("(async function f(await) {})") +check_syntax_error("async function f(a = await new Promise) {}") +check_syntax_error("async function f() { function await() {} }") +check_syntax_error("async await => 0"); +check_syntax_error("async (await) => 0"); +check_syntax_error("async function f() { await () => 0 }"); +check_syntax_error("async (a) => a\\u0077ait a"); +check_syntax_error("async (a) => { () => 0\na\\u0077ait a }"); + +// Valid uses of await + +async a => await a +async a => { await a } +async (a) => await a +async(a) => { await a } + +// Nested async and non-async functions + +async (a) => { + () => await + await a +} + +(a) => { + await + async (a) => await a + await + async (a) => await a + a\u0077ait +} + +async function f1(a) { + await a + (function () { await ? async function(a) { await a } : await }) + await a +} + +async (a) => { + await a; + () => await ? async (a) => await a : await + await a +} + +async (a) => { + (a = () => await, [b] = (c)) + await a + (a, b = () => await) + await a +} + +// Object initializers + +var o = { + async await(a) { + await a; + () => await + await a + }, + + f(a) { + await + async (a) => await a + await + async (a) => await a + a\u0077ait + }, + + async ["g"] () { + await a; + () => await + await a + } +} + +async function f2(a) { + var o = { + [await a]() { await % await } + } + await a; +} + +class C { + async await(a) { + await a; + () => await + await a + } + + f(a) { + await + async (a) => await a + await + async (a) => await a + a\u0077ait + } + + async ["g"] () { + await a; + () => await + await a + } +} + +async function f3(a) { + class C { + [await a]() { await % await } + } + await a; +} diff --git a/tests/jerry/es2015/generator-function.js b/tests/jerry/es2015/generator-function.js index 0342dc41e..16cff4caf 100644 --- a/tests/jerry/es2015/generator-function.js +++ b/tests/jerry/es2015/generator-function.js @@ -43,7 +43,7 @@ // Test %GeneratorPrototype% prototype chain (function () { function* g(){} - var iterator = new g.constructor("a","b","c","yield a; yield b; yield c;")(1,2,3); + var iterator = new g.constructor("a","b","c","() => yield\n yield a; yield b; yield c;")(1,2,3); var item = iterator.next(); assert(item.value === 1); diff --git a/tests/jerry/es2015/generator-yield.js b/tests/jerry/es2015/generator-yield.js index 3c1dd53cd..7fd70c481 100644 --- a/tests/jerry/es2015/generator-yield.js +++ b/tests/jerry/es2015/generator-yield.js @@ -58,6 +58,7 @@ check_syntax_error("function *gen(){ (yield\n1) }"); check_syntax_error("function *gen(){ function yield() {} }"); check_syntax_error("function *gen(){ (yield)=>1 }"); check_syntax_error("function *gen(){ yield => 1 }"); +check_syntax_error("function *gen(){ yi\\u0065ld 1 }"); function *gen4() { var f = function yield(i) { @@ -71,3 +72,15 @@ function *gen4() { } assert(gen4().next().value === 39); + +(function *() { + () => yield + yield 1; +}) + +function *gen5() { + var o = { + ["f"]() { yield % yield } + } + yield 1; +} diff --git a/tests/unit-core/test-snapshot.c b/tests/unit-core/test-snapshot.c index 28c5d9eb0..8c1a39ed0 100644 --- a/tests/unit-core/test-snapshot.c +++ b/tests/unit-core/test-snapshot.c @@ -223,7 +223,7 @@ main (void) /* Check the snapshot data. Unused bytes should be filled with zeroes */ const uint8_t expected_data[] = { - 0x4A, 0x52, 0x52, 0x59, 0x2B, 0x00, 0x00, 0x00, + 0x4A, 0x52, 0x52, 0x59, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x41, 0x00, 0x01, 0x00,