mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Support parsing async modifiers for functions. (#3460)
Only parsing is implemented, so the async functions currently behave like normal function except they return with a resolved Promise object when the function is terminated correctly. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
parent
2a29b72a83
commit
8cb2be6001
@ -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 */
|
||||
|
||||
/**
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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);
|
||||
|
||||
/**
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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, \
|
||||
|
||||
@ -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) */
|
||||
|
||||
/**
|
||||
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@ -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) */
|
||||
|
||||
/**
|
||||
|
||||
@ -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) */
|
||||
|
||||
/**
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) */
|
||||
|
||||
146
tests/jerry/es2015/function-async1.js
Normal file
146
tests/jerry/es2015/function-async1.js
Normal file
@ -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();
|
||||
69
tests/jerry/es2015/function-async2.js
Normal file
69
tests/jerry/es2015/function-async2.js
Normal file
@ -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)
|
||||
@ -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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user