Files
jerryscript/jerry-core/parser/js/js-parser-expr.c
T
Robert Fancsik 76b8555210 Remove JERRY_CONTEXT_INVALID_NEW_TARGET (#3643)
Until now JERRY_CONTEXT_INVALID_NEW_TARGET was used to represent whether the eval called from the script directly.
This information can be retrieved from the parser, so it simplifies the runtime handling of the new.target.

This patch fixes #3630, fixes #3640 and fixes #3641.

JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu
2020-03-27 11:21:50 +01:00

3196 lines
100 KiB
C

/* 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.
*/
#include "js-parser-internal.h"
#if ENABLED (JERRY_PARSER)
#include "jcontext.h"
#include "ecma-helpers.h"
#include "lit-char-helpers.h"
#include "js-parser-tagged-template-literal.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_expr Expression parser
* @{
*/
/**
* Maximum precedence for right-to-left binary operation evaluation.
*/
#define PARSER_RIGHT_TO_LEFT_ORDER_MAX_PRECEDENCE 6
/**
* Precende for ternary operation.
*/
#define PARSER_RIGHT_TO_LEFT_ORDER_TERNARY_PRECEDENCE 4
/**
* Value of grouping level increase and decrease.
*/
#define PARSER_GROUPING_LEVEL_INCREASE 2
/**
* Precedence of the binary tokens.
*
* See also:
* lexer_token_type_t
*/
static const uint8_t parser_binary_precedence_table[36] =
{
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
4, 5, 6, 7, 8, 9, 10, 10, 10, 10,
11, 11, 11, 11, 11, 11, 12, 12, 12,
13, 13, 14, 14, 14
};
/**
* Generate byte code for operators with lvalue.
*/
static inline void
parser_push_result (parser_context_t *context_p) /**< context */
{
if (CBC_NO_RESULT_OPERATION (context_p->last_cbc_opcode))
{
JERRY_ASSERT (CBC_SAME_ARGS (context_p->last_cbc_opcode, context_p->last_cbc_opcode + 1));
if ((context_p->last_cbc_opcode == CBC_POST_INCR
|| context_p->last_cbc_opcode == CBC_POST_DECR)
&& context_p->stack_depth >= context_p->stack_limit)
{
/* Stack limit is increased for CBC_POST_INCR_PUSH_RESULT
* and CBC_POST_DECR_PUSH_RESULT opcodes. Needed by vm.c. */
JERRY_ASSERT (context_p->stack_depth == context_p->stack_limit);
context_p->stack_limit++;
if (context_p->stack_limit > PARSER_MAXIMUM_STACK_LIMIT)
{
parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED);
}
}
context_p->last_cbc_opcode++;
parser_flush_cbc (context_p);
}
} /* parser_push_result */
/**
* Check for invalid assignment for "eval" and "arguments"
*/
static void
parser_check_invalid_assign (parser_context_t *context_p) /**< context */
{
if (context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL
&& JERRY_UNLIKELY (context_p->status_flags & PARSER_IS_STRICT))
{
if (context_p->last_cbc.literal_keyword_type == LEXER_KEYW_EVAL)
{
parser_raise_error (context_p, PARSER_ERR_EVAL_CANNOT_ASSIGNED);
}
else if (context_p->last_cbc.literal_keyword_type == LEXER_KEYW_ARGUMENTS)
{
parser_raise_error (context_p, PARSER_ERR_ARGUMENTS_CANNOT_ASSIGNED);
}
}
} /* parser_check_invalid_assign */
#if ENABLED (JERRY_ES2015)
/**
* Check and throw an error if the "new.target" is invalid as a left-hand side expression.
*/
static void
parser_check_invalid_new_target (parser_context_t *context_p, /**< parser context */
cbc_opcode_t opcode) /**< current opcode under parsing */
{
/* new.target is an invalid left-hand side target */
if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_NEW_TARGET))
{
/* Make sure that the call side is a post/pre increment or an assignment expression.
* There should be no other ways the "new.target" expression should be here. */
JERRY_ASSERT ((opcode >= CBC_PRE_INCR && opcode <= CBC_POST_DECR)
|| (opcode == CBC_ASSIGN
&& (context_p->token.type == LEXER_ASSIGN
|| LEXER_IS_BINARY_LVALUE_TOKEN (context_p->token.type))));
parser_raise_error (context_p, PARSER_ERR_NEW_TARGET_NOT_ALLOWED);
}
} /* parser_check_invalid_new_target */
#endif /* ENABLED (JERRY_ES2015) */
/**
* Emit identifier reference
*/
static void
parser_emit_ident_reference (parser_context_t *context_p, /**< context */
uint16_t opcode) /* opcode */
{
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
context_p->last_cbc_opcode = opcode;
return;
}
uint16_t literal_index;
if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS)
{
context_p->last_cbc_opcode = CBC_PUSH_LITERAL;
literal_index = context_p->last_cbc.value;
}
else if (context_p->last_cbc_opcode == CBC_PUSH_THIS_LITERAL)
{
context_p->last_cbc_opcode = CBC_PUSH_THIS;
literal_index = context_p->lit_object.index;
}
else
{
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_THREE_LITERALS);
context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS;
literal_index = context_p->last_cbc.third_literal_index;
}
parser_emit_cbc_literal (context_p, opcode, literal_index);
} /* parser_emit_ident_reference */
/**
* Generate byte code for operators with lvalue.
*/
static void
parser_emit_unary_lvalue_opcode (parser_context_t *context_p, /**< context */
cbc_opcode_t opcode) /**< opcode */
{
if (PARSER_IS_PUSH_LITERALS_WITH_THIS (context_p->last_cbc_opcode)
&& context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL)
{
parser_check_invalid_assign (context_p);
uint16_t unary_opcode;
if (opcode == CBC_DELETE_PUSH_RESULT)
{
if (JERRY_UNLIKELY (context_p->status_flags & PARSER_IS_STRICT))
{
parser_raise_error (context_p, PARSER_ERR_DELETE_IDENT_NOT_ALLOWED);
}
context_p->status_flags |= PARSER_LEXICAL_ENV_NEEDED;
unary_opcode = CBC_DELETE_IDENT_PUSH_RESULT;
}
else
{
JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_LITERAL, opcode + CBC_UNARY_LVALUE_WITH_IDENT));
unary_opcode = (uint16_t) (opcode + CBC_UNARY_LVALUE_WITH_IDENT);
}
parser_emit_ident_reference (context_p, unary_opcode);
return;
}
if (context_p->last_cbc_opcode == CBC_PUSH_PROP)
{
JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP, opcode));
context_p->last_cbc_opcode = (uint16_t) opcode;
return;
}
if (PARSER_IS_PUSH_PROP_LITERAL (context_p->last_cbc_opcode))
{
context_p->last_cbc_opcode = PARSER_PUSH_PROP_LITERAL_TO_PUSH_LITERAL (context_p->last_cbc_opcode);
}
else
{
/* Invalid LeftHandSide expression. */
if (opcode == CBC_DELETE_PUSH_RESULT)
{
parser_emit_cbc (context_p, CBC_POP);
parser_emit_cbc (context_p, CBC_PUSH_TRUE);
return;
}
#if ENABLED (JERRY_ES2015)
parser_check_invalid_new_target (context_p, opcode);
#endif /* ENABLED (JERRY_ES2015) */
parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR);
}
parser_emit_cbc (context_p, (uint16_t) opcode);
} /* parser_emit_unary_lvalue_opcode */
/**
* Parse array literal.
*/
static void
parser_parse_array_literal (parser_context_t *context_p) /**< context */
{
uint32_t pushed_items = 0;
uint16_t opcode = (uint16_t) CBC_ARRAY_APPEND;
JERRY_ASSERT (context_p->token.type == LEXER_LEFT_SQUARE);
parser_emit_cbc (context_p, CBC_CREATE_ARRAY);
lexer_next_token (context_p);
while (true)
{
if (context_p->token.type == LEXER_RIGHT_SQUARE)
{
if (pushed_items > 0)
{
parser_emit_cbc_call (context_p, opcode, pushed_items);
}
return;
}
pushed_items++;
if (context_p->token.type == LEXER_COMMA)
{
parser_emit_cbc (context_p, CBC_PUSH_ELISION);
lexer_next_token (context_p);
}
else
{
#if ENABLED (JERRY_ES2015)
if (context_p->token.type == LEXER_THREE_DOTS)
{
opcode = (uint16_t) (PARSER_TO_EXT_OPCODE (CBC_EXT_SPREAD_ARRAY_APPEND));
pushed_items++;
lexer_next_token (context_p);
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_SPREAD_ELEMENT);
}
#endif /* ENABLED (JERRY_ES2015) */
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
if (context_p->token.type == LEXER_COMMA)
{
lexer_next_token (context_p);
}
else if (context_p->token.type != LEXER_RIGHT_SQUARE)
{
parser_raise_error (context_p, PARSER_ERR_ARRAY_ITEM_SEPARATOR_EXPECTED);
}
}
if (pushed_items >= 64)
{
parser_emit_cbc_call (context_p, opcode, pushed_items);
#if ENABLED (JERRY_ES2015)
opcode = (uint16_t) CBC_ARRAY_APPEND;
#endif /* ENABLED (JERRY_ES2015) */
pushed_items = 0;
}
}
} /* parser_parse_array_literal */
#if !ENABLED (JERRY_ES2015)
/**
* Object literal item types.
*/
typedef enum
{
PARSER_OBJECT_PROPERTY_START, /**< marks the start of the property list */
PARSER_OBJECT_PROPERTY_VALUE, /**< value property */
PARSER_OBJECT_PROPERTY_GETTER, /**< getter property */
PARSER_OBJECT_PROPERTY_SETTER, /**< setter property */
PARSER_OBJECT_PROPERTY_BOTH_ACCESSORS, /**< both getter and setter properties are set */
} parser_object_literal_item_types_t;
/**
* Parse object literal.
*/
static void
parser_append_object_literal_item (parser_context_t *context_p, /**< context */
uint16_t item_index, /**< index of the item name */
parser_object_literal_item_types_t item_type) /**< type of the item */
{
parser_stack_iterator_t iterator;
uint8_t *current_item_type_p;
iterator.current_p = context_p->stack.first_p;
iterator.current_position = context_p->stack.last_position;
while (true)
{
current_item_type_p = iterator.current_p->bytes + iterator.current_position - 1;
if (*current_item_type_p == PARSER_OBJECT_PROPERTY_START)
{
parser_stack_push_uint16 (context_p, item_index);
parser_stack_push_uint8 (context_p, (uint8_t) item_type);
return;
}
iterator.current_position--;
if (iterator.current_position == 0)
{
iterator.current_p = iterator.current_p->next_p;
iterator.current_position = PARSER_STACK_PAGE_SIZE;
}
uint32_t current_item_index = iterator.current_p->bytes[iterator.current_position - 1];
iterator.current_position--;
if (iterator.current_position == 0)
{
iterator.current_p = iterator.current_p->next_p;
iterator.current_position = PARSER_STACK_PAGE_SIZE;
}
current_item_index |= ((uint32_t) iterator.current_p->bytes[iterator.current_position - 1]) << 8;
iterator.current_position--;
if (iterator.current_position == 0)
{
iterator.current_p = iterator.current_p->next_p;
iterator.current_position = PARSER_STACK_PAGE_SIZE;
}
if (current_item_index == item_index)
{
if (item_type == PARSER_OBJECT_PROPERTY_VALUE
&& *current_item_type_p == PARSER_OBJECT_PROPERTY_VALUE
&& !(context_p->status_flags & PARSER_IS_STRICT))
{
return;
}
if (item_type == PARSER_OBJECT_PROPERTY_GETTER
&& *current_item_type_p == PARSER_OBJECT_PROPERTY_SETTER)
{
break;
}
if (item_type == PARSER_OBJECT_PROPERTY_SETTER
&& *current_item_type_p == PARSER_OBJECT_PROPERTY_GETTER)
{
break;
}
parser_raise_error (context_p, PARSER_ERR_OBJECT_PROPERTY_REDEFINED);
}
}
uint8_t *last_page_p = context_p->stack.first_p->bytes;
*current_item_type_p = PARSER_OBJECT_PROPERTY_BOTH_ACCESSORS;
if (current_item_type_p == (last_page_p + context_p->stack.last_position - 1))
{
context_p->stack_top_uint8 = PARSER_OBJECT_PROPERTY_BOTH_ACCESSORS;
}
} /* parser_append_object_literal_item */
#endif /* !ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_ES2015)
/** Forward definition of parse array initializer. */
static void
parser_parse_array_initializer (parser_context_t *context_p, parser_pattern_flags_t flags);
/** Forward definition of parse object initializer. */
static void
parser_parse_object_initializer (parser_context_t *context_p, parser_pattern_flags_t flags);
/**
* Description of "get" literal string.
*/
static const lexer_lit_location_t lexer_get_literal =
{
(const uint8_t *) "get", 3, LEXER_STRING_LITERAL, false
};
/**
* Description of "set" literal string.
*/
static const lexer_lit_location_t lexer_set_literal =
{
(const uint8_t *) "set", 3, LEXER_STRING_LITERAL, false
};
/**
* Class literal parsing options.
*/
typedef enum
{
PARSER_CLASS_LITERAL_NO_OPTS = 0, /**< no options are provided */
PARSER_CLASS_LITERAL_CTOR_PRESENT = (1 << 0), /**< class constructor is present */
PARSER_CLASS_LITERAL_HERTIAGE_PRESENT = (1 << 1), /**< class heritage is present */
} parser_class_literal_opts_t;
/**
* Parse class literal.
*/
static void
parser_parse_class_literal (parser_context_t *context_p, /**< context */
parser_class_literal_opts_t opts) /**< class literal parsing options */
{
JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE);
uint32_t status_flags = PARSER_FUNCTION_CLOSURE | PARSER_ALLOW_SUPER;
lexer_literal_t *ctor_literal_p = NULL;
if (opts & PARSER_CLASS_LITERAL_CTOR_PRESENT)
{
if (context_p->literal_count >= PARSER_MAXIMUM_NUMBER_OF_LITERALS)
{
parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
}
ctor_literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
ctor_literal_p->type = LEXER_UNUSED_LITERAL;
ctor_literal_p->status_flags = 0;
parser_emit_cbc_literal (context_p, CBC_PUSH_LITERAL, (uint16_t) (context_p->literal_count++));
}
else if (opts & PARSER_CLASS_LITERAL_HERTIAGE_PRESENT)
{
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_IMPLICIT_CONSTRUCTOR_HERITAGE);
}
else
{
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_IMPLICIT_CONSTRUCTOR);
}
parser_emit_cbc_ext (context_p, CBC_EXT_INIT_CLASS);
bool is_static = false;
while (true)
{
if (!is_static)
{
lexer_skip_empty_statements (context_p);
}
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_CLASS_METHOD);
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
break;
}
bool is_computed = false;
if (context_p->token.type == LEXER_PROPERTY_GETTER || context_p->token.type == LEXER_PROPERTY_SETTER)
{
uint16_t literal_index, function_literal_index;
bool is_getter = (context_p->token.type == LEXER_PROPERTY_GETTER);
if (lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
{
lexer_construct_literal_object (context_p,
(is_getter ? (lexer_lit_location_t *) &lexer_get_literal
: (lexer_lit_location_t *) &lexer_set_literal),
LEXER_STRING_LITERAL);
goto parse_class_method;
}
uint32_t accessor_status_flags = status_flags;
accessor_status_flags |= (is_getter ? PARSER_IS_PROPERTY_GETTER : PARSER_IS_PROPERTY_SETTER);
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_CLASS_METHOD | LEXER_OBJ_IDENT_ONLY_IDENTIFIERS);
literal_index = context_p->lit_object.index;
if (context_p->token.type == LEXER_RIGHT_SQUARE)
{
is_computed = true;
}
else if (!is_static
&& LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type)
&& lexer_compare_literal_to_string (context_p, "constructor", 11))
{
parser_raise_error (context_p, PARSER_ERR_CLASS_CONSTRUCTOR_AS_ACCESSOR);
}
function_literal_index = lexer_construct_function_object (context_p, accessor_status_flags);
parser_emit_cbc_literal (context_p,
CBC_PUSH_LITERAL,
literal_index);
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
cbc_ext_opcode_t opcode;
if (is_computed)
{
context_p->last_cbc.literal_index = function_literal_index;
if (is_getter)
{
opcode = is_static ? CBC_EXT_SET_STATIC_COMPUTED_GETTER : CBC_EXT_SET_COMPUTED_GETTER;
}
else
{
opcode = is_static ? CBC_EXT_SET_STATIC_COMPUTED_SETTER : CBC_EXT_SET_COMPUTED_SETTER;
}
}
else
{
context_p->last_cbc.value = function_literal_index;
if (is_getter)
{
opcode = is_static ? CBC_EXT_SET_STATIC_GETTER : CBC_EXT_SET_GETTER;
}
else
{
opcode = is_static ? CBC_EXT_SET_STATIC_SETTER : CBC_EXT_SET_SETTER;
}
}
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (opcode);
is_static = false;
continue;
}
if (!is_static)
{
if (context_p->token.type == LEXER_KEYW_STATIC)
{
is_static = true;
continue;
}
if (context_p->token.type == LEXER_CLASS_CONSTRUCTOR)
{
JERRY_ASSERT (opts & PARSER_CLASS_LITERAL_CTOR_PRESENT);
JERRY_ASSERT (ctor_literal_p != NULL);
if (ctor_literal_p->type == LEXER_FUNCTION_LITERAL)
{
/* 14.5.1 */
parser_raise_error (context_p, PARSER_ERR_MULTIPLE_CLASS_CONSTRUCTORS);
}
uint32_t constructor_status_flags = (status_flags
| PARSER_CLASS_CONSTRUCTOR
| PARSER_LEXICAL_ENV_NEEDED);
if (opts & PARSER_CLASS_LITERAL_HERTIAGE_PRESENT)
{
constructor_status_flags |= PARSER_ALLOW_SUPER_CALL;
}
parser_flush_cbc (context_p);
ecma_compiled_code_t *compiled_code_p = parser_parse_function (context_p, constructor_status_flags);
ctor_literal_p->u.bytecode_p = compiled_code_p;
ctor_literal_p->type = LEXER_FUNCTION_LITERAL;
continue;
}
}
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)
{
is_computed = true;
}
else if (LEXER_IS_IDENT_OR_STRING (context_p->token.lit_location.type))
{
if (is_static)
{
if (lexer_compare_literal_to_string (context_p, "prototype", 9))
{
parser_raise_error (context_p, PARSER_ERR_CLASS_STATIC_PROTOTYPE);
}
}
else if ((status_flags & PARSER_IS_GENERATOR_FUNCTION)
&& lexer_compare_literal_to_string (context_p, "constructor", 11))
{
parser_raise_error (context_p, PARSER_ERR_CLASS_CONSTRUCTOR_AS_GENERATOR);
}
}
parse_class_method:
; /* Empty statement to make compiler happy. */
uint16_t literal_index = context_p->lit_object.index;
uint16_t function_literal_index = lexer_construct_function_object (context_p, status_flags);
parser_emit_cbc_literal (context_p,
CBC_PUSH_LITERAL,
function_literal_index);
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
context_p->last_cbc.value = literal_index;
if (is_static)
{
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (is_computed ? CBC_EXT_SET_STATIC_COMPUTED_PROPERTY_LITERAL
: CBC_EXT_SET_STATIC_PROPERTY_LITERAL);
is_static = false;
}
else
{
context_p->last_cbc_opcode = (is_computed ? PARSER_TO_EXT_OPCODE (CBC_EXT_SET_COMPUTED_PROPERTY_LITERAL)
: CBC_SET_LITERAL_PROPERTY);
}
}
} /* parser_parse_class_literal */
/**
* Parse class statement or expression.
*/
void
parser_parse_class (parser_context_t *context_p, /**< context */
bool is_statement) /**< true - if class is parsed as a statement
* false - otherwise (as an expression) */
{
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_CLASS);
uint16_t class_ident_index = PARSER_MAXIMUM_NUMBER_OF_LITERALS;
uint16_t class_name_index = PARSER_MAXIMUM_NUMBER_OF_LITERALS;
parser_class_literal_opts_t opts = PARSER_CLASS_LITERAL_NO_OPTS;
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_CLASS_CONSTRUCTOR);
scanner_release_next (context_p, sizeof (scanner_info_t));
opts |= PARSER_CLASS_LITERAL_CTOR_PRESENT;
}
if (is_statement)
{
/* Class statement must contain an identifier. */
lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL);
JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL);
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED);
parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED);
}
class_ident_index = context_p->lit_object.index;
lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_STRING_LITERAL);
class_name_index = context_p->lit_object.index;
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
parser_module_append_export_name (context_p);
context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_STORE_IDENT);
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
lexer_next_token (context_p);
}
else
{
lexer_next_token (context_p);
/* Class expression may contain an identifier. */
if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
{
/* NOTE: If 'Function.name' will be supported, the current literal object must be set to 'name' property. */
lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_STRING_LITERAL);
class_name_index = context_p->lit_object.index;
lexer_next_token (context_p);
}
}
if (class_name_index != PARSER_MAXIMUM_NUMBER_OF_LITERALS)
{
parser_emit_cbc_ext_literal (context_p, CBC_EXT_PUSH_NAMED_CLASS_ENV, class_name_index);
}
else
{
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_ANONYMOUS_CLASS_ENV);
}
if (context_p->token.type == LEXER_KEYW_EXTENDS)
{
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR | PARSE_EXPR_LEFT_HAND_SIDE);
opts |= PARSER_CLASS_LITERAL_HERTIAGE_PRESENT;
}
else
{
/* Elisions represents that the classHeritage is not present */
parser_emit_cbc (context_p, CBC_PUSH_ELISION);
}
if (context_p->token.type != LEXER_LEFT_BRACE)
{
parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED);
}
bool is_strict = context_p->status_flags & PARSER_IS_STRICT;
/* 14.5. A ClassBody is always strict code. */
context_p->status_flags |= PARSER_IS_STRICT;
/* ClassDeclaration is parsed. Continue with class body. */
parser_parse_class_literal (context_p, opts);
if (class_name_index != PARSER_MAXIMUM_NUMBER_OF_LITERALS)
{
parser_emit_cbc_ext_literal (context_p, CBC_EXT_FINALIZE_NAMED_CLASS, class_name_index);
}
else
{
parser_emit_cbc_ext (context_p, CBC_EXT_FINALIZE_ANONYMOUS_CLASS);
}
if (is_statement)
{
parser_emit_cbc_literal (context_p,
class_ident_index >= PARSER_REGISTER_START ? CBC_MOV_IDENT : CBC_ASSIGN_LET_CONST,
class_ident_index);
}
parser_flush_cbc (context_p);
if (!is_strict)
{
/* Restore flag */
context_p->status_flags &= (uint32_t) ~PARSER_IS_STRICT;
}
context_p->status_flags &= (uint32_t) ~PARSER_ALLOW_SUPER;
lexer_next_token (context_p);
} /* parser_parse_class */
#endif /* ENABLED (JERRY_ES2015) */
#if ENABLED (JERRY_ES2015)
/**
* Parse object initializer method definition.
*
* See also: ES2015 14.3
*/
static void
parser_parse_object_method (parser_context_t *context_p) /**< context */
{
context_p->source_p--;
context_p->column--;
uint16_t function_literal_index = lexer_construct_function_object (context_p, PARSER_FUNCTION_CLOSURE);
parser_emit_cbc_literal (context_p,
CBC_PUSH_LITERAL,
function_literal_index);
lexer_next_token (context_p);
} /* parser_parse_object_method */
/**
* Reparse the current literal as a common identifier.
*/
static void
parser_reparse_as_common_identifier (parser_context_t *context_p, /**< context */
parser_line_counter_t start_line, /**< start line */
parser_line_counter_t start_column) /**< start column */
{
context_p->source_p = context_p->token.lit_location.char_p;
context_p->line = start_line;
context_p->column = start_column;
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LITERAL
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
}
lexer_construct_literal_object (context_p,
&context_p->token.lit_location,
LEXER_IDENT_LITERAL);
} /* parser_reparse_as_common_identifier */
#endif /* ENABLED (JERRY_ES2015) */
/**
* Parse object literal.
*/
static void
parser_parse_object_literal (parser_context_t *context_p) /**< context */
{
JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE);
parser_emit_cbc (context_p, CBC_CREATE_OBJECT);
#if !ENABLED (JERRY_ES2015)
parser_stack_push_uint8 (context_p, PARSER_OBJECT_PROPERTY_START);
#endif /* !ENABLED (JERRY_ES2015) */
while (true)
{
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_NO_OPTS);
switch (context_p->token.type)
{
case LEXER_RIGHT_BRACE:
{
break;
}
case LEXER_PROPERTY_GETTER:
case LEXER_PROPERTY_SETTER:
{
uint32_t status_flags;
cbc_ext_opcode_t opcode;
#if !ENABLED (JERRY_ES2015)
parser_object_literal_item_types_t item_type;
#endif /* !ENABLED (JERRY_ES2015) */
if (context_p->token.type == LEXER_PROPERTY_GETTER)
{
status_flags = PARSER_FUNCTION_CLOSURE | PARSER_IS_PROPERTY_GETTER;
opcode = CBC_EXT_SET_GETTER;
#if !ENABLED (JERRY_ES2015)
item_type = PARSER_OBJECT_PROPERTY_GETTER;
#endif /* !ENABLED (JERRY_ES2015) */
}
else
{
status_flags = PARSER_FUNCTION_CLOSURE | PARSER_IS_PROPERTY_SETTER;
opcode = CBC_EXT_SET_SETTER;
#if !ENABLED (JERRY_ES2015)
item_type = PARSER_OBJECT_PROPERTY_SETTER;
#endif /* !ENABLED (JERRY_ES2015) */
}
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS);
/* This assignment is a nop for computed getters/setters. */
uint16_t literal_index = context_p->lit_object.index;
#if ENABLED (JERRY_ES2015)
if (context_p->token.type == LEXER_RIGHT_SQUARE)
{
opcode = ((opcode == CBC_EXT_SET_GETTER) ? CBC_EXT_SET_COMPUTED_GETTER
: CBC_EXT_SET_COMPUTED_SETTER);
}
#else /* !ENABLED (JERRY_ES2015) */
parser_append_object_literal_item (context_p, literal_index, item_type);
#endif /* ENABLED (JERRY_ES2015) */
uint16_t function_literal_index = lexer_construct_function_object (context_p, status_flags);
#if ENABLED (JERRY_ES2015)
if (opcode >= CBC_EXT_SET_COMPUTED_GETTER)
{
literal_index = function_literal_index;
}
#endif /* ENABLED (JERRY_ES2015) */
parser_emit_cbc_literal (context_p,
CBC_PUSH_LITERAL,
literal_index);
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (opcode);
context_p->last_cbc.value = function_literal_index;
lexer_next_token (context_p);
break;
}
#if ENABLED (JERRY_ES2015)
case LEXER_RIGHT_SQUARE:
{
lexer_next_token (context_p);
if (context_p->token.type == LEXER_LEFT_PAREN)
{
parser_parse_object_method (context_p);
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SET_COMPUTED_PROPERTY_LITERAL);
break;
}
if (context_p->token.type != LEXER_COLON)
{
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
}
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SET_COMPUTED_PROPERTY_LITERAL);
}
else
{
parser_emit_cbc_ext (context_p, CBC_EXT_SET_COMPUTED_PROPERTY);
}
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;
/* This assignment is a nop for CBC_EXT_SET_COMPUTED_PROPERTY_LITERAL. */
uint16_t literal_index = context_p->lit_object.index;
if (context_p->token.type == LEXER_RIGHT_SQUARE)
{
opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SET_COMPUTED_PROPERTY_LITERAL);
}
uint16_t function_literal_index = lexer_construct_function_object (context_p, status_flags);
parser_emit_cbc_literal (context_p,
CBC_PUSH_LITERAL,
function_literal_index);
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
context_p->last_cbc_opcode = opcode;
context_p->last_cbc.value = literal_index;
lexer_next_token (context_p);
break;
}
#endif /* ENABLED (JERRY_ES2015) */
default:
{
uint16_t literal_index = context_p->lit_object.index;
#if ENABLED (JERRY_ES2015)
parser_line_counter_t start_line = context_p->token.line;
parser_line_counter_t start_column = context_p->token.column;
#else /* !ENABLED (JERRY_ES2015) */
parser_append_object_literal_item (context_p,
literal_index,
PARSER_OBJECT_PROPERTY_VALUE);
#endif /* ENABLED (JERRY_ES2015) */
lexer_next_token (context_p);
#if ENABLED (JERRY_ES2015)
if (context_p->token.type == LEXER_LEFT_PAREN)
{
parser_parse_object_method (context_p);
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
context_p->last_cbc_opcode = CBC_SET_LITERAL_PROPERTY;
context_p->last_cbc.value = literal_index;
break;
}
if (context_p->token.type == LEXER_RIGHT_BRACE
|| context_p->token.type == LEXER_COMMA)
{
parser_reparse_as_common_identifier (context_p, start_line, start_column);
parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
context_p->last_cbc_opcode = CBC_SET_LITERAL_PROPERTY;
context_p->last_cbc.value = literal_index;
lexer_next_token (context_p);
break;
}
#endif /* ENABLED (JERRY_ES2015) */
if (context_p->token.type != LEXER_COLON)
{
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
}
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
context_p->last_cbc_opcode = CBC_SET_LITERAL_PROPERTY;
context_p->last_cbc.value = literal_index;
}
else
{
parser_emit_cbc_literal (context_p, CBC_SET_PROPERTY, literal_index);
}
break;
}
}
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
break;
}
else if (context_p->token.type != LEXER_COMMA)
{
parser_raise_error (context_p, PARSER_ERR_OBJECT_ITEM_SEPARATOR_EXPECTED);
}
}
#if !ENABLED (JERRY_ES2015)
while (context_p->stack_top_uint8 != PARSER_OBJECT_PROPERTY_START)
{
parser_stack_pop (context_p, NULL, 3);
}
parser_stack_pop_uint8 (context_p);
#endif /* !ENABLED (JERRY_ES2015) */
} /* parser_parse_object_literal */
/**
* Parse function literal.
*/
static void
parser_parse_function_expression (parser_context_t *context_p, /**< context */
uint32_t status_flags) /**< function status flags */
{
int literals = 0;
uint16_t literal1 = 0;
uint16_t literal2 = 0;
uint16_t function_literal_index;
int32_t function_name_index = -1;
if (status_flags & PARSER_IS_FUNC_EXPRESSION)
{
#if ENABLED (JERRY_DEBUGGER)
parser_line_counter_t debugger_line = context_p->token.line;
parser_line_counter_t debugger_column = context_p->token.column;
#endif /* ENABLED (JERRY_DEBUGGER) */
#if ENABLED (JERRY_ES2015)
uint32_t parent_status_flags = context_p->status_flags;
if (lexer_check_next_character (context_p, LIT_CHAR_ASTERISK))
{
/* The name of the function cannot be yield. */
context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD;
status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD;
lexer_consume_next_character (context_p);
}
else
{
context_p->status_flags &= (uint32_t) ~(PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_YIELD);
}
#endif /* ENABLED (JERRY_ES2015) */
if (!lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
{
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LITERAL
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
}
parser_flush_cbc (context_p);
lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_STRING_LITERAL);
#if ENABLED (JERRY_DEBUGGER)
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
{
jerry_debugger_send_string (JERRY_DEBUGGER_FUNCTION_NAME,
JERRY_DEBUGGER_NO_SUBTYPE,
context_p->lit_object.literal_p->u.char_p,
context_p->lit_object.literal_p->prop.length);
/* Reset token position for the function. */
context_p->token.line = debugger_line;
context_p->token.column = debugger_column;
}
#endif /* ENABLED (JERRY_DEBUGGER) */
if (context_p->token.keyword_type >= LEXER_FIRST_NON_STRICT_ARGUMENTS)
{
status_flags |= PARSER_HAS_NON_STRICT_ARG;
}
function_name_index = context_p->lit_object.index;
}
#if ENABLED (JERRY_ES2015)
context_p->status_flags = parent_status_flags;
#endif /* ENABLED (JERRY_ES2015) */
}
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
literals = 1;
literal1 = context_p->last_cbc.literal_index;
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
}
else if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS)
{
literals = 2;
literal1 = context_p->last_cbc.literal_index;
literal2 = context_p->last_cbc.value;
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
}
function_literal_index = lexer_construct_function_object (context_p, status_flags);
JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE);
if (literals == 1)
{
context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS;
context_p->last_cbc.literal_index = literal1;
context_p->last_cbc.value = function_literal_index;
}
else if (literals == 2)
{
context_p->last_cbc_opcode = CBC_PUSH_THREE_LITERALS;
context_p->last_cbc.literal_index = literal1;
context_p->last_cbc.value = literal2;
context_p->last_cbc.third_literal_index = function_literal_index;
}
else
{
parser_emit_cbc_literal (context_p,
CBC_PUSH_LITERAL,
function_literal_index);
if (function_name_index != -1)
{
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_NAMED_FUNC_EXPRESSION);
context_p->last_cbc.value = (uint16_t) function_name_index;
}
}
context_p->last_cbc.literal_type = LEXER_FUNCTION_LITERAL;
context_p->last_cbc.literal_keyword_type = LEXER_EOS;
} /* parser_parse_function_expression */
#if ENABLED (JERRY_ES2015)
/**
* Parse template literal.
*/
static void
parser_parse_template_literal (parser_context_t *context_p) /**< context */
{
bool is_empty_head = true;
if (context_p->token.lit_location.length > 0)
{
is_empty_head = false;
lexer_construct_literal_object (context_p,
&context_p->token.lit_location,
context_p->token.lit_location.type);
parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
}
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR);
if (context_p->token.type != LEXER_RIGHT_BRACE)
{
parser_raise_error (context_p, PARSER_ERR_RIGHT_BRACE_EXPECTED);
}
if (!is_empty_head)
{
if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS)
{
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_STRING_CONCAT_TWO_LITERALS);
}
else if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_STRING_CONCAT_RIGHT_LITERAL);
}
else
{
parser_emit_cbc_ext (context_p, CBC_EXT_STRING_CONCAT);
}
}
context_p->source_p--;
context_p->column--;
lexer_parse_string (context_p, LEXER_STRING_NO_OPTS);
if (is_empty_head || context_p->token.lit_location.length > 0)
{
lexer_construct_literal_object (context_p,
&context_p->token.lit_location,
context_p->token.lit_location.type);
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_STRING_CONCAT_TWO_LITERALS);
context_p->last_cbc.value = context_p->lit_object.index;
context_p->last_cbc.literal_type = context_p->token.lit_location.type;
context_p->last_cbc.literal_keyword_type = context_p->token.keyword_type;
}
else
{
parser_emit_cbc_ext_literal_from_token (context_p, CBC_EXT_STRING_CONCAT_RIGHT_LITERAL);
}
}
while (context_p->source_p[-1] != LIT_CHAR_GRAVE_ACCENT)
{
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR);
if (context_p->token.type != LEXER_RIGHT_BRACE)
{
parser_raise_error (context_p, PARSER_ERR_RIGHT_BRACE_EXPECTED);
}
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_STRING_CONCAT_RIGHT_LITERAL);
}
else
{
parser_emit_cbc_ext (context_p, CBC_EXT_STRING_CONCAT);
}
context_p->source_p--;
context_p->column--;
lexer_parse_string (context_p, LEXER_STRING_NO_OPTS);
if (context_p->token.lit_location.length > 0)
{
lexer_construct_literal_object (context_p,
&context_p->token.lit_location,
context_p->token.lit_location.type);
parser_emit_cbc_ext_literal_from_token (context_p, CBC_EXT_STRING_CONCAT_RIGHT_LITERAL);
}
}
} /* parser_parse_template_literal */
/**
* Parse tagged template literal.
*/
static size_t
parser_parse_tagged_template_literal (parser_context_t *context_p) /**< context */
{
JERRY_ASSERT (context_p->token.type == LEXER_TEMPLATE_LITERAL);
uint32_t call_arguments = 0;
ecma_collection_t *collection_p;
if (context_p->tagged_template_literal_cp == JMEM_CP_NULL)
{
collection_p = ecma_new_collection ();
ECMA_SET_INTERNAL_VALUE_POINTER (context_p->tagged_template_literal_cp, collection_p);
}
else
{
collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_collection_t, context_p->tagged_template_literal_cp);
if (collection_p->item_count > CBC_MAXIMUM_BYTE_VALUE)
{
parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIMIT_REACHED);
}
}
const uint32_t tagged_id = collection_p->item_count;
uint32_t prop_idx = 0;
ecma_object_t *raw_strings_p;
ecma_object_t *template_obj_p = parser_new_tagged_template_literal (&raw_strings_p);
ecma_collection_push_back (collection_p, ecma_make_object_value (template_obj_p));
parser_tagged_template_literal_append_strings (context_p, template_obj_p, raw_strings_p, prop_idx++);
call_arguments++;
parser_emit_cbc_ext_call (context_p, CBC_EXT_GET_TAGGED_TEMPLATE_LITERAL, tagged_id);
while (context_p->source_p[-1] != LIT_CHAR_GRAVE_ACCENT)
{
JERRY_ASSERT (context_p->source_p[-1] == LIT_CHAR_LEFT_BRACE);
lexer_next_token (context_p);
if (++call_arguments > CBC_MAXIMUM_BYTE_VALUE)
{
parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIMIT_REACHED);
}
parser_parse_expression (context_p, PARSE_EXPR);
if (context_p->token.type != LEXER_RIGHT_BRACE)
{
parser_raise_error (context_p, PARSER_ERR_RIGHT_BRACE_EXPECTED);
}
context_p->source_p--;
context_p->column--;
lexer_parse_string (context_p, LEXER_STRING_NO_OPTS);
parser_tagged_template_literal_append_strings (context_p, template_obj_p, raw_strings_p, prop_idx++);
}
parser_tagged_template_literal_finalize (template_obj_p, raw_strings_p);
return call_arguments;
} /* parser_parse_tagged_template_literal */
/**
* Throws an error if the current expression is not an assignment expression.
*/
static inline void JERRY_ATTR_ALWAYS_INLINE
parser_check_assignment_expr (parser_context_t *context_p)
{
if (context_p->stack_top_uint8 != LEXER_EXPRESSION_START
&& context_p->stack_top_uint8 != LEXER_LEFT_PAREN
&& context_p->stack_top_uint8 != LEXER_COMMA_SEP_LIST
&& !LEXER_IS_BINARY_LVALUE_TOKEN (context_p->stack_top_uint8))
{
parser_raise_error (context_p, PARSER_ERR_ASSIGNMENT_EXPECTED);
}
} /* parser_check_assignment_expr */
/**
* Checks whether the next token is a valid continuation token after an arrow function.
*/
static inline bool JERRY_ATTR_ALWAYS_INLINE
parser_abort_parsing_after_arrow (parser_context_t *context_p)
{
return (context_p->token.type != LEXER_RIGHT_PAREN
&& context_p->token.type != LEXER_COMMA);
} /* parser_abort_parsing_after_arrow */
#endif /* ENABLED (JERRY_ES2015) */
/**
* Parse and record unary operators, and parse the primary literal.
*
* @return true if parsing should be aborted, true otherwise
*/
static bool
parser_parse_unary_expression (parser_context_t *context_p, /**< context */
size_t *grouping_level_p) /**< grouping level */
{
bool new_was_seen = false;
/* Collect unary operators. */
while (true)
{
/* Convert plus and minus binary operators to unary operators. */
if (context_p->token.type == LEXER_ADD)
{
context_p->token.type = LEXER_PLUS;
}
else if (context_p->token.type == LEXER_SUBTRACT)
{
context_p->token.type = LEXER_NEGATE;
}
/* Bracketed expressions are primary expressions. At this
* point their left paren is pushed onto the stack and
* they are processed when their closing paren is reached. */
if (context_p->token.type == LEXER_LEFT_PAREN)
{
#if ENABLED (JERRY_ES2015)
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION);
break;
}
#endif /* ENABLED (JERRY_ES2015) */
(*grouping_level_p) += PARSER_GROUPING_LEVEL_INCREASE;
new_was_seen = false;
}
else if (context_p->token.type == LEXER_KEYW_NEW)
{
/* After 'new' unary operators are not allowed. */
new_was_seen = true;
#if ENABLED (JERRY_ES2015)
/* Check if "new.target" is written here. */
if (scanner_try_scan_new_target (context_p))
{
if (!(context_p->status_flags & PARSER_ALLOW_NEW_TARGET))
{
parser_raise_error (context_p, PARSER_ERR_NEW_TARGET_NOT_ALLOWED);
}
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_NEW_TARGET);
lexer_next_token (context_p);
/* Found "new.target" return here */
return false;
}
#endif /* ENABLED (JERRY_ES2015) */
}
else if (new_was_seen
|| (*grouping_level_p == PARSE_EXPR_LEFT_HAND_SIDE)
|| !LEXER_IS_UNARY_OP_TOKEN (context_p->token.type))
{
break;
}
parser_stack_push_uint8 (context_p, context_p->token.type);
lexer_next_token (context_p);
}
/* Parse primary expression. */
switch (context_p->token.type)
{
#if ENABLED (JERRY_ES2015)
case LEXER_TEMPLATE_LITERAL:
{
if (context_p->source_p[-1] != LIT_CHAR_GRAVE_ACCENT)
{
parser_parse_template_literal (context_p);
break;
}
/* The string is a normal string literal. */
/* FALLTHRU */
}
#endif /* ENABLED (JERRY_ES2015) */
case LEXER_LITERAL:
{
#if ENABLED (JERRY_ES2015)
if (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_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);
return parser_abort_parsing_after_arrow (context_p);
}
#endif /* ENABLED (JERRY_ES2015) */
uint8_t type = context_p->token.lit_location.type;
if (type == LEXER_IDENT_LITERAL || type == LEXER_STRING_LITERAL)
{
lexer_construct_literal_object (context_p,
&context_p->token.lit_location,
context_p->token.lit_location.type);
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
if ((context_p->status_flags & PARSER_MODULE_STORE_IDENT)
&& type == LEXER_IDENT_LITERAL)
{
context_p->module_identifier_lit_p = context_p->lit_object.literal_p;
context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_STORE_IDENT);
}
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
}
else if (type == LEXER_NUMBER_LITERAL)
{
bool is_negative_number = false;
while (context_p->stack_top_uint8 == LEXER_PLUS
|| context_p->stack_top_uint8 == LEXER_NEGATE)
{
if (context_p->stack_top_uint8 == LEXER_NEGATE)
{
is_negative_number = !is_negative_number;
}
parser_stack_pop_uint8 (context_p);
}
if (lexer_construct_number_object (context_p, true, is_negative_number))
{
JERRY_ASSERT (context_p->lit_object.index <= CBC_PUSH_NUMBER_BYTE_RANGE_END);
parser_emit_cbc_push_number (context_p, is_negative_number);
break;
}
}
cbc_opcode_t opcode = CBC_PUSH_LITERAL;
if (context_p->token.keyword_type != LEXER_KEYW_EVAL)
{
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS;
context_p->last_cbc.value = context_p->lit_object.index;
context_p->last_cbc.literal_type = context_p->token.lit_location.type;
context_p->last_cbc.literal_keyword_type = context_p->token.keyword_type;
break;
}
if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS)
{
context_p->last_cbc_opcode = CBC_PUSH_THREE_LITERALS;
context_p->last_cbc.third_literal_index = context_p->lit_object.index;
context_p->last_cbc.literal_type = context_p->token.lit_location.type;
context_p->last_cbc.literal_keyword_type = context_p->token.keyword_type;
break;
}
if (context_p->last_cbc_opcode == CBC_PUSH_THIS)
{
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
opcode = CBC_PUSH_THIS_LITERAL;
}
}
parser_emit_cbc_literal_from_token (context_p, (uint16_t) opcode);
break;
}
case LEXER_KEYW_FUNCTION:
{
parser_parse_function_expression (context_p, PARSER_FUNCTION_CLOSURE | PARSER_IS_FUNC_EXPRESSION);
break;
}
case LEXER_LEFT_BRACE:
{
#if ENABLED (JERRY_ES2015)
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER);
parser_parse_object_initializer (context_p, PARSER_PATTERN_NO_OPTS);
return false;
}
#endif /* ENABLED (JERRY_ES2015) */
parser_parse_object_literal (context_p);
break;
}
case LEXER_LEFT_SQUARE:
{
#if ENABLED (JERRY_ES2015)
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER);
parser_parse_array_initializer (context_p, PARSER_PATTERN_NO_OPTS);
return false;
}
#endif /* ENABLED (JERRY_ES2015) */
parser_parse_array_literal (context_p);
break;
}
case LEXER_DIVIDE:
case LEXER_ASSIGN_DIVIDE:
{
lexer_construct_regexp_object (context_p, false);
uint16_t literal_index = (uint16_t) (context_p->literal_count - 1);
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS;
context_p->last_cbc.value = literal_index;
}
else if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS)
{
context_p->last_cbc_opcode = CBC_PUSH_THREE_LITERALS;
context_p->last_cbc.third_literal_index = literal_index;
}
else
{
parser_emit_cbc_literal (context_p, CBC_PUSH_LITERAL, literal_index);
}
context_p->last_cbc.literal_type = LEXER_REGEXP_LITERAL;
context_p->last_cbc.literal_keyword_type = LEXER_EOS;
break;
}
case LEXER_KEYW_THIS:
{
#if ENABLED (JERRY_ES2015)
if (context_p->status_flags & PARSER_ALLOW_SUPER_CALL)
{
parser_emit_cbc_ext (context_p, CBC_EXT_RESOLVE_LEXICAL_THIS);
}
else
{
#endif /* ENABLED (JERRY_ES2015) */
parser_emit_cbc (context_p, CBC_PUSH_THIS);
#if ENABLED (JERRY_ES2015)
}
#endif /* ENABLED (JERRY_ES2015) */
break;
}
case LEXER_LIT_TRUE:
{
parser_emit_cbc (context_p, CBC_PUSH_TRUE);
break;
}
case LEXER_LIT_FALSE:
{
parser_emit_cbc (context_p, CBC_PUSH_FALSE);
break;
}
case LEXER_LIT_NULL:
{
parser_emit_cbc (context_p, CBC_PUSH_NULL);
break;
}
#if ENABLED (JERRY_ES2015)
case LEXER_KEYW_CLASS:
{
parser_parse_class (context_p, false);
return false;
}
case LEXER_KEYW_SUPER:
{
if (context_p->status_flags & PARSER_ALLOW_SUPER)
{
if (lexer_check_next_characters (context_p, LIT_CHAR_DOT, LIT_CHAR_LEFT_SQUARE))
{
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_SUPER);
break;
}
if (lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN)
&& (context_p->status_flags & PARSER_ALLOW_SUPER_CALL))
{
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_SUPER_CONSTRUCTOR);
break;
}
}
parser_raise_error (context_p, PARSER_ERR_UNEXPECTED_SUPER_KEYWORD);
}
case LEXER_LEFT_PAREN:
{
JERRY_ASSERT (context_p->next_scanner_info_p->source_p == context_p->source_p
&& context_p->next_scanner_info_p->type == SCANNER_TYPE_FUNCTION);
parser_check_assignment_expr (context_p);
context_p->token.type = LEXER_ARROW_LEFT_PAREN;
parser_parse_function_expression (context_p, PARSER_IS_FUNCTION | PARSER_IS_ARROW_FUNCTION);
return parser_abort_parsing_after_arrow (context_p);
}
case LEXER_KEYW_YIELD:
{
JERRY_ASSERT ((context_p->status_flags & PARSER_IS_GENERATOR_FUNCTION)
&& !(context_p->status_flags & PARSER_DISALLOW_YIELD));
parser_check_assignment_expr (context_p);
lexer_next_token (context_p);
cbc_ext_opcode_t opcode = CBC_EXT_YIELD;
if (!lexer_check_yield_no_arg (context_p))
{
if (context_p->token.type == LEXER_MULTIPLY)
{
lexer_next_token (context_p);
opcode = CBC_EXT_YIELD_ITERATOR;
}
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
}
else
{
parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED);
}
parser_emit_cbc_ext (context_p, opcode);
return (context_p->token.type != LEXER_RIGHT_PAREN
&& context_p->token.type != LEXER_COMMA);
}
#endif /* ENABLED (JERRY_ES2015) */
default:
{
bool is_left_hand_side = (*grouping_level_p == PARSE_EXPR_LEFT_HAND_SIDE);
parser_raise_error (context_p, (is_left_hand_side ? PARSER_ERR_LEFT_HAND_SIDE_EXP_EXPECTED
: PARSER_ERR_PRIMARY_EXP_EXPECTED));
break;
}
}
lexer_next_token (context_p);
return false;
} /* parser_parse_unary_expression */
/**
* Parse the postfix part of unary operators, and
* generate byte code for the whole expression.
*/
static void
parser_process_unary_expression (parser_context_t *context_p, /**< context */
size_t grouping_level) /**< grouping level */
{
/* Parse postfix part of a primary expression. */
while (true)
{
/* Since break would only break the switch, we use
* continue to continue this loop. Without continue,
* the code abandons the loop. */
switch (context_p->token.type)
{
case LEXER_DOT:
{
parser_push_result (context_p);
lexer_expect_identifier (context_p, LEXER_STRING_LITERAL);
JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
&& context_p->lit_object.literal_p->type == LEXER_STRING_LITERAL);
context_p->token.lit_location.type = LEXER_STRING_LITERAL;
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
JERRY_ASSERT (CBC_ARGS_EQ (CBC_PUSH_PROP_LITERAL_LITERAL,
CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2));
context_p->last_cbc_opcode = CBC_PUSH_PROP_LITERAL_LITERAL;
context_p->last_cbc.value = context_p->lit_object.index;
}
else if (context_p->last_cbc_opcode == CBC_PUSH_THIS)
{
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_PROP_THIS_LITERAL);
}
#if ENABLED (JERRY_ES2015)
else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER))
{
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP_LITERAL);
context_p->last_cbc.literal_index = context_p->lit_object.index;
}
#endif /* ENABLED (JERRY_ES2015) */
else
{
parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_PROP_LITERAL);
}
lexer_next_token (context_p);
continue;
}
case LEXER_LEFT_SQUARE:
{
parser_push_result (context_p);
#if ENABLED (JERRY_ES2015)
uint16_t last_cbc_opcode = context_p->last_cbc_opcode;
if (last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER))
{
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
}
#endif /* ENABLED (JERRY_ES2015) */
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR);
if (context_p->token.type != LEXER_RIGHT_SQUARE)
{
parser_raise_error (context_p, PARSER_ERR_RIGHT_SQUARE_EXPECTED);
}
lexer_next_token (context_p);
#if ENABLED (JERRY_ES2015)
if (last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER))
{
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_SUPER_PROP);
continue;
}
#endif /* ENABLED (JERRY_ES2015) */
if (PARSER_IS_MUTABLE_PUSH_LITERAL (context_p->last_cbc_opcode))
{
context_p->last_cbc_opcode = PARSER_PUSH_LITERAL_TO_PUSH_PROP_LITERAL (context_p->last_cbc_opcode);
}
else
{
parser_emit_cbc (context_p, CBC_PUSH_PROP);
}
continue;
}
#if ENABLED (JERRY_ES2015)
case LEXER_TEMPLATE_LITERAL:
#endif /* ENABLED (JERRY_ES2015) */
case LEXER_LEFT_PAREN:
{
size_t call_arguments = 0;
uint16_t opcode = CBC_CALL;
bool is_eval = false;
parser_push_result (context_p);
if (context_p->stack_top_uint8 == LEXER_KEYW_NEW)
{
parser_stack_pop_uint8 (context_p);
opcode = CBC_NEW;
}
else
{
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL
&& context_p->last_cbc.literal_keyword_type == LEXER_KEYW_EVAL
&& context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL)
{
is_eval = true;
}
if (PARSER_IS_PUSH_PROP (context_p->last_cbc_opcode))
{
opcode = CBC_CALL_PROP;
context_p->last_cbc_opcode = PARSER_PUSH_PROP_TO_PUSH_PROP_REFERENCE (context_p->last_cbc_opcode);
}
#if ENABLED (JERRY_ES2015)
else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_CONSTRUCTOR))
{
opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_CALL);
}
else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP_LITERAL))
{
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_PROP_LITERAL_CALL_REFERENCE);
opcode = CBC_CALL_PROP;
}
else if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP))
{
context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_PROP_CALL_REFERENCE);
opcode = CBC_CALL_PROP;
}
#endif /* ENABLED (JERRY_ES2015) */
else if (JERRY_UNLIKELY (context_p->status_flags & PARSER_INSIDE_WITH)
&& PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode)
&& context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL)
{
opcode = CBC_CALL_PROP;
parser_emit_ident_reference (context_p, CBC_PUSH_IDENT_REFERENCE);
parser_emit_cbc_ext (context_p, CBC_EXT_RESOLVE_BASE);
}
}
#if ENABLED (JERRY_ES2015)
bool has_spread_element = false;
if (context_p->token.type == LEXER_TEMPLATE_LITERAL)
{
call_arguments = parser_parse_tagged_template_literal (context_p);
}
else
{
lexer_next_token (context_p);
while (context_p->token.type != LEXER_RIGHT_PAREN)
{
if (++call_arguments > CBC_MAXIMUM_BYTE_VALUE)
{
parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIMIT_REACHED);
}
if (context_p->token.type == LEXER_THREE_DOTS)
{
has_spread_element = true;
call_arguments++;
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_SPREAD_ELEMENT);
lexer_next_token (context_p);
}
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
if (context_p->token.type == LEXER_COMMA)
{
lexer_next_token (context_p);
continue;
}
if (context_p->token.type != LEXER_RIGHT_PAREN)
{
parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
}
break;
}
}
#else /* !ENABLED (JERRY_ES2015) */
lexer_next_token (context_p);
if (context_p->token.type != LEXER_RIGHT_PAREN)
{
while (true)
{
if (++call_arguments > CBC_MAXIMUM_BYTE_VALUE)
{
parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIMIT_REACHED);
}
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
if (context_p->token.type != LEXER_COMMA)
{
break;
}
lexer_next_token (context_p);
}
if (context_p->token.type != LEXER_RIGHT_PAREN)
{
parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
}
}
#endif /* ENABLED (JERRY_ES2015) */
lexer_next_token (context_p);
if (is_eval)
{
#if ENABLED (JERRY_ES2015)
if (context_p->status_flags & (PARSER_ALLOW_SUPER_CALL | PARSER_ALLOW_SUPER | PARSER_ALLOW_NEW_TARGET))
{
parser_emit_cbc_ext_call (context_p,
CBC_EXT_LOCAL_EVAL,
PARSER_SAVE_STATUS_FLAGS (context_p->status_flags));
}
else
{
#endif /* ENABLED (JERRY_ES2015) */
parser_emit_cbc (context_p, CBC_EVAL);
#if ENABLED (JERRY_ES2015)
}
#endif /* ENABLED (JERRY_ES2015) */
}
#if ENABLED (JERRY_ES2015)
if (has_spread_element)
{
uint16_t spread_opcode;
if (opcode == CBC_CALL)
{
spread_opcode = CBC_EXT_SPREAD_CALL;
}
else if (opcode == CBC_CALL_PROP)
{
spread_opcode = CBC_EXT_SPREAD_CALL_PROP;
}
else if (opcode == CBC_NEW)
{
spread_opcode = CBC_EXT_SPREAD_NEW;
}
else
{
/* opcode is unchanged */
JERRY_ASSERT (opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_SUPER_CALL));
spread_opcode = CBC_EXT_SPREAD_SUPER_CALL;
}
parser_emit_cbc_ext_call (context_p, spread_opcode, call_arguments);
continue;
}
#endif /* ENABLED (JERRY_ES2015) */
if (call_arguments <= 1)
{
if (opcode == CBC_CALL)
{
parser_emit_cbc (context_p, (uint16_t) (CBC_CALL0 + (call_arguments * 6)));
continue;
}
if (opcode == CBC_CALL_PROP)
{
parser_emit_cbc (context_p, (uint16_t) (CBC_CALL0_PROP + (call_arguments * 6)));
continue;
}
if (opcode == CBC_NEW)
{
parser_emit_cbc (context_p, (uint16_t) (CBC_NEW0 + call_arguments));
continue;
}
}
if (call_arguments == 2)
{
if (opcode == CBC_CALL)
{
parser_emit_cbc (context_p, CBC_CALL2);
continue;
}
if (opcode == CBC_CALL_PROP)
{
parser_flush_cbc (context_p);
/* Manually adjusting stack usage. */
JERRY_ASSERT (context_p->stack_depth > 0);
context_p->stack_depth--;
parser_emit_cbc (context_p, CBC_CALL2_PROP);
continue;
}
}
parser_emit_cbc_call (context_p, opcode, call_arguments);
continue;
}
default:
{
if (context_p->stack_top_uint8 == LEXER_KEYW_NEW)
{
parser_push_result (context_p);
parser_emit_cbc (context_p, CBC_NEW0);
parser_stack_pop_uint8 (context_p);
continue;
}
if (!(context_p->token.flags & LEXER_WAS_NEWLINE)
&& (context_p->token.type == LEXER_INCREASE || context_p->token.type == LEXER_DECREASE)
&& grouping_level != PARSE_EXPR_LEFT_HAND_SIDE)
{
cbc_opcode_t opcode = (context_p->token.type == LEXER_INCREASE) ? CBC_POST_INCR : CBC_POST_DECR;
parser_push_result (context_p);
parser_emit_unary_lvalue_opcode (context_p, opcode);
lexer_next_token (context_p);
}
break;
}
}
break;
}
/* Generate byte code for the unary operators. */
while (true)
{
uint8_t token = context_p->stack_top_uint8;
if (!LEXER_IS_UNARY_OP_TOKEN (token))
{
break;
}
parser_push_result (context_p);
parser_stack_pop_uint8 (context_p);
if (LEXER_IS_UNARY_LVALUE_OP_TOKEN (token))
{
if (token == LEXER_KEYW_DELETE)
{
token = CBC_DELETE_PUSH_RESULT;
}
else
{
token = (uint8_t) (LEXER_UNARY_LVALUE_OP_TOKEN_TO_OPCODE (token));
}
parser_emit_unary_lvalue_opcode (context_p, (cbc_opcode_t) token);
}
else
{
token = (uint8_t) (LEXER_UNARY_OP_TOKEN_TO_OPCODE (token));
if (token == CBC_TYPEOF)
{
if (PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode)
&& context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL)
{
parser_emit_ident_reference (context_p, CBC_TYPEOF_IDENT);
}
else
{
parser_emit_cbc (context_p, token);
}
}
else
{
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
/* It is not worth to combine with push multiple literals
* since the byte code size will not decrease. */
JERRY_ASSERT (CBC_SAME_ARGS (context_p->last_cbc_opcode, token + 1));
context_p->last_cbc_opcode = (uint16_t) (token + 1);
}
else
{
parser_emit_cbc (context_p, token);
}
}
}
}
} /* parser_process_unary_expression */
/**
* Append a binary '=' token.
*/
static void
parser_append_binary_single_assignment_token (parser_context_t *context_p, /**< context */
uint8_t assign_ident_opcode) /**< assign ident opcode */
{
JERRY_ASSERT (assign_ident_opcode == CBC_ASSIGN_SET_IDENT
|| assign_ident_opcode == CBC_ASSIGN_LET_CONST);
/* Unlike other tokens, the whole byte code is saved for binary
* assignment, since it has multiple forms depending on the
* previous instruction. */
#if ENABLED (JERRY_ES2015)
if (context_p->last_cbc_opcode == PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_SUPER_PROP_LITERAL))
{
context_p->last_cbc_opcode = CBC_PUSH_PROP_THIS_LITERAL;
}
#endif /* ENABLED (JERRY_ES2015) */
if (PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode)
&& context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL)
{
JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_LITERAL, assign_ident_opcode));
parser_check_invalid_assign (context_p);
uint16_t literal_index;
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
literal_index = context_p->last_cbc.literal_index;
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
}
else if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS)
{
literal_index = context_p->last_cbc.value;
context_p->last_cbc_opcode = CBC_PUSH_LITERAL;
}
else
{
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_THREE_LITERALS);
literal_index = context_p->last_cbc.third_literal_index;
context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS;
}
parser_stack_push_uint16 (context_p, literal_index);
parser_stack_push_uint8 (context_p, assign_ident_opcode);
}
else if (context_p->last_cbc_opcode == CBC_PUSH_THIS_LITERAL)
{
if (context_p->last_cbc.literal_type != LEXER_IDENT_LITERAL)
{
parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR);
parser_stack_push_uint8 (context_p, CBC_ASSIGN);
}
else
{
parser_check_invalid_assign (context_p);
context_p->last_cbc_opcode = CBC_PUSH_THIS;
parser_flush_cbc (context_p);
parser_stack_push_uint16 (context_p, context_p->last_cbc.literal_index);
parser_stack_push_uint8 (context_p, assign_ident_opcode);
}
}
else if (context_p->last_cbc_opcode == CBC_PUSH_PROP)
{
JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP, CBC_ASSIGN));
parser_stack_push_uint8 (context_p, CBC_ASSIGN);
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
}
else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_LITERAL)
{
if (context_p->last_cbc.literal_type != LEXER_IDENT_LITERAL)
{
JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP_LITERAL, CBC_ASSIGN_PROP_LITERAL));
parser_stack_push_uint16 (context_p, context_p->last_cbc.literal_index);
parser_stack_push_uint8 (context_p, CBC_ASSIGN_PROP_LITERAL);
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
}
else
{
context_p->last_cbc_opcode = CBC_PUSH_LITERAL;
parser_stack_push_uint8 (context_p, CBC_ASSIGN);
}
}
else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_LITERAL_LITERAL)
{
JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP_LITERAL_LITERAL, CBC_PUSH_TWO_LITERALS));
context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS;
parser_stack_push_uint8 (context_p, CBC_ASSIGN);
}
else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_THIS_LITERAL)
{
if (context_p->last_cbc.literal_type != LEXER_IDENT_LITERAL)
{
JERRY_ASSERT (CBC_SAME_ARGS (CBC_PUSH_PROP_THIS_LITERAL, CBC_ASSIGN_PROP_THIS_LITERAL));
parser_stack_push_uint16 (context_p, context_p->last_cbc.literal_index);
parser_stack_push_uint8 (context_p, CBC_ASSIGN_PROP_THIS_LITERAL);
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
}
else
{
context_p->last_cbc_opcode = CBC_PUSH_THIS_LITERAL;
parser_stack_push_uint8 (context_p, CBC_ASSIGN);
}
}
else
{
/* Invalid LeftHandSide expression. */
#if ENABLED (JERRY_ES2015)
parser_check_invalid_new_target (context_p, CBC_ASSIGN);
#endif /* ENABLED (JERRY_ES2015) */
parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR);
parser_stack_push_uint8 (context_p, CBC_ASSIGN);
}
parser_stack_push_uint8 (context_p, LEXER_ASSIGN);
} /* parser_append_binary_single_assignment_token */
/**
* Append a binary token.
*/
static void
parser_append_binary_token (parser_context_t *context_p) /**< context */
{
JERRY_ASSERT (LEXER_IS_BINARY_OP_TOKEN (context_p->token.type));
parser_push_result (context_p);
if (context_p->token.type == LEXER_ASSIGN)
{
parser_append_binary_single_assignment_token (context_p, CBC_ASSIGN_SET_IDENT);
return;
}
if (LEXER_IS_BINARY_LVALUE_TOKEN (context_p->token.type))
{
if (PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode)
&& context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL)
{
parser_check_invalid_assign (context_p);
parser_emit_ident_reference (context_p, CBC_PUSH_IDENT_REFERENCE);
}
else if (PARSER_IS_PUSH_PROP (context_p->last_cbc_opcode))
{
context_p->last_cbc_opcode = PARSER_PUSH_PROP_TO_PUSH_PROP_REFERENCE (context_p->last_cbc_opcode);
}
else if (context_p->last_cbc_opcode == CBC_PUSH_THIS_LITERAL)
{
if (context_p->last_cbc.literal_type != LEXER_IDENT_LITERAL)
{
parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR);
parser_emit_cbc (context_p, CBC_PUSH_PROP_REFERENCE);
}
else
{
parser_check_invalid_assign (context_p);
context_p->last_cbc_opcode = CBC_PUSH_THIS;
parser_flush_cbc (context_p);
context_p->last_cbc_opcode = CBC_PUSH_IDENT_REFERENCE;
}
}
else
{
/* Invalid LeftHandSide expression. */
#if ENABLED (JERRY_ES2015)
parser_check_invalid_new_target (context_p, CBC_ASSIGN);
#endif /* ENABLED (JERRY_ES2015) */
parser_emit_cbc_ext (context_p, CBC_EXT_THROW_REFERENCE_ERROR);
parser_emit_cbc (context_p, CBC_PUSH_PROP_REFERENCE);
}
}
else if (context_p->token.type == LEXER_LOGICAL_OR
|| context_p->token.type == LEXER_LOGICAL_AND)
{
parser_branch_t branch;
uint16_t opcode = CBC_BRANCH_IF_LOGICAL_TRUE;
if (context_p->token.type == LEXER_LOGICAL_AND)
{
opcode = CBC_BRANCH_IF_LOGICAL_FALSE;
}
parser_emit_cbc_forward_branch (context_p, opcode, &branch);
parser_stack_push (context_p, &branch, sizeof (parser_branch_t));
}
parser_stack_push_uint8 (context_p, context_p->token.type);
} /* parser_append_binary_token */
/**
* Emit opcode for binary computations.
*/
static void
parser_process_binary_opcodes (parser_context_t *context_p, /**< context */
uint8_t min_prec_treshold) /**< minimal precedence of tokens */
{
while (true)
{
uint8_t token = context_p->stack_top_uint8;
cbc_opcode_t opcode;
/* For left-to-right operators (all binary operators except assignment
* and logical operators), the byte code is flushed if the precedence
* of the next operator is less or equal than the current operator. For
* assignment and logical operators, we add 1 to the min precendence to
* force right-to-left evaluation order. */
if (!LEXER_IS_BINARY_OP_TOKEN (token)
|| parser_binary_precedence_table[token - LEXER_FIRST_BINARY_OP] < min_prec_treshold)
{
return;
}
parser_push_result (context_p);
parser_stack_pop_uint8 (context_p);
if (token == LEXER_ASSIGN)
{
opcode = (cbc_opcode_t) context_p->stack_top_uint8;
parser_stack_pop_uint8 (context_p);
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL
&& opcode == CBC_ASSIGN_SET_IDENT)
{
JERRY_ASSERT (CBC_ARGS_EQ (CBC_ASSIGN_LITERAL_SET_IDENT,
CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2));
context_p->last_cbc.value = parser_stack_pop_uint16 (context_p);
context_p->last_cbc_opcode = CBC_ASSIGN_LITERAL_SET_IDENT;
continue;
}
if (cbc_flags[opcode] & CBC_HAS_LITERAL_ARG)
{
uint16_t index = parser_stack_pop_uint16 (context_p);
parser_emit_cbc_literal (context_p, (uint16_t) opcode, index);
if (opcode == CBC_ASSIGN_PROP_THIS_LITERAL
&& (context_p->stack_depth >= context_p->stack_limit))
{
/* Stack limit is increased for VM_OC_ASSIGN_PROP_THIS. Needed by vm.c. */
JERRY_ASSERT (context_p->stack_depth == context_p->stack_limit);
context_p->stack_limit++;
if (context_p->stack_limit > PARSER_MAXIMUM_STACK_LIMIT)
{
parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED);
}
}
continue;
}
}
else if (LEXER_IS_BINARY_LVALUE_TOKEN (token))
{
parser_stack_push_uint8 (context_p, CBC_ASSIGN);
parser_stack_push_uint8 (context_p, LEXER_ASSIGN);
parser_stack_push_uint8 (context_p, lexer_convert_binary_lvalue_token_to_binary (token));
continue;
}
else if (token == LEXER_LOGICAL_OR || token == LEXER_LOGICAL_AND)
{
parser_branch_t branch;
parser_stack_pop (context_p, &branch, sizeof (parser_branch_t));
parser_set_branch_to_current_position (context_p, &branch);
continue;
}
else
{
opcode = LEXER_BINARY_OP_TOKEN_TO_OPCODE (token);
if (PARSER_IS_PUSH_NUMBER (context_p->last_cbc_opcode))
{
lexer_convert_push_number_to_push_literal (context_p);
}
if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
{
JERRY_ASSERT (CBC_SAME_ARGS (context_p->last_cbc_opcode, opcode + CBC_BINARY_WITH_LITERAL));
context_p->last_cbc_opcode = (uint16_t) (opcode + CBC_BINARY_WITH_LITERAL);
continue;
}
else if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS)
{
JERRY_ASSERT (CBC_ARGS_EQ (opcode + CBC_BINARY_WITH_TWO_LITERALS,
CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2));
context_p->last_cbc_opcode = (uint16_t) (opcode + CBC_BINARY_WITH_TWO_LITERALS);
continue;
}
}
parser_emit_cbc (context_p, (uint16_t) opcode);
}
} /* parser_process_binary_opcodes */
#if ENABLED (JERRY_ES2015)
/**
* End position marker of a pattern.
*/
typedef struct
{
scanner_location_t location; /**< end position of the pattern */
lexer_token_t token; /**< token at the end position */
} parser_pattern_end_marker_t;
/**
* Literal index should not be emitted while processing rhs target value
*/
#define PARSER_PATTERN_RHS_NO_LIT UINT16_MAX
/**
* Process the target of an initializer pattern.
*/
static parser_pattern_end_marker_t
parser_pattern_get_target (parser_context_t *context_p, /**< context */
parser_pattern_flags_t flags) /**< flags */
{
parser_pattern_end_marker_t end_marker;
end_marker.token.type = LEXER_INVALID_PATTERN;
parser_branch_t skip_init;
if (flags & PARSER_PATTERN_TARGET_DEFAULT)
{
JERRY_ASSERT (flags & PARSER_PATTERN_TARGET_ON_STACK);
parser_emit_cbc_forward_branch (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_DEFAULT_INITIALIZER), &skip_init);
}
if ((flags & (PARSER_PATTERN_TARGET_ON_STACK | PARSER_PATTERN_TARGET_DEFAULT)) != PARSER_PATTERN_TARGET_ON_STACK)
{
scanner_location_t start_location;
if (context_p->next_scanner_info_p->source_p != context_p->source_p
|| context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED
|| (flags & PARSER_PATTERN_REST_ELEMENT))
{
/* Found invalid pattern, push null value to fake the rhs target. */
parser_emit_cbc (context_p, CBC_PUSH_NULL);
}
else
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER);
scanner_get_location (&start_location, context_p);
scanner_set_location (context_p, &((scanner_location_info_t *) context_p->next_scanner_info_p)->location);
scanner_release_next (context_p, sizeof (scanner_location_info_t));
scanner_seek (context_p);
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
scanner_get_location (&(end_marker.location), context_p);
end_marker.token = context_p->token;
scanner_set_location (context_p, &start_location);
scanner_seek (context_p);
parser_flush_cbc (context_p);
}
}
if (flags & PARSER_PATTERN_TARGET_DEFAULT)
{
parser_set_branch_to_current_position (context_p, &skip_init);
}
return end_marker;
} /* parser_pattern_get_target */
/**
* Finalize an assignment/binding pattern.
*/
static void
parser_pattern_finalize (parser_context_t *context_p, /**< context */
parser_pattern_flags_t flags, /**< flags */
parser_pattern_end_marker_t *end_marker_p) /**< pattern end position */
{
if ((flags & (PARSER_PATTERN_TARGET_ON_STACK | PARSER_PATTERN_TARGET_DEFAULT)) != PARSER_PATTERN_TARGET_ON_STACK)
{
if (end_marker_p->token.type == LEXER_INVALID_PATTERN)
{
parser_raise_error (context_p, PARSER_ERR_INVALID_DESTRUCTURING_PATTERN);
}
scanner_set_location (context_p, &(end_marker_p->location));
context_p->token = end_marker_p->token;
}
else
{
JERRY_ASSERT (!(flags & PARSER_PATTERN_TARGET_DEFAULT));
lexer_next_token (context_p);
}
if ((flags & (PARSER_PATTERN_BINDING | PARSER_PATTERN_NESTED_PATTERN)) == PARSER_PATTERN_BINDING)
{
/* Pop the result of the expression. */
parser_emit_cbc (context_p, CBC_POP);
}
parser_flush_cbc (context_p);
} /* parser_pattern_finalize */
/**
* Emit right-hand-side target value.
*/
static void
parser_pattern_emit_rhs (parser_context_t *context_p, /**< context */
uint16_t rhs_opcode, /**< opcode to process the rhs value */
uint16_t literal_index) /**< literal index for object pattern */
{
if (literal_index != PARSER_PATTERN_RHS_NO_LIT)
{
parser_emit_cbc_ext_literal (context_p, rhs_opcode, literal_index);
}
else
{
parser_emit_cbc_ext (context_p, rhs_opcode);
}
} /* parser_pattern_emit_rhs */
/**
* Form an assignment from a pattern.
*/
static void
parser_pattern_form_assignment (parser_context_t *context_p, /**< context */
parser_pattern_flags_t flags, /**< flags */
uint16_t rhs_opcode, /**< opcode to process the rhs value */
uint16_t literal_index, /**< literal index for object pattern */
parser_line_counter_t ident_line_counter) /**< identifier line counter */
{
JERRY_UNUSED (ident_line_counter);
uint8_t assign_opcode = CBC_ASSIGN_SET_IDENT;
if (flags & (PARSER_PATTERN_LEXICAL | PARSER_PATTERN_LOCAL)
&& context_p->lit_object.index < PARSER_REGISTER_START)
{
assign_opcode = CBC_ASSIGN_LET_CONST;
}
parser_stack_push_uint8 (context_p, LEXER_EXPRESSION_START);
parser_append_binary_single_assignment_token (context_p, assign_opcode);
parser_pattern_emit_rhs (context_p, rhs_opcode, literal_index);
if (context_p->token.type == LEXER_ASSIGN)
{
parser_branch_t skip_init;
lexer_next_token (context_p);
parser_emit_cbc_forward_branch (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_DEFAULT_INITIALIZER), &skip_init);
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
parser_set_branch_to_current_position (context_p, &skip_init);
}
parser_process_binary_opcodes (context_p, 0);
JERRY_ASSERT (context_p->stack_top_uint8 == LEXER_EXPRESSION_START);
parser_stack_pop_uint8 (context_p);
#if ENABLED (JERRY_DEBUGGER)
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
&& ident_line_counter != context_p->last_breakpoint_line)
{
parser_emit_cbc (context_p, CBC_BREAKPOINT_DISABLED);
parser_flush_cbc (context_p);
parser_append_breakpoint_info (context_p, JERRY_DEBUGGER_BREAKPOINT_LIST, ident_line_counter);
context_p->last_breakpoint_line = ident_line_counter;
}
#endif /* ENABLED (JERRY_DEBUGGER) */
#if ENABLED (JERRY_LINE_INFO)
if (ident_line_counter != context_p->last_line_info_line)
{
parser_emit_line_info (context_p, ident_line_counter, false);
}
#endif /* ENABLED (JERRY_LINE_INFO) */
} /* parser_pattern_form_assignment */
/**
* Parse pattern inside a pattern.
*/
static void
parser_pattern_process_nested_pattern (parser_context_t *context_p, /**< context */
parser_pattern_flags_t flags, /**< flags */
uint16_t rhs_opcode, /**< opcode to process the rhs value */
uint16_t literal_index) /**< literal index for object pattern */
{
JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE || context_p->token.type == LEXER_LEFT_SQUARE);
parser_pattern_flags_t options = (PARSER_PATTERN_NESTED_PATTERN
| PARSER_PATTERN_TARGET_ON_STACK
| (flags & (PARSER_PATTERN_BINDING
| PARSER_PATTERN_LEXICAL
| PARSER_PATTERN_LOCAL
| PARSER_PATTERN_REST_ELEMENT
| PARSER_PATTERN_ARGUMENTS)));
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
options |= PARSER_PATTERN_TARGET_DEFAULT;
}
parser_pattern_emit_rhs (context_p, rhs_opcode, literal_index);
if (context_p->token.type == LEXER_LEFT_BRACE)
{
parser_parse_object_initializer (context_p, options);
}
else
{
parser_parse_array_initializer (context_p, options);
}
parser_emit_cbc (context_p, CBC_POP);
} /* parser_pattern_process_nested_pattern */
/**
* Process the current {Binding, Assignment}Property
*/
static void
parser_pattern_process_assignment (parser_context_t *context_p, /**< context */
parser_pattern_flags_t flags, /**< flags */
uint16_t rhs_opcode, /**< opcode to process the rhs value */
uint16_t literal_index, /**< literal index for object pattern */
lexer_token_type_t end_type) /**< end type token */
{
if (context_p->token.type == LEXER_LEFT_BRACE || context_p->token.type == LEXER_LEFT_SQUARE)
{
parser_pattern_process_nested_pattern (context_p, flags, rhs_opcode, literal_index);
return;
}
parser_line_counter_t ident_line_counter = context_p->token.line;
if (flags & PARSER_PATTERN_BINDING)
{
if (context_p->token.type != LEXER_LITERAL || context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
}
lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL);
if (flags & PARSER_PATTERN_LEXICAL
&& context_p->token.keyword_type == LEXER_KEYW_LET)
{
parser_raise_error (context_p, PARSER_ERR_LEXICAL_LET_BINDING);
}
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED);
parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED);
}
if (flags & PARSER_PATTERN_ARGUMENTS)
{
if (context_p->lit_object.literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
{
parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED);
}
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_FUNCTION_ARGUMENT;
}
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
parser_module_append_export_name (context_p);
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
lexer_next_token (context_p);
if (context_p->token.type != end_type
&& context_p->token.type != LEXER_ASSIGN
&& context_p->token.type != LEXER_COMMA)
{
parser_raise_error (context_p, PARSER_ERR_ILLEGAL_PROPERTY_IN_DECLARATION);
}
}
else
{
parser_flush_cbc (context_p);
uint16_t stack_depth_before = context_p->stack_depth;
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA | PARSE_EXPR_LEFT_HAND_SIDE);
if (!PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode))
{
if (!PARSER_IS_PUSH_PROP (context_p->last_cbc_opcode))
{
parser_raise_error (context_p, PARSER_ERR_INVALID_DESTRUCTURING_PATTERN);
}
if (end_type == LEXER_RIGHT_SQUARE)
{
/* LHS expression parsing may increases the stack depth, therefore rhs opcode may transforms:
Example: [a.b.c]
CBC_EXT_ITERATOR_STEP -> CBC_EXT_ITERATOR_STEP_2
CBC_EXT_REST_INITIALIZER -> CBC_EXT_ITERATOR_STEP_2 */
uint16_t stack_difference = (uint16_t) (context_p->stack_depth - stack_depth_before);
if (context_p->last_cbc_opcode == CBC_PUSH_PROP_LITERAL_LITERAL)
{
/* Example: [a.b]
CBC_EXT_ITERATOR_STEP -> CBC_EXT_ITERATOR_STEP_3
CBC_EXT_REST_INITIALIZER -> CBC_EXT_ITERATOR_STEP_3 */
PARSER_PLUS_EQUAL_U16 (stack_difference, 2);
}
PARSER_PLUS_EQUAL_U16 (rhs_opcode, stack_difference);
}
}
}
parser_pattern_form_assignment (context_p, flags, rhs_opcode, literal_index, ident_line_counter);
} /* parser_pattern_process_assignment */
/**
* Parse array initializer.
*/
static void
parser_parse_array_initializer (parser_context_t *context_p, /**< context */
parser_pattern_flags_t flags) /**< flags */
{
parser_pattern_end_marker_t end_pos = parser_pattern_get_target (context_p, flags);
lexer_next_token (context_p);
parser_emit_cbc_ext (context_p, CBC_EXT_GET_ITERATOR);
while (context_p->token.type != LEXER_RIGHT_SQUARE)
{
uint16_t rhs_opcode = CBC_EXT_ITERATOR_STEP;
if (context_p->token.type == LEXER_COMMA)
{
parser_emit_cbc_ext (context_p, rhs_opcode);
parser_emit_cbc (context_p, CBC_POP);
lexer_next_token (context_p);
continue;
}
parser_pattern_flags_t options = flags;
if (context_p->token.type == LEXER_THREE_DOTS)
{
lexer_next_token (context_p);
rhs_opcode = CBC_EXT_REST_INITIALIZER;
options |= PARSER_PATTERN_REST_ELEMENT;
}
parser_pattern_process_assignment (context_p, options, rhs_opcode, PARSER_PATTERN_RHS_NO_LIT, LEXER_RIGHT_SQUARE);
if (context_p->token.type == LEXER_COMMA && rhs_opcode != CBC_EXT_REST_INITIALIZER)
{
lexer_next_token (context_p);
}
else if (context_p->token.type != LEXER_RIGHT_SQUARE)
{
parser_raise_error (context_p, PARSER_ERR_INVALID_DESTRUCTURING_PATTERN);
}
}
/* close the iterator */
parser_emit_cbc_ext (context_p, CBC_EXT_ITERATOR_CLOSE);
parser_pattern_finalize (context_p, flags, &end_pos);
} /* parser_parse_array_initializer */
/**
* Parse object initializer.
*/
static void
parser_parse_object_initializer (parser_context_t *context_p, /**< context */
parser_pattern_flags_t flags) /**< flags */
{
parser_pattern_end_marker_t end_pos = parser_pattern_get_target (context_p, flags);
/* 12.14.5.2: ObjectAssignmentPattern : { } */
if (lexer_check_next_character (context_p, LIT_CHAR_RIGHT_BRACE))
{
parser_emit_cbc_ext (context_p, CBC_EXT_REQUIRE_OBJECT_COERCIBLE);
lexer_consume_next_character (context_p);
parser_pattern_finalize (context_p, flags, &end_pos);
return;
}
while (true)
{
lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_OBJECT_PATTERN);
uint16_t prop_index = context_p->lit_object.index;
parser_line_counter_t start_line = context_p->token.line;
parser_line_counter_t start_column = context_p->token.column;
uint16_t push_prop_opcode = CBC_EXT_INITIALIZER_PUSH_PROP_LITERAL;
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
break;
}
else if (context_p->token.type == LEXER_RIGHT_SQUARE)
{
prop_index = PARSER_PATTERN_RHS_NO_LIT;
push_prop_opcode = CBC_EXT_INITIALIZER_PUSH_PROP;
}
if (context_p->next_scanner_info_p->source_p == context_p->source_p)
{
JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED);
parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED);
}
lexer_next_token (context_p);
if (context_p->token.type == LEXER_COLON)
{
lexer_next_token (context_p);
parser_pattern_process_assignment (context_p, flags, push_prop_opcode, prop_index, LEXER_RIGHT_BRACE);
}
else
{
if (push_prop_opcode == CBC_EXT_INITIALIZER_PUSH_PROP)
{
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
}
if (context_p->token.type == LEXER_RIGHT_BRACE
|| context_p->token.type == LEXER_ASSIGN
|| context_p->token.type == LEXER_COMMA)
{
parser_reparse_as_common_identifier (context_p, start_line, start_column);
lexer_next_token (context_p);
}
if (flags & PARSER_PATTERN_ARGUMENTS)
{
if (context_p->lit_object.literal_p->status_flags & LEXER_FLAG_FUNCTION_ARGUMENT)
{
parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED);
}
context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_FUNCTION_ARGUMENT;
}
#if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
parser_module_append_export_name (context_p);
#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL);
parser_pattern_form_assignment (context_p, flags, push_prop_opcode, prop_index, start_line);
}
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
break;
}
else if (context_p->token.type != LEXER_COMMA)
{
parser_raise_error (context_p, PARSER_ERR_OBJECT_ITEM_SEPARATOR_EXPECTED);
}
}
parser_pattern_finalize (context_p, flags, &end_pos);
} /* parser_parse_object_initializer */
/**
* Parse an initializer.
*/
void
parser_parse_initializer (parser_context_t *context_p, /**< context */
parser_pattern_flags_t flags) /**< flags */
{
if (context_p->token.type == LEXER_LEFT_BRACE)
{
parser_parse_object_initializer (context_p, flags);
}
else
{
JERRY_ASSERT (context_p->token.type == LEXER_LEFT_SQUARE);
parser_parse_array_initializer (context_p, flags);
}
} /* parser_parse_initializer */
/**
* Parse an initializer using the next character.
*/
void
parser_parse_initializer_by_next_char (parser_context_t *context_p, /**< context */
parser_pattern_flags_t flags) /**< flags */
{
JERRY_ASSERT (lexer_check_next_characters (context_p, LIT_CHAR_LEFT_SQUARE, LIT_CHAR_LEFT_BRACE));
if (lexer_consume_next_character (context_p) == LIT_CHAR_LEFT_BRACE)
{
parser_parse_object_initializer (context_p, flags);
}
else
{
parser_parse_array_initializer (context_p, flags);
}
} /* parser_parse_initializer_by_next_char */
#endif /* ENABLED (JERRY_ES2015) */
/**
* Process ternary expression.
*
* @return true - continue with primary expression parsing
* false - otherwise
*/
static bool
parser_process_ternary_expression (parser_context_t *context_p, /**< context */
size_t grouping_level) /**< grouping level */
{
JERRY_ASSERT (context_p->token.type == LEXER_QUESTION_MARK);
cbc_opcode_t opcode = CBC_BRANCH_IF_FALSE_FORWARD;
parser_branch_t cond_branch;
parser_branch_t uncond_branch;
parser_push_result (context_p);
if (context_p->last_cbc_opcode == CBC_LOGICAL_NOT)
{
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
opcode = CBC_BRANCH_IF_TRUE_FORWARD;
}
parser_emit_cbc_forward_branch (context_p, (uint16_t) opcode, &cond_branch);
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &uncond_branch);
parser_set_branch_to_current_position (context_p, &cond_branch);
/* Although byte code is constructed for two branches,
* only one of them will be executed. To reflect this
* the stack is manually adjusted. */
JERRY_ASSERT (context_p->stack_depth > 0);
context_p->stack_depth--;
if (context_p->token.type != LEXER_COLON)
{
parser_raise_error (context_p, PARSER_ERR_COLON_FOR_CONDITIONAL_EXPECTED);
}
lexer_next_token (context_p);
parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA);
parser_set_branch_to_current_position (context_p, &uncond_branch);
/* Last opcode rewrite is not allowed because
* the result may come from the first branch. */
parser_flush_cbc (context_p);
parser_process_binary_opcodes (context_p, 0);
return grouping_level >= PARSER_GROUPING_LEVEL_INCREASE;
} /* parser_process_ternary_expression */
/**
* Process expression sequence.
*/
static void
parser_process_expression_sequence (parser_context_t *context_p) /**< context */
{
if (!CBC_NO_RESULT_OPERATION (context_p->last_cbc_opcode))
{
parser_emit_cbc (context_p, CBC_POP);
}
if (context_p->stack_top_uint8 == LEXER_LEFT_PAREN)
{
parser_mem_page_t *page_p = context_p->stack.first_p;
JERRY_ASSERT (page_p != NULL);
page_p->bytes[context_p->stack.last_position - 1] = LEXER_COMMA_SEP_LIST;
context_p->stack_top_uint8 = LEXER_COMMA_SEP_LIST;
}
lexer_next_token (context_p);
} /* parser_process_expression_sequence */
/**
* Process group expression.
*/
static void
parser_process_group_expression (parser_context_t *context_p, /**< context */
size_t *grouping_level_p) /**< grouping level */
{
JERRY_ASSERT (*grouping_level_p >= PARSER_GROUPING_LEVEL_INCREASE);
(*grouping_level_p) -= PARSER_GROUPING_LEVEL_INCREASE;
if (context_p->stack_top_uint8 == LEXER_COMMA_SEP_LIST)
{
parser_push_result (context_p);
parser_flush_cbc (context_p);
}
parser_stack_pop_uint8 (context_p);
lexer_next_token (context_p);
} /* parser_process_group_expression */
/**
* Parse block expression.
*/
void
parser_parse_block_expression (parser_context_t *context_p, /**< context */
int options) /**< option flags */
{
parser_parse_expression (context_p, options | PARSE_EXPR_NO_PUSH_RESULT);
if (CBC_NO_RESULT_OPERATION (context_p->last_cbc_opcode))
{
JERRY_ASSERT (CBC_SAME_ARGS (context_p->last_cbc_opcode, context_p->last_cbc_opcode + 2));
PARSER_PLUS_EQUAL_U16 (context_p->last_cbc_opcode, 2);
parser_flush_cbc (context_p);
}
else
{
parser_emit_cbc (context_p, CBC_POP_BLOCK);
}
} /* parser_parse_block_expression */
/**
* Parse expression statement.
*/
void
parser_parse_expression_statement (parser_context_t *context_p, /**< context */
int options) /**< option flags */
{
parser_parse_expression (context_p, options | PARSE_EXPR_NO_PUSH_RESULT);
if (!CBC_NO_RESULT_OPERATION (context_p->last_cbc_opcode))
{
parser_emit_cbc (context_p, CBC_POP);
}
} /* parser_parse_expression_statement */
JERRY_STATIC_ASSERT (PARSE_EXPR_LEFT_HAND_SIDE == 0x1,
value_of_parse_expr_left_hand_side_must_be_1);
/**
* Parse expression.
*/
void
parser_parse_expression (parser_context_t *context_p, /**< context */
int options) /**< option flags */
{
size_t grouping_level = (options & PARSE_EXPR_LEFT_HAND_SIDE);
parser_stack_push_uint8 (context_p, LEXER_EXPRESSION_START);
if (options & PARSE_EXPR_HAS_LITERAL)
{
JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL);
goto process_unary_expression;
}
while (true)
{
if (parser_parse_unary_expression (context_p, &grouping_level))
{
parser_process_binary_opcodes (context_p, 0);
break;
}
while (true)
{
process_unary_expression:
parser_process_unary_expression (context_p, grouping_level);
if (JERRY_LIKELY (grouping_level != PARSE_EXPR_LEFT_HAND_SIDE))
{
uint8_t min_prec_treshold = 0;
if (LEXER_IS_BINARY_OP_TOKEN (context_p->token.type))
{
min_prec_treshold = parser_binary_precedence_table[context_p->token.type - LEXER_FIRST_BINARY_OP];
/* Check for BINARY_LVALUE tokens + LEXER_LOGICAL_OR + LEXER_LOGICAL_AND */
if (min_prec_treshold <= PARSER_RIGHT_TO_LEFT_ORDER_MAX_PRECEDENCE
&& min_prec_treshold != PARSER_RIGHT_TO_LEFT_ORDER_TERNARY_PRECEDENCE)
{
/* Right-to-left evaluation order. */
min_prec_treshold++;
}
}
parser_process_binary_opcodes (context_p, min_prec_treshold);
}
if (context_p->token.type == LEXER_RIGHT_PAREN
&& (context_p->stack_top_uint8 == LEXER_LEFT_PAREN
|| context_p->stack_top_uint8 == LEXER_COMMA_SEP_LIST))
{
parser_process_group_expression (context_p, &grouping_level);
continue;
}
if (JERRY_UNLIKELY (context_p->token.type == LEXER_QUESTION_MARK)
&& (grouping_level != PARSE_EXPR_LEFT_HAND_SIDE)
&& parser_process_ternary_expression (context_p, grouping_level))
{
continue;
}
break;
}
if (grouping_level == PARSE_EXPR_LEFT_HAND_SIDE)
{
break;
}
if (JERRY_UNLIKELY (context_p->token.type == LEXER_COMMA)
&& (!(options & PARSE_EXPR_NO_COMMA) || grouping_level >= PARSER_GROUPING_LEVEL_INCREASE))
{
parser_process_expression_sequence (context_p);
continue;
}
if (LEXER_IS_BINARY_OP_TOKEN (context_p->token.type))
{
parser_append_binary_token (context_p);
lexer_next_token (context_p);
continue;
}
break;
}
if (grouping_level >= PARSER_GROUPING_LEVEL_INCREASE)
{
parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
}
JERRY_ASSERT (context_p->stack_top_uint8 == LEXER_EXPRESSION_START);
parser_stack_pop_uint8 (context_p);
if (!(options & PARSE_EXPR_NO_PUSH_RESULT))
{
parser_push_result (context_p);
}
} /* parser_parse_expression */
/**
* @}
* @}
* @}
*/
#endif /* ENABLED (JERRY_PARSER) */