diff --git a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c index ae3381fcc..367179678 100644 --- a/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c +++ b/jerry-core/ecma/builtin-objects/ecma-builtin-promise.c @@ -42,83 +42,6 @@ * @{ */ -/** - * The common function for 'reject' and 'resolve'. - * - * @return ecma value - * Returned value must be freed with ecma_free_value. - */ -static ecma_value_t -ecma_builtin_promise_reject_or_resolve (ecma_value_t this_arg, /**< "this" argument */ - ecma_value_t argument, /**< argument for reject or resolve */ - bool is_resolve) /**< whether it is for resolve routine */ -{ - if (!ecma_is_value_object (this_arg)) - { - return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object.")); - } - - if (is_resolve - && ecma_is_value_object (argument) - && ecma_is_promise (ecma_get_object_from_value (argument))) - { - ecma_object_t *ctor_obj_p = ecma_get_object_from_value (argument); - ecma_value_t x_ctor = ecma_op_object_get_by_magic_id (ctor_obj_p, LIT_MAGIC_STRING_CONSTRUCTOR); - if (ECMA_IS_VALUE_ERROR (x_ctor)) - { - return x_ctor; - } - - bool is_same_value = ecma_op_same_value (x_ctor, this_arg); - ecma_free_value (x_ctor); - if (is_same_value) - { - return ecma_copy_value (argument); - } - } - - - ecma_value_t capability = ecma_promise_new_capability (this_arg); - - if (ECMA_IS_VALUE_ERROR (capability)) - { - return capability; - } - - ecma_string_t *property_str_p; - - if (is_resolve) - { - property_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); - } - else - { - property_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); - } - - ecma_value_t func = ecma_op_object_get (ecma_get_object_from_value (capability), property_str_p); - - ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (func), - ECMA_VALUE_UNDEFINED, - &argument, - 1); - - ecma_free_value (func); - - if (ECMA_IS_VALUE_ERROR (call_ret)) - { - return call_ret; - } - - ecma_free_value (call_ret); - - ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); - ecma_value_t promise_new = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p); - ecma_free_value (capability); - - return promise_new; -} /* ecma_builtin_promise_reject_or_resolve */ - /** * Reject the promise if the value is error. * @@ -169,7 +92,7 @@ static ecma_value_t ecma_builtin_promise_reject (ecma_value_t this_arg, /**< 'this' argument */ ecma_value_t reason) /**< the reason for reject */ { - return ecma_builtin_promise_reject_or_resolve (this_arg, reason, false); + return ecma_promise_reject_or_resolve (this_arg, reason, false); } /* ecma_builtin_promise_reject */ /** @@ -185,7 +108,7 @@ static ecma_value_t ecma_builtin_promise_resolve (ecma_value_t this_arg, /**< 'this' argument */ ecma_value_t argument) /**< the argument for resolve */ { - return ecma_builtin_promise_reject_or_resolve (this_arg, argument, true); + return ecma_promise_reject_or_resolve (this_arg, argument, true); } /* ecma_builtin_promise_resolve */ /** diff --git a/jerry-core/ecma/operations/ecma-promise-object.c b/jerry-core/ecma/operations/ecma-promise-object.c index 1f5c86520..bed155711 100644 --- a/jerry-core/ecma/operations/ecma-promise-object.c +++ b/jerry-core/ecma/operations/ecma-promise-object.c @@ -720,6 +720,85 @@ ecma_promise_new_capability (ecma_value_t constructor) return ecma_make_object_value (capability_p); } /* ecma_promise_new_capability */ +/** + * The common function for 'reject' and 'resolve'. + * + * @return ecma value + * Returned value must be freed with ecma_free_value. + */ +ecma_value_t +ecma_promise_reject_or_resolve (ecma_value_t this_arg, /**< "this" argument */ + ecma_value_t value, /**< rejected or resolved value */ + bool is_resolve) /**< the operation is resolve */ +{ + if (!ecma_is_value_object (this_arg)) + { + return ecma_raise_type_error (ECMA_ERR_MSG ("'this' is not an object.")); + } + + if (is_resolve + && ecma_is_value_object (value) + && ecma_is_promise (ecma_get_object_from_value (value))) + { + ecma_object_t *object_p = ecma_get_object_from_value (value); + ecma_value_t constructor = ecma_op_object_get_by_magic_id (object_p, LIT_MAGIC_STRING_CONSTRUCTOR); + + if (ECMA_IS_VALUE_ERROR (constructor)) + { + return constructor; + } + + /* The this_arg must be an object. */ + bool is_same_value = (constructor == this_arg); + ecma_free_value (constructor); + + if (is_same_value) + { + return ecma_copy_value (value); + } + } + + ecma_value_t capability = ecma_promise_new_capability (this_arg); + + if (ECMA_IS_VALUE_ERROR (capability)) + { + return capability; + } + + ecma_string_t *property_str_p; + + if (is_resolve) + { + property_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_RESOLVE); + } + else + { + property_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_REJECT); + } + + ecma_value_t func = ecma_op_object_get (ecma_get_object_from_value (capability), property_str_p); + + ecma_value_t call_ret = ecma_op_function_call (ecma_get_object_from_value (func), + ECMA_VALUE_UNDEFINED, + &value, + 1); + + ecma_free_value (func); + + if (ECMA_IS_VALUE_ERROR (call_ret)) + { + return call_ret; + } + + ecma_free_value (call_ret); + + ecma_string_t *promise_str_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_PROMISE_PROPERTY_PROMISE); + ecma_value_t promise = ecma_op_object_get (ecma_get_object_from_value (capability), promise_str_p); + ecma_free_value (capability); + + return promise; +} /* ecma_promise_reject_or_resolve */ + /** * It performs the "then" operation on promiFulfilled * and onRejected as its settlement actions. diff --git a/jerry-core/ecma/operations/ecma-promise-object.h b/jerry-core/ecma/operations/ecma-promise-object.h index d39cdce72..09b9bd3a7 100644 --- a/jerry-core/ecma/operations/ecma-promise-object.h +++ b/jerry-core/ecma/operations/ecma-promise-object.h @@ -69,17 +69,13 @@ typedef struct } ecma_promise_object_t; bool ecma_is_promise (ecma_object_t *obj_p); -ecma_value_t -ecma_op_create_promise_object (ecma_value_t executor, ecma_promise_executor_type_t type); +ecma_value_t ecma_op_create_promise_object (ecma_value_t executor, ecma_promise_executor_type_t type); uint8_t ecma_promise_get_state (ecma_object_t *promise_p); ecma_value_t ecma_promise_get_result (ecma_object_t *promise_p); ecma_value_t ecma_promise_new_capability (ecma_value_t constructor); -ecma_value_t -ecma_promise_then (ecma_value_t promise, - ecma_value_t on_fulfilled, - ecma_value_t on_rejected); -ecma_promise_resolving_functions_t * -ecma_promise_create_resolving_functions (ecma_object_t *object_p); +ecma_value_t ecma_promise_reject_or_resolve (ecma_value_t this_arg, ecma_value_t value, bool is_resolve); +ecma_value_t ecma_promise_then (ecma_value_t promise, ecma_value_t on_fulfilled, ecma_value_t on_rejected); +ecma_promise_resolving_functions_t *ecma_promise_create_resolving_functions (ecma_object_t *object_p); void ecma_promise_free_resolving_functions (ecma_promise_resolving_functions_t *funcs); /** diff --git a/jerry-core/include/jerryscript-snapshot.h b/jerry-core/include/jerryscript-snapshot.h index f79ddadbe..b25a5955c 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 (35u) +#define JERRY_SNAPSHOT_VERSION (36u) /** * 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 a2919b23c..fdd181928 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -550,6 +550,14 @@ 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_STRING_CONCAT, CBC_NO_FLAG, -1, \ + VM_OC_STRING_CONCAT | VM_OC_GET_STACK_STACK | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_STRING_CONCAT_RIGHT_LITERAL, CBC_HAS_LITERAL_ARG, 0, \ + VM_OC_STRING_CONCAT | VM_OC_GET_STACK_LITERAL | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_STRING_CONCAT_TWO_LITERALS, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 1, \ + 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, \ @@ -558,6 +566,12 @@ VM_OC_RESOURCE_NAME) \ CBC_OPCODE (CBC_EXT_LINE, CBC_NO_FLAG, 0, \ VM_OC_LINE) \ + CBC_OPCODE (CBC_EXT_ERROR, CBC_NO_FLAG, 0, \ + VM_OC_ERROR) \ + CBC_OPCODE (CBC_EXT_THROW_REFERENCE_ERROR, CBC_NO_FLAG, 1, \ + VM_OC_THROW_REFERENCE_ERROR) \ + \ + /* Computed / class property related opcodes. */ \ CBC_OPCODE (CBC_EXT_SET_COMPUTED_PROPERTY, CBC_NO_FLAG, -2, \ VM_OC_SET_COMPUTED_PROPERTY | VM_OC_NON_STATIC_FLAG | VM_OC_GET_STACK_STACK) \ CBC_OPCODE (CBC_EXT_SET_COMPUTED_PROPERTY_LITERAL, CBC_HAS_LITERAL_ARG, -1, \ @@ -578,10 +592,8 @@ VM_OC_SET_GETTER | VM_OC_GET_STACK_LITERAL) \ CBC_OPCODE (CBC_EXT_SET_STATIC_COMPUTED_SETTER, CBC_HAS_LITERAL_ARG, -1, \ VM_OC_SET_SETTER | VM_OC_GET_STACK_LITERAL) \ - CBC_OPCODE (CBC_EXT_THROW_REFERENCE_ERROR, CBC_NO_FLAG, 1, \ - VM_OC_THROW_REFERENCE_ERROR) \ \ - /* Class opcodes */ \ + /* Class related opcodes. */ \ CBC_OPCODE (CBC_EXT_INHERIT_AND_SET_CONSTRUCTOR, CBC_NO_FLAG, 0, \ VM_OC_CLASS_INHERITANCE) \ CBC_OPCODE (CBC_EXT_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE, CBC_NO_FLAG, 2, \ @@ -632,20 +644,12 @@ VM_OC_SUPER_PROP_REFERENCE) \ CBC_OPCODE (CBC_EXT_CONSTRUCTOR_RETURN, CBC_NO_FLAG, -1, \ VM_OC_CONSTRUCTOR_RET | VM_OC_GET_STACK) \ - CBC_OPCODE (CBC_EXT_ERROR, CBC_NO_FLAG, 0, \ - VM_OC_ERROR) \ + \ + /* Spread / rest operation related opcodes. */ \ CBC_OPCODE (CBC_EXT_PUSH_SPREAD_ELEMENT, CBC_NO_FLAG, 1, \ VM_OC_PUSH_SPREAD_ELEMENT) \ CBC_OPCODE (CBC_EXT_SPREAD_ARRAY_APPEND, CBC_HAS_POP_STACK_BYTE_ARG, 0, \ VM_OC_APPEND_ARRAY) \ - CBC_OPCODE (CBC_EXT_GET_ITERATOR, CBC_NO_FLAG, 1, \ - VM_OC_GET_ITERATOR) \ - CBC_OPCODE (CBC_EXT_ITERATOR_STEP, CBC_NO_FLAG, 1, \ - VM_OC_ITERATOR_STEP) \ - CBC_OPCODE (CBC_EXT_ITERATOR_STEP_PROP, CBC_NO_FLAG, 1, \ - VM_OC_ITERATOR_STEP) \ - CBC_OPCODE (CBC_EXT_ITERATOR_CLOSE, CBC_NO_FLAG, -1, \ - VM_OC_ITERATOR_CLOSE | VM_OC_GET_STACK) \ CBC_OPCODE (CBC_EXT_REST_INITIALIZER, CBC_NO_FLAG, 1, \ VM_OC_REST_INITIALIZER) \ CBC_OPCODE (CBC_EXT_REST_INITIALIZER_PROP, CBC_NO_FLAG, 1, \ @@ -654,6 +658,18 @@ VM_OC_INITIALIZER_PUSH_PROP | VM_OC_GET_LITERAL) \ CBC_OPCODE (CBC_EXT_SPREAD_NEW, CBC_HAS_POP_STACK_BYTE_ARG, 0, \ VM_OC_SPREAD_ARGUMENTS | VM_OC_PUT_STACK) \ + \ + /* Iterator related opcodes. */ \ + CBC_OPCODE (CBC_EXT_GET_ITERATOR, CBC_NO_FLAG, 1, \ + VM_OC_GET_ITERATOR) \ + CBC_OPCODE (CBC_EXT_ITERATOR_STEP, CBC_NO_FLAG, 1, \ + VM_OC_ITERATOR_STEP) \ + CBC_OPCODE (CBC_EXT_ITERATOR_STEP_PROP, CBC_NO_FLAG, 1, \ + VM_OC_ITERATOR_STEP) \ + CBC_OPCODE (CBC_EXT_ITERATOR_CLOSE, CBC_NO_FLAG, -1, \ + VM_OC_ITERATOR_CLOSE | VM_OC_GET_STACK) \ + \ + /* Executable object related opcodes. */ \ CBC_OPCODE (CBC_EXT_CREATE_GENERATOR, CBC_NO_FLAG, 1, \ VM_OC_CREATE_GENERATOR) \ CBC_OPCODE (CBC_EXT_YIELD, CBC_NO_FLAG, 0, \ @@ -662,14 +678,8 @@ VM_OC_YIELD | VM_OC_GET_STACK) \ CBC_OPCODE (CBC_EXT_RETURN, CBC_NO_FLAG, -1, \ VM_OC_EXT_RETURN | VM_OC_GET_STACK) \ - CBC_OPCODE (CBC_EXT_STRING_CONCAT, CBC_NO_FLAG, -1, \ - VM_OC_STRING_CONCAT | VM_OC_GET_STACK_STACK | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_EXT_STRING_CONCAT_RIGHT_LITERAL, CBC_HAS_LITERAL_ARG, 0, \ - VM_OC_STRING_CONCAT | VM_OC_GET_STACK_LITERAL | VM_OC_PUT_STACK) \ - CBC_OPCODE (CBC_EXT_STRING_CONCAT_TWO_LITERALS, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 1, \ - 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_RETURN_PROMISE, CBC_NO_FLAG, -1, \ + VM_OC_RETURN_PROMISE | VM_OC_GET_STACK) \ \ /* Last opcode (not a real opcode). */ \ CBC_OPCODE (CBC_EXT_END, CBC_NO_FLAG, 0, \ diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c index e67435bc6..24e96d19c 100644 --- a/jerry-core/parser/js/js-lexer.c +++ b/jerry-core/parser/js/js-lexer.c @@ -486,6 +486,7 @@ static const keyword_string_t keywords_with_length_4[] = static const keyword_string_t keywords_with_length_5[] = { #if ENABLED (JERRY_ES2015) + LEXER_KEYWORD ("async", LEXER_KEYW_ASYNC), LEXER_KEYWORD ("await", LEXER_KEYW_AWAIT), #endif /* ENABLED (JERRY_ES2015) */ LEXER_KEYWORD ("break", LEXER_KEYW_BREAK), @@ -1843,6 +1844,30 @@ lexer_check_yield_no_arg (parser_context_t *context_p) /**< context */ } } /* lexer_check_yield_no_arg */ +/** + * Checks whether the next token is a multiply and consumes it. + * + * @return true if the next token is a multiply + */ +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->source_p >= context_p->source_end_p + || context_p->source_p[0] != LIT_CHAR_ASTERISK + || (context_p->source_p + 1 < context_p->source_end_p + && (context_p->source_p[1] == LIT_CHAR_EQUALS || context_p->source_p[1] == LIT_CHAR_ASTERISK))) + { + return false; + } + + lexer_consume_next_character (context_p); + context_p->token.type = LEXER_MULTIPLY; + return true; +} /* lexer_consume_generator */ + #endif /* ENABLED (JERRY_ES2015) */ /** @@ -2780,8 +2805,7 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */ if (lexer_parse_identifier (context_p, LEXER_PARSE_NO_OPTS)) { - if (!(ident_opts & (LEXER_OBJ_IDENT_ONLY_IDENTIFIERS | LEXER_OBJ_IDENT_OBJECT_PATTERN)) - && context_p->token.lit_location.length == 3) + if (!(ident_opts & (LEXER_OBJ_IDENT_ONLY_IDENTIFIERS | LEXER_OBJ_IDENT_OBJECT_PATTERN))) { lexer_skip_spaces (context_p); context_p->token.flags = (uint8_t) (context_p->token.flags | LEXER_NO_SKIP_SPACES); @@ -2799,11 +2823,20 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */ context_p->token.type = LEXER_PROPERTY_GETTER; return; } - else if (lexer_compare_literal_to_string (context_p, "set", 3)) + + if (lexer_compare_literal_to_string (context_p, "set", 3)) { context_p->token.type = LEXER_PROPERTY_SETTER; return; } + +#if ENABLED (JERRY_ES2015) + if (lexer_compare_literal_to_string (context_p, "async", 5)) + { + context_p->token.type = LEXER_KEYW_ASYNC; + return; + } +#endif /* ENABLED (JERRY_ES2015) */ } } @@ -2904,11 +2937,12 @@ lexer_expect_object_literal_id (parser_context_t *context_p, /**< context */ } /* lexer_expect_object_literal_id */ /** - * Next token must be an identifier. + * Read next token without checking keywords + * + * @return true if the next literal is identifier, false otherwise */ -void -lexer_scan_identifier (parser_context_t *context_p, /**< context */ - uint32_t ident_opts) /**< lexer_scan_ident_opts_t option bits */ +bool +lexer_scan_identifier (parser_context_t *context_p) /**< context */ { lexer_skip_spaces (context_p); context_p->token.line = context_p->line; @@ -2917,37 +2951,58 @@ lexer_scan_identifier (parser_context_t *context_p, /**< context */ if (context_p->source_p < context_p->source_end_p && lexer_parse_identifier (context_p, LEXER_PARSE_NO_OPTS)) { - if ((ident_opts & LEXER_SCAN_IDENT_PROPERTY) - && context_p->token.lit_location.length == 3) - { - 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 -#if ENABLED (JERRY_ES2015) - && context_p->source_p[0] != LIT_CHAR_COMMA - && context_p->source_p[0] != LIT_CHAR_RIGHT_BRACE - && context_p->source_p[0] != LIT_CHAR_LEFT_PAREN -#endif /* ENABLED (JERRY_ES2015) */ - && context_p->source_p[0] != LIT_CHAR_COLON) - { - if (lexer_compare_literal_to_string (context_p, "get", 3)) - { - context_p->token.type = LEXER_PROPERTY_GETTER; - } - else if (lexer_compare_literal_to_string (context_p, "set", 3)) - { - context_p->token.type = LEXER_PROPERTY_SETTER; - } - } - } - - return; + return true; } lexer_next_token (context_p); + return false; } /* lexer_scan_identifier */ +/** + * Check whether the identifier is a modifier in a property definition. + */ +void +lexer_check_property_modifier (parser_context_t *context_p) /**< context */ +{ + JERRY_ASSERT (!(context_p->token.flags & LEXER_NO_SKIP_SPACES)); + JERRY_ASSERT (context_p->token.type = LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL); + + 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 +#if ENABLED (JERRY_ES2015) + || context_p->source_p[0] == LIT_CHAR_COMMA + || context_p->source_p[0] == LIT_CHAR_RIGHT_BRACE + || context_p->source_p[0] == LIT_CHAR_LEFT_PAREN +#endif /* ENABLED (JERRY_ES2015) */ + || context_p->source_p[0] == LIT_CHAR_COLON) + { + return; + } + + if (lexer_compare_literal_to_string (context_p, "get", 3)) + { + context_p->token.type = LEXER_PROPERTY_GETTER; + return; + } + + if (lexer_compare_literal_to_string (context_p, "set", 3)) + { + context_p->token.type = LEXER_PROPERTY_SETTER; + return; + } + +#if ENABLED (JERRY_ES2015) + if (lexer_compare_literal_to_string (context_p, "async", 5)) + { + context_p->token.type = LEXER_KEYW_ASYNC; + return; + } +#endif /* ENABLED (JERRY_ES2015) */ +} /* lexer_check_property_modifier */ + /** * Compares two identifiers. * @@ -3190,6 +3245,24 @@ lexer_token_is_let (parser_context_t *context_p) /**< context */ && !context_p->token.lit_location.has_escape); } /* lexer_token_is_let */ +/** + * Compares the current identifier token to "async". + * + * Note: + * Escape sequences are not allowed. + * + * @return true if "async" is found, false otherwise + */ +inline bool JERRY_ATTR_ALWAYS_INLINE +lexer_token_is_async (parser_context_t *context_p) /**< context */ +{ + JERRY_ASSERT (context_p->token.type == LEXER_LITERAL + || context_p->token.type == LEXER_TEMPLATE_LITERAL); + + return (context_p->token.keyword_type == LEXER_KEYW_ASYNC + && !context_p->token.lit_location.has_escape); +} /* lexer_token_is_async */ + #endif /* ENABLED (JERRY_ES2015) */ /** diff --git a/jerry-core/parser/js/js-lexer.h b/jerry-core/parser/js/js-lexer.h index 216df07e9..5ab77c3d2 100644 --- a/jerry-core/parser/js/js-lexer.h +++ b/jerry-core/parser/js/js-lexer.h @@ -167,8 +167,15 @@ typedef enum LEXER_ARROW_LEFT_PAREN, /**< start of arrow function argument list */ #endif /* ENABLED (JERRY_ES2015) */ +#if ENABLED (JERRY_ES2015) + /* Keywords which are not keyword tokens. */ +#define LEXER_FIRST_NON_RESERVED_KEYWORD LEXER_KEYW_ASYNC + LEXER_KEYW_ASYNC, /**< async */ +#else /* !ENABLED (JERRY_ES2015) */ /* Keywords which are not keyword tokens. */ #define LEXER_FIRST_NON_RESERVED_KEYWORD LEXER_KEYW_EVAL +#endif /* ENABLED (JERRY_ES2015) */ + /* Keywords which cannot be assigned in strict mode. */ #define LEXER_FIRST_NON_STRICT_ARGUMENTS LEXER_KEYW_EVAL LEXER_KEYW_EVAL, /**< eval */ @@ -248,15 +255,6 @@ typedef enum LEXER_STRING_RAW = (1u << 1), /**< raw string ECMAScript v6, 11.8.6.1: TVR */ } lexer_string_options_t; -/** - * Lexer scan identifier parse options. - */ -typedef enum -{ - LEXER_SCAN_IDENT_NO_OPTS = (1u << 0), /**< no options */ - LEXER_SCAN_IDENT_PROPERTY = (1u << 1), /**< scan valid property names */ -} lexer_scan_ident_opts_t; - /** * Lexer number types. */ diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 4b4ff5b03..fe288ea99 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -547,11 +547,23 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */ } } + if (context_p->token.type == LEXER_KEYW_ASYNC) + { + if (!lexer_consume_generator (context_p)) + { + lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); + } + } + 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); + } if (context_p->token.type == LEXER_RIGHT_SQUARE) { @@ -875,8 +887,20 @@ 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_MULTIPLY) + { + status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD; + } + lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); uint16_t opcode = CBC_SET_LITERAL_PROPERTY; @@ -888,7 +912,6 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SET_COMPUTED_PROPERTY_LITERAL); } - uint32_t status_flags = PARSER_FUNCTION_CLOSURE | PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD; uint16_t function_literal_index = lexer_construct_function_object (context_p, status_flags); parser_emit_cbc_literal (context_p, @@ -1383,6 +1406,24 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ { JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_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)); + + lexer_next_token (context_p); + + if (context_p->token.type == LEXER_KEYW_FUNCTION) + { + parser_parse_function_expression (context_p, PARSER_FUNCTION_CLOSURE | PARSER_IS_FUNC_EXPRESSION); + break; + } + if (context_p->token.type == LEXER_LEFT_PAREN) + { + context_p->token.type = LEXER_ARROW_LEFT_PAREN; + } + } + parser_check_assignment_expr (context_p); parser_parse_function_expression (context_p, PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION); diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index 476bf2434..0d609a539 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -61,22 +61,23 @@ typedef enum PARSER_INSIDE_BLOCK = (1u << 12), /**< script has a lexical environment for let and const */ PARSER_IS_ARROW_FUNCTION = (1u << 13), /**< an arrow function is parsed */ PARSER_IS_GENERATOR_FUNCTION = (1u << 14), /**< a generator function is parsed */ - PARSER_DISALLOW_YIELD = (1u << 15), /**< throw SyntaxError for yield expression */ - PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM = (1u << 16), /**< function has a non simple parameter */ - PARSER_FUNCTION_HAS_REST_PARAM = (1u << 17), /**< function has rest parameter */ + PARSER_IS_ASYNC_FUNCTION = (1u << 15), /**< an async function is parsed */ + PARSER_DISALLOW_YIELD = (1u << 16), /**< throw SyntaxError for yield expression */ + PARSER_FUNCTION_HAS_NON_SIMPLE_PARAM = (1u << 17), /**< function has a non simple parameter */ + PARSER_FUNCTION_HAS_REST_PARAM = (1u << 18), /**< function has rest parameter */ /* These four status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */ - PARSER_CLASS_CONSTRUCTOR = (1u << 18), /**< a class constructor is parsed (this value must be kept in + PARSER_CLASS_CONSTRUCTOR = (1u << 19), /**< a class constructor is parsed (this value must be kept in * in sync with ECMA_PARSE_CLASS_CONSTRUCTOR) */ - PARSER_CLASS_HAS_SUPER = (1u << 19), /**< class has super reference */ - PARSER_CLASS_IMPLICIT_SUPER = (1u << 20), /**< class has implicit parent class */ - PARSER_CLASS_STATIC_FUNCTION = (1u << 21), /**< this function is a static class method */ - PARSER_CLASS_SUPER_PROP_REFERENCE = (1u << 22), /**< super property call or assignment */ - PARSER_IS_EVAL = (1u << 23), /**< eval code */ + PARSER_CLASS_HAS_SUPER = (1u << 20), /**< class has super reference */ + PARSER_CLASS_IMPLICIT_SUPER = (1u << 21), /**< class has implicit parent class */ + PARSER_CLASS_STATIC_FUNCTION = (1u << 22), /**< this function is a static class method */ + PARSER_CLASS_SUPER_PROP_REFERENCE = (1u << 23), /**< super property call or assignment */ + PARSER_IS_EVAL = (1u << 24), /**< eval code */ #endif /* ENABLED (JERRY_ES2015) */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - PARSER_IS_MODULE = (1u << 24), /**< an export / import keyword is encountered */ - PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 25), /**< parsing a function or class default export */ - PARSER_MODULE_STORE_IDENT = (1u << 26), /**< store identifier of the current export statement */ + PARSER_IS_MODULE = (1u << 25), /**< an export / import keyword is encountered */ + PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 26), /**< parsing a function or class default export */ + PARSER_MODULE_STORE_IDENT = (1u << 27), /**< store identifier of the current export statement */ #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ PARSER_HAS_LATE_LIT_INIT = (1u << 30), /**< there are identifier or string literals which construction * is postponed after the local parser data is freed */ @@ -635,10 +636,12 @@ void lexer_skip_empty_statements (parser_context_t *context_p); 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); #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); -void lexer_scan_identifier (parser_context_t *context_p, uint32_t ident_opts); +bool lexer_scan_identifier (parser_context_t *context_p); +void lexer_check_property_modifier (parser_context_t *context_p); void lexer_convert_ident_to_cesu8 (uint8_t *destination_p, const uint8_t *source_p, prop_length_t length); const uint8_t *lexer_convert_literal_to_chars (parser_context_t *context_p, const lexer_lit_location_t *literal_p, @@ -660,6 +663,7 @@ bool lexer_string_is_directive (parser_context_t *context_p); bool lexer_token_is_identifier (parser_context_t *context_p, const char *identifier_p, size_t identifier_length); bool lexer_token_is_let (parser_context_t *context_p); +bool lexer_token_is_async (parser_context_t *context_p); #endif /* ENABLED (JERRY_ES2015) */ bool lexer_compare_literal_to_string (parser_context_t *context_p, const char *string_p, size_t string_length); uint8_t lexer_convert_binary_lvalue_token_to_binary (uint8_t token); diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 95ffaa391..082f077b8 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -2929,43 +2929,44 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS); } parser_emit_cbc (context_p, CBC_RETURN); + break; } - else + + if (context_p->status_flags & PARSER_IS_ASYNC_FUNCTION) { -#endif /* ENABLED (JERRY_ES2015) */ - parser_emit_cbc (context_p, CBC_RETURN_WITH_BLOCK); -#if ENABLED (JERRY_ES2015) + parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED); + parser_emit_cbc_ext (context_p, CBC_EXT_RETURN_PROMISE); + break; } #endif /* ENABLED (JERRY_ES2015) */ + + parser_emit_cbc (context_p, CBC_RETURN_WITH_BLOCK); break; } parser_parse_expression (context_p, PARSE_EXPR); - bool return_with_literal = (context_p->last_cbc_opcode == CBC_PUSH_LITERAL); #if ENABLED (JERRY_ES2015) - return_with_literal = return_with_literal && !PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags); + if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags))) + { + parser_emit_cbc_ext (context_p, CBC_EXT_CONSTRUCTOR_RETURN); + break; + } + + if (context_p->status_flags & PARSER_IS_ASYNC_FUNCTION) + { + parser_emit_cbc_ext (context_p, CBC_EXT_RETURN_PROMISE); + break; + } #endif /* ENABLED (JERRY_ES2015) */ - if (return_with_literal) + if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) { context_p->last_cbc_opcode = CBC_RETURN_WITH_LITERAL; + break; } - else - { -#if ENABLED (JERRY_ES2015) - if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags))) - { - parser_emit_cbc_ext (context_p, CBC_EXT_CONSTRUCTOR_RETURN); - } - else - { -#endif /* ENABLED (JERRY_ES2015) */ - parser_emit_cbc (context_p, CBC_RETURN); -#if ENABLED (JERRY_ES2015) - } -#endif /* ENABLED (JERRY_ES2015) */ - } + + parser_emit_cbc (context_p, CBC_RETURN); break; } @@ -2987,7 +2988,7 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ { if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL) { - if (lexer_check_next_character (context_p, LIT_CHAR_COLON)) + if (JERRY_UNLIKELY (lexer_check_next_character (context_p, LIT_CHAR_COLON))) { parser_parse_label (context_p); lexer_consume_next_character (context_p); @@ -2995,7 +2996,7 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ continue; } #if ENABLED (JERRY_ES2015) - if (lexer_token_is_let (context_p)) + if (JERRY_UNLIKELY (lexer_token_is_let (context_p))) { if (context_p->next_scanner_info_p->source_p == context_p->source_p) { @@ -3012,6 +3013,21 @@ parser_parse_statements (parser_context_t *context_p) /**< context */ parser_parse_var_statement (context_p); break; } + + 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); + + if (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_STATEMENT) + { + JERRY_ASSERT (context_p->next_scanner_info_p->u8_arg & SCANNER_FUNCTION_ASYNC); + + lexer_next_token (context_p); + JERRY_ASSERT (context_p->token.type == LEXER_KEYW_FUNCTION); + continue; + } + } #endif /* ENABLED (JERRY_ES2015) */ } /* FALLTHRU */ diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 481d2cea4..2ed196176 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -994,7 +994,8 @@ parser_post_processing (parser_context_t *context_p) /**< context */ length++; #if ENABLED (JERRY_ES2015) - if (ext_opcode == CBC_EXT_CONSTRUCTOR_RETURN) + if (ext_opcode == CBC_EXT_CONSTRUCTOR_RETURN + || ext_opcode == CBC_EXT_RETURN_PROMISE) { last_opcode = CBC_RETURN; } @@ -1140,6 +1141,14 @@ parser_post_processing (parser_context_t *context_p) /**< context */ || !(PARSER_OPCODE_IS_RETURN (last_opcode))) { context_p->status_flags &= (uint32_t) ~PARSER_NO_END_LABEL; + +#if ENABLED (JERRY_ES2015) + if (context_p->status_flags & PARSER_IS_ASYNC_FUNCTION) + { + length += 2; + } +#endif /* ENABLED (JERRY_ES2015) */ + length++; } @@ -1496,6 +1505,16 @@ parser_post_processing (parser_context_t *context_p) /**< context */ if (!(context_p->status_flags & PARSER_NO_END_LABEL)) { *dst_p++ = CBC_RETURN_WITH_BLOCK; + +#if ENABLED (JERRY_ES2015) + if (context_p->status_flags & PARSER_IS_ASYNC_FUNCTION) + { + dst_p[-1] = CBC_PUSH_UNDEFINED; + dst_p[0] = CBC_EXT_OPCODE; + dst_p[1] = CBC_EXT_RETURN_PROMISE; + dst_p += 2; + } +#endif /* ENABLED (JERRY_ES2015) */ } JERRY_ASSERT (dst_p == byte_code_p + length); @@ -1657,11 +1676,18 @@ static void parser_parse_function_arguments (parser_context_t *context_p, /**< context */ lexer_token_type_t end_type) /**< expected end type */ { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION); + #if ENABLED (JERRY_ES2015) bool duplicated_argument_names = false; -#endif /* ENABLED (JERRY_ES2015) */ - JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION); + /* 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)) + { + context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION; + } +#endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.type == end_type) { @@ -2454,14 +2480,25 @@ parser_parse_arrow_function (parser_context_t *context_p, /**< context */ parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); - if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) +#if ENABLED (JERRY_ES2015) + if (context_p->status_flags & PARSER_IS_ASYNC_FUNCTION) { - context_p->last_cbc_opcode = CBC_RETURN_WITH_LITERAL; + parser_emit_cbc_ext (context_p, CBC_EXT_RETURN_PROMISE); } else { - parser_emit_cbc (context_p, CBC_RETURN); +#endif /* ENABLED (JERRY_ES2015) */ + if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) + { + context_p->last_cbc_opcode = CBC_RETURN_WITH_LITERAL; + } + else + { + parser_emit_cbc (context_p, CBC_RETURN); + } +#if ENABLED (JERRY_ES2015) } +#endif /* ENABLED (JERRY_ES2015) */ parser_flush_cbc (context_p); } diff --git a/jerry-core/parser/js/js-scanner-internal.h b/jerry-core/parser/js/js-scanner-internal.h index c2ff55213..b3037e8d4 100644 --- a/jerry-core/parser/js/js-scanner-internal.h +++ b/jerry-core/parser/js/js-scanner-internal.h @@ -27,7 +27,7 @@ */ /** - * Scan mode types types. + * Scan mode types. */ typedef enum { @@ -50,7 +50,7 @@ typedef enum } scan_modes_t; /** - * Scan stack mode types types. + * Scan stack mode types. */ typedef enum { @@ -108,6 +108,7 @@ typedef enum SCAN_STACK_CLASS_EXPRESSION, /**< class expression */ SCAN_STACK_CLASS_EXTENDS, /**< class extends expression */ SCAN_STACK_FUNCTION_PARAMETERS, /**< function parameter initializer */ + SCAN_STACK_USE_ASYNC, /**< an "async" identifier is used */ #endif /* ENABLED (JERRY_ES2015) */ } scan_stack_modes_t; @@ -272,7 +273,9 @@ typedef enum SCANNER_LITERAL_POOL_IN_EXPORT = (1 << 8), /**< the declared variables are exported by the module system */ #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ #if ENABLED (JERRY_ES2015) - SCANNER_LITERAL_POOL_GENERATOR = (1 << 9), /**< generator function */ + SCANNER_LITERAL_POOL_FUNCTION_STATEMENT = (1 << 9), /**< function statement (only if async is set) */ + SCANNER_LITERAL_POOL_GENERATOR = (1 << 10), /**< generator function */ + SCANNER_LITERAL_POOL_ASYNC = (1 << 11), /**< async function */ #endif /* ENABLED (JERRY_ES2015) */ } scanner_literal_pool_flags_t; @@ -311,6 +314,9 @@ struct scanner_context_t scanner_literal_pool_t *active_literal_pool_p; /**< currently active literal pool */ scanner_switch_statement_t active_switch_statement; /**< currently active switch statement */ scanner_info_t *end_arguments_p; /**< position of end arguments */ +#if ENABLED (JERRY_ES2015) + const uint8_t *async_source_p; /**< source position for async functions */ +#endif /* ENABLED (JERRY_ES2015) */ }; void scanner_raise_error (parser_context_t *context_p); diff --git a/jerry-core/parser/js/js-scanner-util.c b/jerry-core/parser/js/js-scanner-util.c index cf5991b0d..1b621a8d0 100644 --- a/jerry-core/parser/js/js-scanner-util.c +++ b/jerry-core/parser/js/js-scanner-util.c @@ -670,6 +670,18 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ } } +#if ENABLED (JERRY_ES2015) + if (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_ASYNC) + { + status_flags |= SCANNER_FUNCTION_ASYNC; + + if (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION_STATEMENT) + { + status_flags |= SCANNER_FUNCTION_STATEMENT; + } + } +#endif /* ENABLED (JERRY_ES2015) */ + info_p->u8_arg = status_flags; info_p->u16_arg = (uint16_t) no_declarations; } diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index e0b6e50ae..f28e57af2 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -31,7 +31,7 @@ */ /** - * Scan mode types types. + * Scan return types. */ typedef enum { @@ -57,6 +57,32 @@ typedef enum (((literal_pool_flags) & SCANNER_LITERAL_POOL_GENERATOR) ? SCAN_STACK_COMPUTED_GENERATOR_FUNCTION \ : SCAN_STACK_COMPUTED_PROPERTY) +/** + * Add the "async" literal to the literal pool. + */ +static void +scanner_add_async_literal (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + lexer_lit_location_t async_literal; + + JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_USE_ASYNC); + + parser_stack_pop_uint8 (context_p); + parser_stack_pop (context_p, &async_literal, sizeof (lexer_lit_location_t)); + + lexer_lit_location_t *lit_location_p = scanner_add_custom_literal (context_p, + scanner_context_p->active_literal_pool_p, + &async_literal); + + lit_location_p->type |= SCANNER_LITERAL_IS_USED; + + if (scanner_context_p->active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH) + { + lit_location_p->type |= SCANNER_LITERAL_NO_REG; + } +} /* scanner_add_async_literal */ + /** * Init scanning the body of an arrow function. */ @@ -92,11 +118,21 @@ scanner_process_arrow (parser_context_t *context_p, /**< context */ if (context_p->token.type != LEXER_ARROW || (context_p->token.flags & LEXER_WAS_NEWLINE)) { + if (context_p->stack_top_uint8 == SCAN_STACK_USE_ASYNC) + { + scanner_add_async_literal (context_p, scanner_context_p); + } + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; scanner_pop_literal_pool (context_p, scanner_context_p); return; } + if (context_p->stack_top_uint8 == SCAN_STACK_USE_ASYNC) + { + parser_stack_pop (context_p, NULL, sizeof (lexer_lit_location_t) + 1); + } + scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p; literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS; @@ -210,14 +246,75 @@ scanner_process_arrow_arg (parser_context_t *context_p, /**< context */ } /* scanner_process_arrow_arg */ /** - * Arrow types for scanner_handle_bracket() function. + * Detect async functions. + * + * @return true, if async is followed by a function keyword, false otherwise + */ +static bool +scanner_scan_async (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ +{ + JERRY_ASSERT (lexer_token_is_async (context_p)); + JERRY_ASSERT (scanner_context_p->mode == SCAN_MODE_PRIMARY_EXPRESSION); + JERRY_ASSERT (scanner_context_p->async_source_p != NULL); + + lexer_lit_location_t async_literal = context_p->token.lit_location; + + lexer_next_token (context_p); + + if (!(context_p->token.flags & LEXER_WAS_NEWLINE)) + { + if (context_p->token.type == LEXER_KEYW_FUNCTION) + { + return true; + } + + if (context_p->token.type == LEXER_LITERAL + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) + { + if (!lexer_check_arrow (context_p)) + { + scanner_raise_error (context_p); + } + + scanner_process_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; + } + + if (context_p->token.type == LEXER_LEFT_PAREN) + { + parser_stack_push (context_p, &async_literal, sizeof (lexer_lit_location_t)); + parser_stack_push_uint8 (context_p, SCAN_STACK_USE_ASYNC); + return false; + } + } + + lexer_lit_location_t *lit_location_p = scanner_add_custom_literal (context_p, + scanner_context_p->active_literal_pool_p, + &async_literal); + lit_location_p->type |= SCANNER_LITERAL_IS_USED; + + if (scanner_context_p->active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH) + { + lit_location_p->type |= SCANNER_LITERAL_NO_REG; + } + + scanner_context_p->async_source_p = NULL; + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + return false; +} /* scanner_scan_async */ + +/** + * Arrow types for scanner_scan_bracket() function. */ typedef enum { - SCANNER_HANDLE_BRACKET_NO_ARROW, /**< not an arrow function */ - SCANNER_HANDLE_BRACKET_SIMPLE_ARROW, /**< simple arrow function */ - SCANNER_HANDLE_BRACKET_ARROW_WITH_ONE_ARG, /**< arrow function with one argument */ -} scanner_handle_bracket_arrow_type_t; + SCANNER_SCAN_BRACKET_NO_ARROW, /**< not an arrow function */ + SCANNER_SCAN_BRACKET_SIMPLE_ARROW, /**< simple arrow function */ + SCANNER_SCAN_BRACKET_ARROW_WITH_ONE_ARG, /**< arrow function with one argument */ +} scanner_scan_bracket_arrow_type_t; #endif /* ENABLED (JERRY_ES2015) */ @@ -225,13 +322,14 @@ typedef enum * Detect special cases in bracketed expressions. */ static void -scanner_handle_bracket (parser_context_t *context_p, /**< context */ - scanner_context_t *scanner_context_p) /**< scanner context */ +scanner_scan_bracket (parser_context_t *context_p, /**< context */ + scanner_context_t *scanner_context_p) /**< scanner context */ { size_t depth = 0; #if ENABLED (JERRY_ES2015) const uint8_t *arrow_source_p; - scanner_handle_bracket_arrow_type_t arrow_type = SCANNER_HANDLE_BRACKET_NO_ARROW; + const uint8_t *async_source_p = NULL; + scanner_scan_bracket_arrow_type_t arrow_type = SCANNER_SCAN_BRACKET_NO_ARROW; #endif /* ENABLED (JERRY_ES2015) */ JERRY_ASSERT (context_p->token.type == LEXER_LEFT_PAREN); @@ -266,7 +364,7 @@ scanner_handle_bracket (parser_context_t *context_p, /**< context */ if (lexer_check_arrow (context_p)) { arrow_source_p = source_p; - arrow_type = SCANNER_HANDLE_BRACKET_SIMPLE_ARROW; + arrow_type = SCANNER_SCAN_BRACKET_SIMPLE_ARROW; break; } @@ -279,17 +377,15 @@ scanner_handle_bracket (parser_context_t *context_p, /**< context */ depth--; } - if (lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN)) + if (context_p->token.keyword_type == LEXER_KEYW_EVAL + && lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN)) { #if ENABLED (JERRY_ES2015) /* A function call cannot be an eval function. */ arrow_source_p = NULL; #endif /* ENABLED (JERRY_ES2015) */ - if (context_p->token.keyword_type == LEXER_KEYW_EVAL) - { - scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_NO_REG; - } + scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_NO_REG; break; } @@ -302,11 +398,15 @@ scanner_handle_bracket (parser_context_t *context_p, /**< context */ depth--; break; } + + if (JERRY_UNLIKELY (lexer_token_is_async (context_p))) + { + async_source_p = source_p; + } } - else if (depth == total_depth - 1 - && lexer_check_arrow (context_p)) + else if (depth == total_depth - 1 && lexer_check_arrow (context_p)) { - arrow_type = SCANNER_HANDLE_BRACKET_ARROW_WITH_ONE_ARG; + arrow_type = SCANNER_SCAN_BRACKET_ARROW_WITH_ONE_ARG; break; } @@ -334,6 +434,14 @@ scanner_handle_bracket (parser_context_t *context_p, /**< context */ } } +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (scanner_context_p->async_source_p != NULL) + && (arrow_source_p == NULL || depth > 0)) + { + scanner_context_p->async_source_p = NULL; + } +#endif /* ENABLED (JERRY_ES2015) */ + while (depth > 0) { parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION); @@ -343,7 +451,9 @@ scanner_handle_bracket (parser_context_t *context_p, /**< context */ #if ENABLED (JERRY_ES2015) if (arrow_source_p != NULL) { - if (arrow_type == SCANNER_HANDLE_BRACKET_SIMPLE_ARROW) + JERRY_ASSERT (async_source_p == NULL); + + if (arrow_type == SCANNER_SCAN_BRACKET_SIMPLE_ARROW) { scanner_process_simple_arrow (context_p, scanner_context_p, arrow_source_p); return; @@ -351,11 +461,20 @@ scanner_handle_bracket (parser_context_t *context_p, /**< context */ parser_stack_push_uint8 (context_p, SCAN_STACK_ARROW_ARGUMENTS); + uint16_t status_flags = 0; + + if (JERRY_UNLIKELY (scanner_context_p->async_source_p != NULL)) + { + status_flags |= SCANNER_LITERAL_POOL_ASYNC; + arrow_source_p = scanner_context_p->async_source_p; + scanner_context_p->async_source_p = NULL; + } + scanner_literal_pool_t *literal_pool_p; - literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, 0); + literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, status_flags); literal_pool_p->source_p = arrow_source_p; - if (arrow_type == SCANNER_HANDLE_BRACKET_ARROW_WITH_ONE_ARG) + if (arrow_type == SCANNER_SCAN_BRACKET_ARROW_WITH_ONE_ARG) { scanner_append_argument (context_p, scanner_context_p); scanner_detect_eval_call (context_p, scanner_context_p); @@ -372,8 +491,13 @@ scanner_handle_bracket (parser_context_t *context_p, /**< context */ scanner_process_arrow_arg (context_p, scanner_context_p); } } + else if (JERRY_UNLIKELY (async_source_p != NULL)) + { + scanner_context_p->async_source_p = async_source_p; + scanner_scan_async (context_p, scanner_context_p); + } #endif /* ENABLED (JERRY_ES2015) */ -} /* scanner_handle_bracket */ +} /* scanner_scan_bracket */ /** * Scan primary expression. @@ -431,7 +555,7 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ } case LEXER_LEFT_PAREN: { - scanner_handle_bracket (context_p, scanner_context_p); + scanner_scan_bracket (context_p, scanner_context_p); return SCAN_KEEP_TOKEN; } case LEXER_LEFT_SQUARE: @@ -479,6 +603,12 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ scanner_process_simple_arrow (context_p, scanner_context_p, source_p); return SCAN_KEEP_TOKEN; } + else if (JERRY_UNLIKELY (lexer_token_is_async (context_p))) + { + scanner_context_p->async_source_p = source_p; + scanner_scan_async (context_p, scanner_context_p); + return SCAN_KEEP_TOKEN; + } #endif /* ENABLED (JERRY_ES2015) */ if (context_p->token.lit_location.type == LEXER_IDENT_LITERAL) @@ -597,7 +727,7 @@ scanner_scan_post_primary_expression (parser_context_t *context_p, /**< context { case LEXER_DOT: { - lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_NO_OPTS); + lexer_scan_identifier (context_p); if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) @@ -811,8 +941,17 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * { break; } - scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + parser_stack_pop_uint8 (context_p); + +#if ENABLED (JERRY_ES2015) + if (context_p->stack_top_uint8 == SCAN_STACK_USE_ASYNC) + { + scanner_add_async_literal (context_p, scanner_context_p); + } +#endif /* ENABLED (JERRY_ES2015) */ + + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; return SCAN_NEXT_TOKEN; } case SCAN_STACK_STATEMENT_WITH_EXPR: @@ -2164,6 +2303,17 @@ scanner_scan_statement (parser_context_t *context_p, /**< context */ scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; return SCAN_KEEP_TOKEN; } + + if (JERRY_UNLIKELY (lexer_token_is_async (context_p))) + { + scanner_context_p->async_source_p = context_p->source_p; + + if (scanner_scan_async (context_p, scanner_context_p)) + { + scanner_context_p->mode = SCAN_MODE_STATEMENT; + } + return SCAN_KEEP_TOKEN; + } #endif /* ENABLED (JERRY_ES2015) */ scanner_add_reference (context_p, scanner_context_p); @@ -2537,6 +2687,9 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ scanner_context.active_literal_pool_p = NULL; scanner_context.active_switch_statement.last_case_p = NULL; scanner_context.end_arguments_p = NULL; +#if ENABLED (JERRY_ES2015) + scanner_context.async_source_p = NULL; +#endif /* ENABLED (JERRY_ES2015) */ /* This assignment must be here because of Apple compilers. */ context_p->u.scanner_context_p = &scanner_context; @@ -2639,7 +2792,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ JERRY_ASSERT (stack_top == SCAN_STACK_CLASS_STATEMENT || stack_top == SCAN_STACK_CLASS_EXPRESSION); lexer_skip_empty_statements (context_p); - lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_NO_OPTS); + lexer_scan_identifier (context_p); if (context_p->token.type == LEXER_RIGHT_BRACE) { @@ -2657,7 +2810,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ if (lexer_token_is_identifier (context_p, "static", 6)) { - lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_NO_OPTS); + lexer_scan_identifier (context_p); } parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY); @@ -2668,7 +2821,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ if (lexer_token_is_identifier (context_p, "get", 3) || lexer_token_is_identifier (context_p, "set", 3)) { - lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_NO_OPTS); + lexer_scan_identifier (context_p); if (context_p->token.type == LEXER_LEFT_PAREN) { @@ -2676,9 +2829,27 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ continue; } } + else if (lexer_token_is_identifier (context_p, "async", 5)) + { + lexer_scan_identifier (context_p); + + if (context_p->token.type == LEXER_LEFT_PAREN) + { + scanner_push_literal_pool (context_p, &scanner_context, SCANNER_LITERAL_POOL_FUNCTION); + continue; + } + + literal_pool_flags |= SCANNER_LITERAL_POOL_ASYNC; + + if (context_p->token.type == LEXER_MULTIPLY) + { + lexer_scan_identifier (context_p); + literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR; + } + } else if (context_p->token.type == LEXER_MULTIPLY) { - lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_NO_OPTS); + lexer_scan_identifier (context_p); literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR; } @@ -2906,10 +3077,24 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ || stack_top == SCAN_STACK_FUNCTION_EXPRESSION || stack_top == SCAN_STACK_FUNCTION_PROPERTY); - JERRY_ASSERT (scanner_context.active_literal_pool_p != NULL - && (scanner_context.active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION)); + scanner_literal_pool_t *literal_pool_p = scanner_context.active_literal_pool_p; - scanner_context.active_literal_pool_p->source_p = context_p->source_p; + JERRY_ASSERT (literal_pool_p != NULL && (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION)); + + literal_pool_p->source_p = context_p->source_p; + +#if ENABLED (JERRY_ES2015) + if (JERRY_UNLIKELY (scanner_context.async_source_p != NULL)) + { + literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ASYNC; + if (stack_top == SCAN_STACK_FUNCTION_STATEMENT) + { + literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_FUNCTION_STATEMENT; + } + literal_pool_p->source_p = scanner_context.async_source_p; + scanner_context.async_source_p = NULL; + } +#endif /* ENABLED (JERRY_ES2015) */ if (type != LEXER_LEFT_PAREN) { @@ -3035,7 +3220,10 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ { JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL); - lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_PROPERTY); + if (lexer_scan_identifier (context_p)) + { + lexer_check_property_modifier (context_p); + } #if ENABLED (JERRY_ES2015) if (context_p->token.type == LEXER_LEFT_SQUARE) @@ -3054,6 +3242,7 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ if (context_p->token.type == LEXER_PROPERTY_GETTER #if ENABLED (JERRY_ES2015) + || context_p->token.type == LEXER_KEYW_ASYNC || context_p->token.type == LEXER_MULTIPLY #endif /* ENABLED (JERRY_ES2015) */ || context_p->token.type == LEXER_PROPERTY_SETTER) @@ -3065,10 +3254,19 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ { literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR; } + else if (context_p->token.type == LEXER_KEYW_ASYNC) + { + literal_pool_flags |= SCANNER_LITERAL_POOL_ASYNC; + + if (lexer_consume_generator (context_p)) + { + literal_pool_flags |= SCANNER_LITERAL_POOL_GENERATOR; + } + } #endif /* ENABLED (JERRY_ES2015) */ parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_PROPERTY); - lexer_scan_identifier (context_p, LEXER_SCAN_IDENT_NO_OPTS); + lexer_scan_identifier (context_p); #if ENABLED (JERRY_ES2015) if (context_p->token.type == LEXER_LEFT_SQUARE) diff --git a/jerry-core/parser/js/js-scanner.h b/jerry-core/parser/js/js-scanner.h index 3146520d5..d74dcfe14 100644 --- a/jerry-core/parser/js/js-scanner.h +++ b/jerry-core/parser/js/js-scanner.h @@ -210,6 +210,10 @@ typedef enum typedef enum { SCANNER_FUNCTION_ARGUMENTS_NEEDED = (1 << 0), /**< arguments object needs to be created */ +#if ENABLED (JERRY_ES2015) + SCANNER_FUNCTION_STATEMENT = (1 << 1), /**< function is (async) function statement */ + SCANNER_FUNCTION_ASYNC = (1 << 2), /**< function is async function expression */ +#endif /* ENABLED (JERRY_ES2015) */ } scanner_function_flags_t; /** diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index 2550a505e..c64a9d9c8 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -26,6 +26,7 @@ #include "ecma-iterator-object.h" #include "ecma-lex-env.h" #include "ecma-objects.h" +#include "ecma-promise-object.h" #include "ecma-try-catch-macro.h" #include "jcontext.h" #include "opcodes.h" @@ -706,6 +707,21 @@ opfunc_resume_executable_object (vm_executable_object_t *executable_object_p, /* return result; } /* opfunc_resume_executable_object */ +/** + * Create a Promise object if needed and resolve it with a value + * + * @return Promise object + */ +ecma_value_t +opfunc_return_promise (ecma_value_t value) /**< value */ +{ + ecma_value_t promise = ecma_make_object_value (ecma_builtin_get (ECMA_BUILTIN_ID_PROMISE)); + ecma_value_t result = ecma_promise_reject_or_resolve (promise, value, true); + + ecma_free_value (value); + return result; +} /* opfunc_return_promise */ + #endif /* ENABLED (JERRY_ES2015) */ /** diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h index d6bb01aef..6b384efbc 100644 --- a/jerry-core/vm/opcodes.h +++ b/jerry-core/vm/opcodes.h @@ -115,6 +115,9 @@ opfunc_create_executable_object (vm_frame_ctx_t *frame_ctx_p); ecma_value_t opfunc_resume_executable_object (vm_executable_object_t *executable_object_p, ecma_value_t value); + +ecma_value_t +opfunc_return_promise (ecma_value_t value); #endif /* ENABLED (JERRY_ES2015) */ /** diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 0dbbf1f46..028af542c 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -2098,6 +2098,12 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ goto error; } + case VM_OC_RETURN_PROMISE: + { + result = opfunc_return_promise (left_value); + left_value = ECMA_VALUE_UNDEFINED; + goto error; + } case VM_OC_STRING_CONCAT: { ecma_string_t *left_str_p = ecma_op_to_string (left_value); @@ -2131,7 +2137,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ *stack_top_p++ = ecma_copy_value (collection_p->buffer_p[tagged_idx]); continue; } - #endif /* ENABLED (JERRY_ES2015) */ +#endif /* ENABLED (JERRY_ES2015) */ case VM_OC_PUSH_ELISON: { *stack_top_p++ = ECMA_VALUE_ARRAY_HOLE; diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index 29d98d688..1f1d045b7 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -258,6 +258,7 @@ typedef enum VM_OC_CREATE_GENERATOR, /**< create a generator object */ VM_OC_YIELD, /**< yield 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 */ VM_OC_GET_TEMPLATE_OBJECT, /**< GetTemplateObject operation */ #endif /* ENABLED (JERRY_ES2015) */ @@ -313,6 +314,7 @@ typedef enum VM_OC_CREATE_GENERATOR = VM_OC_NONE, /**< create a generator object */ VM_OC_YIELD = VM_OC_NONE, /**< yield 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 */ VM_OC_GET_TEMPLATE_OBJECT = VM_OC_NONE, /**< GetTemplateObject operation */ #endif /* !ENABLED (JERRY_ES2015) */ diff --git a/tests/jerry/es2015/function-async1.js b/tests/jerry/es2015/function-async1.js new file mode 100644 index 000000000..17907e581 --- /dev/null +++ b/tests/jerry/es2015/function-async1.js @@ -0,0 +1,146 @@ +// 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 async modifiers (nothing else). */ + +function check_promise(p, value) +{ + assert(p instanceof Promise) + + p.then(function(v) { + assert(v === value) + }) +} + +/* Async functions */ + +async function f(a) { + return a +} + +check_promise(f(1), 1) + +f = async function (a) { return a } +check_promise(f(2), 2) + +f = (async function (a) { return a }) +check_promise(f(3), 3) + +f = [async function (a) { return a }] +check_promise(f[0](4), 4) + +/* These four are parser tests. */ +async => {} +async async => {} +(async => {}) +(async async => {}) + +f = async => async; +assert(f(5) === 5) + +f = async async => async; +check_promise(f(6), 6) + +f = (async => async) +assert(f(7) === 7) + +f = (async async => async) +check_promise(f(8), 8) + +f = [async => async] +assert(f[0](9) === 9) + +f = [async async => async] +check_promise(f[0](10), 10) + +f = async (a, b) => a + b; +check_promise(f(10, 1), 11) + +f = (async (a, b) => a + b); +check_promise(f(10, 2), 12) + +f = [async (a, b) => a + b]; +check_promise(f[0](10, 3), 13) + +f = true ? async () => 14 : 0; +check_promise(f(), 14) + +f = (1, async async => async) +check_promise(f(15), 15) + +/* Functions contain async references */ + +function f1() { + var async = 1; + + /* The arrow function after the newline should be ignored. */ + var v1 = async + async => async + + /* The function statement after the newline should not be an async function. */ + var v2 = async + function g() { return 2 } + + async + function h() { return 3 } + + assert(v1 === 1) + assert(v2 === 1) + assert(g() === 2) + assert(h() === 3) +} +f1(); + +function f2() { + var async = 1; + + function g() { async = 2; } + g(); + + assert(async == 2); +} +f2(); + +function f3() { + var v = 3; + var async = () => v = 4; + + function g() { async(); } + g(); + + assert(v === 4); +} +f3(); + +function f4() { + var v = 5; + var async = (a, b) => v = a + b; + + function g() { async(((v)), ((v))); } + g(); + + assert(v === 10); +} +f4(); + +function f5() { + var v = 0; + var async = (a, b) => v = a + b; + + function g() { async((async(1,2)), ((async(3,4)))); } + g(); + + assert(v === 10); +} +f5(); diff --git a/tests/jerry/es2015/function-async2.js b/tests/jerry/es2015/function-async2.js new file mode 100644 index 000000000..3ae9947e3 --- /dev/null +++ b/tests/jerry/es2015/function-async2.js @@ -0,0 +1,69 @@ +// 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 async modifiers (nothing else). */ + +function check_syntax_error (code) +{ + try { + eval (code) + assert (false) + } catch (e) { + assert (e instanceof SyntaxError) + } +} + +check_syntax_error("function async f() {}") +check_syntax_error("(a,b) async => 1") +/* SyntaxError because arrow declaration is an assignment expression. */ +check_syntax_error("async * (a,b) => 1") +check_syntax_error("({ *async f() {} })") +check_syntax_error("class C { async static f() {} }") +check_syntax_error("class C { * async f() {} }") +check_syntax_error("class C { static * async f() {} }") + + +function check_promise(p, value) +{ + assert(p instanceof Promise) + + p.then(function(v) { + assert(v === value) + }) +} + +var o = { + async f() { return 1 }, + async() { return 2 }, + async *x() {}, /* Parser test, async iterators are needed to work. */ +} + +check_promise(o.f(), 1) +assert(o.async() === 2) + +class C { + async f() { return 3 } + async *x() {} /* Parser test, async iterators are needed to work. */ + static async f() { return 4 } + static async *y() {} /* Parser test, async iterators are needed to work. */ + async() { return 5 } + static async() { return 6 } +} + +var c = new C + +check_promise(c.f(), 3) +check_promise(C.f(), 4) +assert(c.async() === 5) +assert(C.async() === 6) diff --git a/tests/unit-core/test-snapshot.c b/tests/unit-core/test-snapshot.c index b599266bd..3dc3d7f5d 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, 0x23, 0x00, 0x00, 0x00, + 0x4A, 0x52, 0x52, 0x59, 0x24, 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,