blob: 879459e9dcb7174ee94ecaa72d85ada60f903aac [file] [log] [blame]
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Alexander Borisov
* Copyright (C) NGINX, Inc.
*/
#include <njs_main.h>
static njs_int_t njs_parser_scope_begin(njs_parser_t *parser, njs_scope_t type);
static void njs_parser_scope_end(njs_parser_t *parser);
static njs_int_t njs_parser_check_error_state(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_primary_expression_test(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_regexp_literal(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_template_literal(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_template_literal_string(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_template_literal_expression(
njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_cover_parenthesized_expression(
njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_binding_identifier_pattern(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_cover_parenthesized_expression_after(
njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_cover_parenthesized_expression_end(
njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_array_literal(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_array_element_list(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_array_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_array_spread_element(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_object_literal(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_object_literal_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_property_definition_list(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_property_definition_list_after(
njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_property_definition(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_property_definition_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_computed_property_name_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_initializer(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_initializer_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_initializer_assign(njs_parser_t *parser,
njs_token_type_t type);
static njs_int_t njs_parser_member_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_member_expression_next(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_member_expression_bracket(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_member_expression_new_next(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_super_property(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_member_expression_import(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_member_expression_new(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_member_expression_new_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_member_expression_new_args(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_parser_node_t *njs_parser_create_call(njs_parser_t *parser,
njs_parser_node_t *node, uint8_t ctor);
static njs_int_t njs_parser_call_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_call_expression_args(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_call_expression_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_arguments(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_parenthesis_or_comma(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_argument_list(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_argument_list_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_optional_expression_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_optional_chain(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_optional_chain_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_new_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_new_expression_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_left_hand_side_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_left_hand_side_expression_after(
njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_left_hand_side_expression_node(
njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_left_hand_side_expression_optional(
njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_update_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_update_expression_post(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_update_expression_unary(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_unary_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_unary_expression_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_unary_expression_next(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_exponentiation_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_exponentiation_expression_match(
njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_multiplicative_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_multiplicative_expression_match(
njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_additive_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_additive_expression_match(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_shift_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_shift_expression_match(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_relational_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_relational_expression_match(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_equality_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_equality_expression_match(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_bitwise_AND_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_bitwise_AND_expression_and(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_bitwise_XOR_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_bitwise_XOR_expression_xor(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_bitwise_OR_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_bitwise_OR_expression_or(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_logical_AND_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_logical_AND_expression_and(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_logical_OR_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_logical_OR_expression_or(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_coalesce_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_short_circuit_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_conditional_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_conditional_question_mark(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_conditional_colon(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_conditional_colon_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_assignment_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_match_arrow_expression(njs_parser_t *parser,
njs_lexer_token_t *token);
static njs_int_t njs_parser_assignment_expression_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_assignment_operator(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_assignment_operator_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_expression_comma(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_statement_wo_node(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_statement_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_declaration(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_hoistable_declaration(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_block_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_block_statement_open_brace(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_block_statement_close_brace(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_statement_list(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_statement_list_next(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_statement_list_item(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_variable_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_variable_declaration_list(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_variable_declaration_list_next(
njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_variable_declaration(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_binding_pattern(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_object_binding_pattern(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_array_binding_pattern(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_expression_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_expression_statement_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_if_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_if_close_parenthesis(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_else_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_else_statement_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_iteration_statement_do(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_iteration_statement_do_while(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_do_while_semicolon(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_iteration_statement_while(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_while_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_while_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_iteration_statement_for(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_iteration_statement_for_map(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_for_var_binding_or_var_list(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_for_var_in_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_for_var_in_statement_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_for_var_in_of_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_for_in_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_for_in_statement_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_for_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_for_expression_end(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_for_end(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_switch_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_switch_statement_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_switch_block(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_switch_case(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_switch_case_wo_def(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_switch_case_def(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current,
njs_bool_t with_default);
static njs_int_t njs_parser_switch_case_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_switch_case_block(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_switch_case_after_wo_def(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_switch_case_block_wo_def(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_continue_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_break_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_break_continue(njs_parser_t *parser,
njs_lexer_token_t *token, njs_token_type_t type);
static njs_int_t njs_parser_return_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_return_statement_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_with_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_labelled_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_labelled_statement_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_throw_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_throw_statement_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_try_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_catch_or_finally(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_catch_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_catch_parenthesis(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_catch_finally(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_debugger_statement(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_function_declaration(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_function_declaration_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_function_parse(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_function_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_function_expression_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_unique_formal_parameters(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_formal_parameters(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_formal_parameters_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_arrow_function(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_arrow_function_args_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_arrow_function_arrow(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_arrow_function_body_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_method_definition(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_get_set(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_get_set_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_get_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_set_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_function_lambda(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_function_lambda_args_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_function_lambda_body_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_export(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_export_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_import(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_import_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_module_lambda_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current);
static njs_int_t njs_parser_export_sink(njs_parser_t *parser);
static njs_parser_node_t *njs_parser_return_set(njs_parser_t *parser,
njs_parser_node_t *expr);
static njs_parser_node_t *njs_parser_variable_node(njs_parser_t *parser,
uintptr_t unique_id, njs_variable_type_t type);
static njs_parser_node_t *njs_parser_reference(njs_parser_t *parser,
njs_lexer_token_t *token);
static njs_parser_node_t *njs_parser_argument(njs_parser_t *parser,
njs_parser_node_t *expr, njs_index_t index);
static njs_int_t njs_parser_object_property(njs_parser_t *parser,
njs_parser_node_t *parent, njs_parser_node_t *property,
njs_parser_node_t *value, njs_bool_t proto_init);
static njs_int_t njs_parser_property_accessor(njs_parser_t *parser,
njs_parser_node_t *parent, njs_parser_node_t *property,
njs_parser_node_t *value, njs_token_type_t accessor);
static njs_int_t njs_parser_array_item(njs_parser_t *parser,
njs_parser_node_t *array, njs_parser_node_t *value);
static njs_int_t njs_parser_template_string(njs_parser_t *parser,
njs_lexer_token_t *token);
static njs_token_type_t njs_parser_escape_string_create(njs_parser_t *parser,
njs_lexer_token_t *token, njs_value_t *value);
static njs_int_t njs_parser_escape_string_calc_length(njs_parser_t *parser,
njs_lexer_token_t *token, size_t *out_size, size_t *out_length);
static void njs_parser_serialize_tree(njs_chb_t *chain,
njs_parser_node_t *node, njs_int_t *ret, size_t indent);
static njs_int_t njs_parser_serialize_node(njs_chb_t *chain,
njs_parser_node_t *node);
#define njs_parser_chain_top(parser) \
((parser)->scope->top)
#define njs_parser_chain_top_set(parser, node) \
(parser)->scope->top = node
njs_inline njs_int_t
njs_parser_not_supported(njs_parser_t *parser, njs_lexer_token_t *token)
{
if (token->type != NJS_TOKEN_END) {
njs_parser_syntax_error(parser, "Token \"%V\" not supported "
"in this version", &token->text);
} else {
njs_parser_syntax_error(parser, "Not supported in this version");
}
return NJS_DONE;
}
njs_inline njs_int_t
njs_parser_reject(njs_parser_t *parser)
{
njs_queue_link_t *link;
njs_parser_stack_entry_t *entry;
while (!njs_queue_is_empty(&parser->stack)) {
entry = njs_queue_link_data(njs_queue_first(&parser->stack),
njs_parser_stack_entry_t, link);
link = njs_queue_first(&parser->stack);
njs_queue_remove(link);
if (!entry->optional) {
njs_parser_next(parser, entry->state);
parser->target = entry->node;
return NJS_DECLINED;
}
}
return njs_parser_failed(parser);
}
njs_int_t
njs_parser(njs_parser_t *parser, njs_parser_t *prev)
{
njs_int_t ret;
njs_lexer_token_t *token;
ret = njs_parser_scope_begin(parser, NJS_SCOPE_GLOBAL);
if (njs_slow_path(ret != NJS_OK)) {
return NJS_ERROR;
}
if (prev != NULL) {
/*
* Copy the global scope variables from the previous
* iteration of the accumulative mode.
*/
ret = njs_variables_copy(parser->vm, &parser->scope->variables,
&prev->scope->variables);
if (ret != NJS_OK) {
return ret;
}
}
njs_queue_init(&parser->stack);
parser->target = NULL;
njs_parser_next(parser, njs_parser_statement_list);
ret = njs_parser_after(parser, njs_queue_first(&parser->stack),
NULL, 0, njs_parser_check_error_state);
if (ret != NJS_OK) {
return ret;
}
do {
token = njs_lexer_token(parser->lexer, 0);
if (njs_slow_path(token == NULL)) {
return NJS_ERROR;
}
parser->ret = parser->state(parser, token,
njs_queue_first(&parser->stack));
} while (parser->ret != NJS_DONE && parser->ret != NJS_ERROR);
if (parser->ret != NJS_DONE) {
return NJS_ERROR;
}
if (njs_is_error(&parser->vm->retval)) {
return NJS_ERROR;
}
if (parser->node == NULL) {
/* Empty string, just semicolons or variables declarations. */
parser->node = njs_parser_node_new(parser, 0);
if (njs_slow_path(parser->node == NULL)) {
return NJS_ERROR;
}
}
parser->node->token_type = NJS_TOKEN_END;
parser->node->token_line = parser->lexer->line;
njs_parser_chain_top_set(parser, parser->node);
return NJS_OK;
}
static njs_int_t
njs_parser_check_error_state(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
return njs_parser_failed(parser);
}
njs_int_t
njs_parser_failed_state(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
if (token->type != NJS_TOKEN_END) {
njs_parser_syntax_error(parser, "Unexpected token \"%V\"",
&token->text);
} else {
njs_parser_syntax_error(parser, "Unexpected end of input");
}
return NJS_DONE;
}
static njs_int_t
njs_parser_scope_begin(njs_parser_t *parser, njs_scope_t type)
{
njs_arr_t *values;
njs_uint_t nesting;
njs_lexer_t *lexer;
njs_parser_scope_t *scope, *parent;
nesting = 0;
if (type == NJS_SCOPE_FUNCTION) {
for (scope = parser->scope; scope != NULL; scope = scope->parent) {
if (scope->type == NJS_SCOPE_FUNCTION) {
nesting = scope->nesting + 1;
if (nesting < NJS_MAX_NESTING) {
break;
}
njs_parser_syntax_error(parser, "The maximum function nesting "
"level is \"%d\"", NJS_MAX_NESTING);
return NJS_ERROR;
}
}
}
scope = njs_mp_zalloc(parser->vm->mem_pool, sizeof(njs_parser_scope_t));
if (njs_slow_path(scope == NULL)) {
return NJS_ERROR;
}
scope->type = type;
if (type == NJS_SCOPE_FUNCTION) {
scope->next_index[0] = type;
scope->next_index[1] = NJS_SCOPE_CLOSURE + nesting
+ sizeof(njs_value_t);
} else {
if (type == NJS_SCOPE_GLOBAL) {
type += NJS_INDEX_GLOBAL_OFFSET;
}
scope->next_index[0] = type;
scope->next_index[1] = 0;
}
scope->nesting = nesting;
scope->argument_closures = 0;
njs_queue_init(&scope->nested);
njs_rbtree_init(&scope->variables, njs_parser_scope_rbtree_compare);
njs_rbtree_init(&scope->labels, njs_parser_scope_rbtree_compare);
njs_rbtree_init(&scope->references, njs_parser_scope_rbtree_compare);
values = NULL;
if (scope->type < NJS_SCOPE_BLOCK) {
values = njs_arr_create(parser->vm->mem_pool, 4, sizeof(njs_value_t));
if (njs_slow_path(values == NULL)) {
return NJS_ERROR;
}
}
scope->values[0] = values;
scope->values[1] = NULL;
lexer = parser->lexer;
if (lexer->file.length != 0) {
njs_file_basename(&lexer->file, &scope->file);
njs_file_dirname(&lexer->file, &scope->cwd);
}
parent = parser->scope;
scope->parent = parent;
parser->scope = scope;
if (parent != NULL) {
njs_queue_insert_tail(&parent->nested, &scope->link);
if (nesting == 0) {
/* Inherit function nesting in blocks. */
scope->nesting = parent->nesting;
}
}
return NJS_OK;
}
static void
njs_parser_scope_end(njs_parser_t *parser)
{
njs_parser_scope_t *scope, *parent;
scope = parser->scope;
parent = scope->parent;
parser->scope = parent;
}
intptr_t
njs_parser_scope_rbtree_compare(njs_rbtree_node_t *node1,
njs_rbtree_node_t *node2)
{
njs_variable_node_t *lex_node1, *lex_node2;
lex_node1 = (njs_variable_node_t *) node1;
lex_node2 = (njs_variable_node_t *) node2;
if (lex_node1->key < lex_node2->key) {
return -1;
}
if (lex_node1->key > lex_node2->key) {
return 1;
}
return 0;
}
static njs_int_t
njs_parser_generator_expression(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
return njs_parser_not_supported(parser, token);
}
static njs_int_t
njs_parser_class_expression(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
return njs_parser_not_supported(parser, token);
}
static njs_int_t
njs_parser_async_generator_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
return njs_parser_not_supported(parser, token);
}
static njs_int_t
njs_parser_async_function_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
return njs_parser_not_supported(parser, token);
}
static njs_int_t
njs_parser_generator_declaration(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
return njs_parser_not_supported(parser, token);
}
static njs_int_t
njs_parser_class_declaration(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
return njs_parser_not_supported(parser, token);
}
static njs_int_t
njs_parser_lexical_declaration(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
return njs_parser_not_supported(parser, token);
}
static njs_int_t
njs_parser_function_or_generator(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
njs_parser_node_t *node, *cur;
if (token->type != NJS_TOKEN_FUNCTION) {
return NJS_DECLINED;
}
cur = parser->node;
if (token->type == NJS_TOKEN_MULTIPLICATION) {
njs_lexer_consume_token(parser->lexer, 1);
njs_parser_next(parser, njs_parser_generator_declaration);
} else {
node = njs_parser_node_new(parser, NJS_TOKEN_FUNCTION);
if (node == NULL) {
return NJS_ERROR;
}
node->token_line = token->line;
parser->node = node;
njs_lexer_consume_token(parser->lexer, 1);
njs_parser_next(parser, njs_parser_function_declaration);
}
return njs_parser_after(parser, current, cur, 1,
njs_parser_statement_after);
}
static njs_int_t
njs_parser_async_function_or_generator(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
if (token->type != NJS_TOKEN_ASYNC) {
return NJS_DECLINED;
}
token = njs_lexer_peek_token(parser->lexer, token, 1);
if (token == NULL) {
return NJS_ERROR;
}
if (token->type != NJS_TOKEN_FUNCTION) {
return NJS_DECLINED;
}
if (token->type == NJS_TOKEN_MULTIPLICATION) {
njs_parser_next(parser, njs_parser_generator_declaration);
} else {
njs_parser_next(parser, njs_parser_async_function_expression);
}
return NJS_OK;
}
njs_inline njs_int_t
njs_parser_expect_semicolon(njs_parser_t *parser, njs_lexer_token_t *token)
{
if (token->type != NJS_TOKEN_SEMICOLON) {
if (parser->strict_semicolon
|| (token->type != NJS_TOKEN_END
&& token->type != NJS_TOKEN_CLOSE_BRACE
&& parser->lexer->prev_type != NJS_TOKEN_LINE_END))
{
return NJS_DECLINED;
}
return NJS_OK;
}
njs_lexer_consume_token(parser->lexer, 1);
return NJS_OK;
}
static njs_int_t
njs_parser_semicolon(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
if (njs_parser_expect_semicolon(parser, token) != NJS_OK) {
return njs_parser_failed(parser);
}
return njs_parser_stack_pop(parser);
}
static njs_int_t
njs_parser_close_bracked(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
if (token->type != NJS_TOKEN_CLOSE_BRACKET) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
return njs_parser_stack_pop(parser);
}
static njs_int_t
njs_parser_close_parenthesis(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
if (parser->ret != NJS_OK) {
return njs_parser_failed(parser);
}
if (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
return njs_parser_stack_pop(parser);
}
static njs_int_t
njs_parser_expression_parenthesis(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
if (token->type != NJS_TOKEN_OPEN_PARENTHESIS) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
parser->node = NULL;
njs_parser_next(parser, njs_parser_expression);
return njs_parser_after(parser, current, NULL, 0,
njs_parser_close_parenthesis);
}
static njs_int_t
njs_parser_set_line_state(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
parser->node->token_line = (uint32_t) (uintptr_t) parser->target;
parser->target = NULL;
return njs_parser_stack_pop(parser);
}
/*
* 12.2 Primary Expression.
*/
static njs_int_t
njs_parser_primary_expression_test(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
njs_int_t ret;
njs_lexer_token_t *next;
njs_parser_node_t *node;
switch (token->type) {
/* IdentifierReference */
case NJS_TOKEN_THIS:
case NJS_TOKEN_NULL:
case NJS_TOKEN_NAME:
case NJS_TOKEN_YIELD:
case NJS_TOKEN_AWAIT:
goto reference;
case NJS_TOKEN_TRUE:
node = njs_parser_node_new(parser, token->type);
if (node == NULL) {
return NJS_ERROR;
}
node->u.value = njs_value_true;
node->token_line = token->line;
parser->node = node;
goto done;
case NJS_TOKEN_FALSE:
node = njs_parser_node_new(parser, token->type);
if (node == NULL) {
return NJS_ERROR;
}
node->u.value = njs_value_false;
node->token_line = token->line;
parser->node = node;
goto done;
case NJS_TOKEN_NUMBER:
node = njs_parser_node_new(parser, NJS_TOKEN_NUMBER);
if (node == NULL) {
return NJS_ERROR;
}
njs_set_number(&node->u.value, token->number);
node->token_line = token->line;
parser->node = node;
goto done;
case NJS_TOKEN_STRING:
node = njs_parser_node_new(parser, NJS_TOKEN_STRING);
if (node == NULL) {
return NJS_ERROR;
}
node->token_line = token->line;
ret = njs_parser_string_create(parser->vm, token, &node->u.value);
if (ret != NJS_OK) {
return NJS_ERROR;
}
parser->node = node;
goto done;
case NJS_TOKEN_ESCAPE_STRING:
/* Internal optimization. This is not in the specification. */
node = njs_parser_node_new(parser, NJS_TOKEN_STRING);
if (node == NULL) {
return NJS_ERROR;
}
node->token_line = token->line;
ret = njs_parser_escape_string_create(parser, token, &node->u.value);
if (ret != NJS_TOKEN_STRING) {
return NJS_ERROR;
}
parser->node = node;
goto done;
case NJS_TOKEN_UNTERMINATED_STRING:
/* Internal optimization. This is not in the specification. */
njs_parser_syntax_error(parser, "Unterminated string \"%V\"",
&token->text);
return NJS_ERROR;
/* ArrayLiteral */
case NJS_TOKEN_OPEN_BRACKET:
node = njs_parser_node_new(parser, NJS_TOKEN_ARRAY);
if (node == NULL) {
return NJS_ERROR;
}
node->token_line = token->line;
parser->node = node;
njs_parser_next(parser, njs_parser_array_literal);
break;
/* ObjectLiteral */
case NJS_TOKEN_OPEN_BRACE:
node = njs_parser_node_new(parser, NJS_TOKEN_OBJECT);
if (node == NULL) {
return NJS_ERROR;
}
node->token_line = token->line;
parser->node = node;
njs_parser_next(parser, njs_parser_object_literal);
break;
/* FunctionExpression */
case NJS_TOKEN_FUNCTION:
token = njs_lexer_peek_token(parser->lexer, token, 0);
if (token == NULL) {
return NJS_ERROR;
}
/* GeneratorExpression */
if (token->type == NJS_TOKEN_MULTIPLICATION) {
njs_parser_next(parser, njs_parser_generator_expression);
} else {
node = njs_parser_node_new(parser, NJS_TOKEN_FUNCTION_EXPRESSION);
if (node == NULL) {
return NJS_ERROR;
}
node->token_line = token->line;
parser->node = node;
njs_parser_next(parser, njs_parser_function_expression);
}
break;
/* ClassExpression */
case NJS_TOKEN_CLASS:
njs_parser_next(parser, njs_parser_class_expression);
return NJS_OK;
/* AsyncFunctionExpression */
case NJS_TOKEN_ASYNC:
next = njs_lexer_peek_token(parser->lexer, token, 1);
if (next == NULL) {
return NJS_ERROR;
}
if (next->type != NJS_TOKEN_FUNCTION) {
goto reference;
}
next = njs_lexer_peek_token(parser->lexer, next, 0);
if (njs_slow_path(next == NULL)) {
return NJS_ERROR;
}
/* GeneratorExpression */
if (next->type == NJS_TOKEN_MULTIPLICATION) {
njs_lexer_consume_token(parser->lexer, 1);
njs_parser_next(parser, njs_parser_async_generator_expression);
} else {
njs_parser_next(parser, njs_parser_async_function_expression);
}
return NJS_OK;
/* RegularExpressionLiteral */
case NJS_TOKEN_DIVISION:
case NJS_TOKEN_DIVISION_ASSIGNMENT:
node = njs_parser_node_new(parser, NJS_TOKEN_REGEXP);
if (node == NULL) {
return NJS_ERROR;
}
node->token_line = token->line;
parser->node = node;
ret = njs_parser_regexp_literal(parser, token, current);
if (ret != NJS_OK) {
return NJS_ERROR;
}
goto done;
/* TemplateLiteral */
case NJS_TOKEN_GRAVE:
node = njs_parser_node_new(parser, NJS_TOKEN_TEMPLATE_LITERAL);
if (node == NULL) {
return NJS_ERROR;
}
node->token_line = token->line;
parser->node = node;
njs_parser_next(parser, njs_parser_template_literal);
return NJS_OK;
/* CoverParenthesizedExpressionAndArrowParameterList */
case NJS_TOKEN_OPEN_PARENTHESIS:
njs_lexer_consume_token(parser->lexer, 1);
/* TODO: By specification. */
(void) njs_parser_cover_parenthesized_expression;
parser->node = NULL;
njs_parser_next(parser, njs_parser_expression);
return njs_parser_after(parser, current, NULL, 0,
njs_parser_close_parenthesis);
default:
if (njs_lexer_token_is_identifier_reference(token)) {
goto reference;
}
return njs_parser_reject(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
return NJS_OK;
reference:
node = njs_parser_reference(parser, token);
if (node == NULL) {
return NJS_ERROR;
}
node->token_line = token->line;
parser->node = node;
done:
njs_lexer_consume_token(parser->lexer, 1);
return NJS_DONE;
}
static njs_int_t
njs_parser_regexp_literal(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
u_char *p;
njs_str_t text;
njs_lexer_t *lexer;
njs_value_t *value;
njs_regexp_flags_t flags;
njs_regexp_pattern_t *pattern;
value = &parser->node->u.value;
lexer = parser->lexer;
if (token->type == NJS_TOKEN_DIVISION_ASSIGNMENT) {
lexer->start--;
}
for (p = lexer->start; p < lexer->end; p++) {
switch (*p) {
case '\n':
case '\r':
goto failed;
case '[':
while (1) {
if (++p >= lexer->end) {
goto failed;
}
if (*p == ']') {
break;
}
switch (*p) {
case '\n':
case '\r':
goto failed;
case '\\':
if (++p >= lexer->end || *p == '\n' || *p == '\r') {
goto failed;
}
break;
}
}
break;
case '\\':
if (++p >= lexer->end || *p == '\n' || *p == '\r') {
goto failed;
}
break;
case '/':
text.start = lexer->start;
text.length = p - text.start;
p++;
lexer->start = p;
flags = njs_regexp_flags(&p, lexer->end);
if (njs_slow_path(flags < 0)) {
njs_parser_syntax_error(parser, "Invalid RegExp flags \"%*s\"",
p - lexer->start, lexer->start);
return NJS_ERROR;
}
lexer->start = p;
pattern = njs_regexp_pattern_create(parser->vm, text.start,
text.length, flags);
if (njs_slow_path(pattern == NULL)) {
return NJS_ERROR;
}
value->data.u.data = pattern;
return NJS_OK;
}
}
failed:
njs_parser_syntax_error(parser, "Unterminated RegExp \"%*s\"",
p - (lexer->start - 1), lexer->start - 1);
return NJS_ERROR;
}
static njs_int_t
njs_parser_template_literal(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
njs_index_t index;
njs_parser_node_t *node, *array, *template, *temp;
temp = njs_parser_node_new(parser, 0);
if (temp == NULL) {
return NJS_ERROR;
}
array = njs_parser_node_new(parser, NJS_TOKEN_ARRAY);
if (array == NULL) {
return NJS_ERROR;
}
array->token_line = token->line;
template = parser->node;
index = NJS_SCOPE_CALLEE_ARGUMENTS;
if (template->token_type != NJS_TOKEN_TEMPLATE_LITERAL) {
node = njs_parser_argument(parser, array, index);
if (node == NULL) {
return NJS_ERROR;
}
template->right = node;
temp->right = node;
index += sizeof(njs_value_t);
} else {
template->left = array;
temp->right = template;
}
temp->left = template;
temp->index = index;
parser->target = temp;
token->text.start++;
token->text.length = 0;
njs_parser_next(parser, njs_parser_template_literal_string);
return NJS_OK;
}
static njs_int_t
njs_parser_template_literal_string(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
njs_int_t ret, ret_item;
njs_parser_node_t *template;
template = parser->target->left;
ret = njs_parser_template_string(parser, token);
if (ret == NJS_ERROR) {
njs_parser_syntax_error(parser, "Unterminated template literal");
return NJS_DONE;
}
if (template->token_type != NJS_TOKEN_TEMPLATE_LITERAL) {
ret_item = njs_parser_array_item(parser, template->right->left,
parser->node);
} else {
ret_item = njs_parser_array_item(parser, template->left, parser->node);
}
if (ret_item != NJS_OK) {
return NJS_ERROR;
}
if (ret == NJS_DONE) {
parser->node = template;
njs_parser_node_free(parser, parser->target);
njs_lexer_consume_token(parser->lexer, 1);
return njs_parser_stack_pop(parser);
}
parser->node = NULL;
njs_parser_next(parser, njs_parser_expression);
njs_lexer_consume_token(parser->lexer, 1);
return njs_parser_after(parser, current, parser->target, 0,
njs_parser_template_literal_expression);
}
static njs_int_t
njs_parser_template_literal_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
njs_int_t ret;
njs_parser_node_t *template, *node, *parent;
if (parser->ret != NJS_OK) {
return njs_parser_failed(parser);
}
if (token->type != NJS_TOKEN_CLOSE_BRACE) {
njs_parser_syntax_error(parser, "Missing \"}\" in template expression");
return NJS_DONE;
}
parent = parser->target->right;
template = parser->target->left;
if (template->token_type != NJS_TOKEN_TEMPLATE_LITERAL) {
node = njs_parser_argument(parser, parser->node, parser->target->index);
if (node == NULL) {
return NJS_ERROR;
}
parent->right = node;
parent = node;
parser->target->index += sizeof(njs_value_t);
} else {
ret = njs_parser_array_item(parser, template->left, parser->node);
if (ret != NJS_OK) {
return NJS_ERROR;
}
}
parser->target->right = parent;
parser->node = NULL;
njs_parser_next(parser, njs_parser_template_literal_string);
token->text.length = 0;
token->text.start += 1;
return NJS_OK;
}
static njs_int_t
njs_parser_cover_parenthesized_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
switch (token->type) {
case NJS_TOKEN_CLOSE_PARENTHESIS:
(void) njs_parser_stack_pop(parser);
break;
case NJS_TOKEN_ELLIPSIS:
njs_parser_next(parser, njs_parser_binding_identifier_pattern);
break;
default:
parser->node = NULL;
njs_parser_next(parser, njs_parser_expression);
return njs_parser_after(parser, current, NULL, 0,
njs_parser_cover_parenthesized_expression_after);
}
njs_lexer_consume_token(parser->lexer, 1);
return NJS_OK;
}
static njs_int_t
njs_parser_binding_identifier_pattern(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
/*
* BindingIdentifier )
* BindingPattern )
*/
switch (token->type) {
/* BindingIdentifier */
case NJS_TOKEN_NAME:
njs_parser_next(parser, njs_parser_cover_parenthesized_expression_end);
break;
case NJS_TOKEN_YIELD:
njs_parser_next(parser, njs_parser_cover_parenthesized_expression_end);
break;
case NJS_TOKEN_AWAIT:
njs_parser_next(parser, njs_parser_cover_parenthesized_expression_end);
break;
/* BindingPattern */
case NJS_TOKEN_OPEN_BRACKET:
njs_parser_next(parser, njs_parser_array_binding_pattern);
njs_lexer_consume_token(parser->lexer, 1);
return njs_parser_after(parser, current, NULL, 0,
njs_parser_cover_parenthesized_expression_end);
case NJS_TOKEN_OPEN_BRACE:
njs_parser_next(parser, njs_parser_object_binding_pattern);
njs_lexer_consume_token(parser->lexer, 1);
return njs_parser_after(parser, current, NULL, 0,
njs_parser_cover_parenthesized_expression_end);
default:
return NJS_ERROR;
}
njs_lexer_consume_token(parser->lexer, 1);
return NJS_OK;
}
static njs_int_t
njs_parser_cover_parenthesized_expression_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
/*
* )
* ,)
* , ... BindingIdentifier )
* , ... BindingPattern )
*/
if (token->type == NJS_TOKEN_CLOSE_PARENTHESIS) {
goto shift_stack;
}
if (token->type != NJS_TOKEN_COMMA) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
token = njs_lexer_token(parser->lexer, 0);
if (njs_slow_path(token == NULL)) {
return NJS_ERROR;
}
if (token->type == NJS_TOKEN_CLOSE_PARENTHESIS) {
goto shift_stack;
}
if(token->type != NJS_TOKEN_ELLIPSIS) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
njs_parser_next(parser, njs_parser_binding_identifier_pattern);
return NJS_OK;
shift_stack:
njs_lexer_consume_token(parser->lexer, 1);
return njs_parser_stack_pop(parser);
}
static njs_int_t
njs_parser_cover_parenthesized_expression_end(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
if (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
return njs_parser_stack_pop(parser);
}
/*
* 12.2.5 Array Initializer.
*/
static njs_int_t
njs_parser_array_literal(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
parser->target = parser->node;
parser->node = NULL;
njs_parser_next(parser, njs_parser_array_element_list);
return NJS_OK;
}
static njs_int_t
njs_parser_array_element_list(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
njs_parser_node_t *array;
array = parser->target;
switch (token->type) {
case NJS_TOKEN_CLOSE_BRACKET:
njs_lexer_consume_token(parser->lexer, 1);
parser->node = array;
return njs_parser_stack_pop(parser);
case NJS_TOKEN_COMMA:
njs_lexer_consume_token(parser->lexer, 1);
array->ctor = 1;
array->u.length++;
return NJS_OK;
case NJS_TOKEN_ELLIPSIS:
njs_lexer_consume_token(parser->lexer, 1);
njs_parser_next(parser, njs_parser_assignment_expression);
return njs_parser_after(parser, current, array, 0,
njs_parser_array_spread_element);
default:
break;
}
njs_parser_next(parser, njs_parser_assignment_expression);
return njs_parser_after(parser, current, array, 0, njs_parser_array_after);
}
static njs_int_t
njs_parser_array_after(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
njs_int_t ret;
if (parser->ret != NJS_OK) {
return njs_parser_failed(parser);
}
ret = njs_parser_array_item(parser, parser->target, parser->node);
if (ret != NJS_OK) {
return NJS_ERROR;
}
switch (token->type) {
case NJS_TOKEN_COMMA:
njs_lexer_consume_token(parser->lexer, 1);
/* Fall through. */
case NJS_TOKEN_CLOSE_BRACKET:
njs_parser_next(parser, njs_parser_array_element_list);
break;
default:
return njs_parser_failed(parser);
}
return NJS_OK;
}
static njs_int_t
njs_parser_array_spread_element(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
if (parser->ret != NJS_OK || token->type != NJS_TOKEN_CLOSE_BRACKET) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
parser->node = parser->target;
return njs_parser_stack_pop(parser);
}
/*
* 12.2.6 Object Initializer.
*/
static njs_int_t
njs_parser_object_literal(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
njs_parser_node_t *node;
node = njs_parser_node_new(parser, 0);
if (node == NULL) {
return NJS_ERROR;
}
node->left = parser->node;
parser->node = NULL;
parser->target = node;
njs_parser_next(parser, njs_parser_property_definition_list);
return njs_parser_after(parser, current, node, 1,
njs_parser_object_literal_after);
}
static njs_int_t
njs_parser_object_literal_after(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
if (token->type == NJS_TOKEN_COMMA) {
njs_lexer_consume_token(parser->lexer, 1);
token = njs_lexer_token(parser->lexer, 1);
if (token == NULL) {
return NJS_ERROR;
}
}
if (token->type != NJS_TOKEN_CLOSE_BRACE) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
parser->node = parser->target->left;
njs_parser_node_free(parser, parser->target);
parser->target = NULL;
return njs_parser_stack_pop(parser);
}
static njs_int_t
njs_parser_property_definition_list(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
njs_parser_next(parser, njs_parser_property_definition);
return njs_parser_after(parser, current, parser->target, 1,
njs_parser_property_definition_list_after);
}
static njs_int_t
njs_parser_property_definition_list_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
if (token->type != NJS_TOKEN_COMMA) {
return njs_parser_stack_pop(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
njs_parser_next(parser, njs_parser_property_definition);
return njs_parser_after(parser, current, parser->target, 1,
njs_parser_property_definition_list_after);
}
njs_inline njs_parser_node_t *
njs_parser_property_name_node(njs_parser_t *parser, njs_lexer_token_t *token)
{
njs_int_t ret;
njs_parser_node_t *property;
if (token->type == NJS_TOKEN_NUMBER) {
property = njs_parser_node_new(parser, NJS_TOKEN_NUMBER);
if (property != NULL) {
njs_set_number(&property->u.value, token->number);
}
} else if (token->type == NJS_TOKEN_ESCAPE_STRING) {
property = njs_parser_node_new(parser, NJS_TOKEN_STRING);
if (property != NULL) {
ret = njs_parser_escape_string_create(parser, token,
&property->u.value);
if (ret != NJS_TOKEN_STRING) {
return NULL;
}
}
} else {
property = njs_parser_node_string(parser->vm, token, parser);
}
if (property != NULL) {
property->token_line = token->line;
}
return property;
}
njs_inline njs_int_t
njs_parser_property_name(njs_parser_t *parser, njs_queue_link_t *current,
unsigned consume)
{
njs_lexer_token_t *token;
njs_parser_node_t *property;
if (consume > 1) {
token = njs_lexer_token(parser->lexer, 0);
if (token == NULL) {
return NJS_ERROR;
}
property = njs_parser_property_name_node(parser, token);
if (property == NULL) {
return NJS_ERROR;
}
parser->target->right = property;
parser->target->index = (token->type == NJS_TOKEN_NAME);
}
njs_lexer_consume_token(parser->lexer, consume);
parser->node = NULL;
njs_parser_next(parser, njs_parser_assignment_expression);
return njs_parser_after(parser, current, parser->target, 1,
njs_parser_property_definition_after);
}
static njs_int_t
njs_parser_property_definition_ident(njs_parser_t *parser,
njs_lexer_token_t *token, njs_parser_node_t *temp)
{
temp->right = njs_parser_node_string(parser->vm, token, parser);
if (temp->right == NULL) {
return NJS_ERROR;
}
temp->right->index = NJS_TOKEN_OPEN_BRACKET;
parser->node = njs_parser_reference(parser, token);
if (parser->node == NULL) {
return NJS_ERROR;
}
njs_lexer_consume_token(parser->lexer, 1);
token = njs_lexer_token(parser->lexer, 0);
if (token == NULL) {
return NJS_ERROR;
}
/* CoverInitializedName */
if (token->type == NJS_TOKEN_ASSIGNMENT) {
return njs_parser_not_supported(parser, token);
}
njs_parser_next(parser, njs_parser_property_definition_after);
return NJS_OK;
}
static njs_int_t
njs_parser_property_definition(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
njs_str_t *name;
njs_token_type_t accessor;
njs_lexer_token_t *next;
njs_parser_node_t *temp, *property;
temp = parser->target;
switch (token->type) {
case NJS_TOKEN_CLOSE_BRACE:
return njs_parser_stack_pop(parser);
/* PropertyName */
case NJS_TOKEN_STRING:
case NJS_TOKEN_ESCAPE_STRING:
case NJS_TOKEN_NUMBER:
next = njs_lexer_peek_token(parser->lexer, token, 0);
if (next == NULL) {
return NJS_ERROR;
}
if (next->type == NJS_TOKEN_COLON) {
return njs_parser_property_name(parser, current, 2);
} else if (next->type == NJS_TOKEN_OPEN_PARENTHESIS) {
goto method_definition;
}
njs_lexer_consume_token(parser->lexer, 1);
return njs_parser_failed(parser);
/* ComputedPropertyName */
case NJS_TOKEN_OPEN_BRACKET:
njs_lexer_consume_token(parser->lexer, 1);
njs_parser_next(parser, njs_parser_assignment_expression);
return njs_parser_after(parser, current, temp, 1,
njs_parser_computed_property_name_after);
case NJS_TOKEN_ELLIPSIS:
return njs_parser_not_supported(parser, token);
default:
if (!njs_lexer_token_is_identifier_name(token)) {
return njs_parser_reject(parser);
}
next = njs_lexer_peek_token(parser->lexer, token, 0);
if (next == NULL) {
return NJS_ERROR;
}
/* PropertyName */
if (next->type == NJS_TOKEN_COLON) {
return njs_parser_property_name(parser, current, 2);
/* MethodDefinition */
} else if (next->type == NJS_TOKEN_OPEN_PARENTHESIS) {
goto method_definition;
} else if (njs_lexer_token_is_reserved(token)) {
njs_lexer_consume_token(parser->lexer, 1);
return njs_parser_failed(parser);
}
name = &token->text;
if (name->length == 3 && (memcmp(name->start, "get", 3) == 0
|| memcmp(name->start, "set", 3) == 0))
{
accessor = (name->start[0] == 'g') ? NJS_TOKEN_PROPERTY_GETTER
: NJS_TOKEN_PROPERTY_SETTER;
temp->right = (njs_parser_node_t *) (uintptr_t) accessor;
njs_parser_next(parser, njs_parser_get_set);
return NJS_OK;
}
return njs_parser_property_definition_ident(parser, token, temp);
}
method_definition:
property = njs_parser_property_name_node(parser, token);
if (property == NULL) {
return NJS_ERROR;
}
temp->right = property;
temp->right->index = NJS_TOKEN_OPEN_BRACKET;
njs_parser_next(parser, njs_parser_method_definition);
return njs_parser_after(parser, current, temp, 1,
njs_parser_property_definition_after);
}
static njs_int_t
njs_parser_property_definition_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
njs_int_t ret;
njs_str_t name;
njs_bool_t proto_init;
njs_parser_node_t *property, *temp;
static const njs_str_t proto_string = njs_str("__proto__");
temp = parser->target;
property = temp->right;
proto_init = 0;
if (property->index != NJS_TOKEN_OPEN_BRACKET
&& njs_is_string(&property->u.value))
{
njs_string_get(&property->u.value, &name);
if (njs_slow_path(njs_strstr_eq(&name, &proto_string))) {
if (temp->token_type == NJS_TOKEN_PROTO_INIT) {
njs_parser_syntax_error(parser,
"Duplicate __proto__ fields are not allowed "
"in object literals");
return NJS_ERROR;
}
temp->token_type = NJS_TOKEN_PROTO_INIT;
proto_init = 1;
}
}
if (property->index != 0) {
property->index = 0;
}
ret = njs_parser_object_property(parser, temp->left, property,
parser->node, proto_init);
if (ret != NJS_OK) {
return NJS_ERROR;
}
temp->right = NULL;
return njs_parser_stack_pop(parser);
}
static njs_int_t
njs_parser_computed_property_name_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
njs_parser_node_t *expr;
if (token->type != NJS_TOKEN_CLOSE_BRACKET) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
token = njs_lexer_token(parser->lexer, 0);
if (token == NULL) {
return NJS_ERROR;
}
/*
* For further identification.
* In njs_parser_property_definition_after() index will be reset to zero.
*/
parser->node->index = NJS_TOKEN_OPEN_BRACKET;
parser->target->right = parser->node;
if (token->type == NJS_TOKEN_COLON) {
return njs_parser_property_name(parser, current, 1);
/* MethodDefinition */
} else if (token->type == NJS_TOKEN_OPEN_PARENTHESIS) {
expr = njs_parser_node_new(parser, NJS_TOKEN_FUNCTION_EXPRESSION);
if (expr == NULL) {
return NJS_ERROR;
}
expr->token_line = token->line;
parser->node = expr;
njs_lexer_consume_token(parser->lexer, 1);
njs_parser_next(parser, njs_parser_function_lambda);
return njs_parser_after(parser, current, parser->target, 1,
njs_parser_property_definition_after);
}
return njs_parser_failed(parser);
}
static njs_int_t
njs_parser_initializer(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
njs_parser_node_t *node;
if (token->type != NJS_TOKEN_ASSIGNMENT) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
node = parser->node;
parser->node = NULL;
njs_parser_next(parser, njs_parser_assignment_expression);
return njs_parser_after(parser, current, node, 1,
njs_parser_initializer_after);
}
static njs_int_t
njs_parser_initializer_after(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
njs_parser_node_t *stmt;
stmt = njs_parser_node_new(parser, NJS_TOKEN_STATEMENT);
if (stmt == NULL) {
return NJS_ERROR;
}
stmt->left = NULL;
stmt->right = parser->target;
parser->target->right = parser->node;
parser->node = stmt;
return njs_parser_stack_pop(parser);
}
static njs_int_t
njs_parser_initializer_assign(njs_parser_t *parser, njs_token_type_t type)
{
njs_parser_node_t *assign;
assign = njs_parser_node_new(parser, type);
if (assign == NULL) {
return NJS_ERROR;
}
assign->u.operation = NJS_VMCODE_MOVE;
assign->left = parser->node;
/* assign->right in njs_parser_initializer_after. */
parser->node = assign;
return NJS_OK;
}
/*
* 12.3 Left-Hand-Side Expressions.
*/
static njs_int_t
njs_parser_property(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
njs_parser_node_t *node, *prop_node;
/*
* [ Expression ]
* . IdentifierName
* TemplateLiteral
*/
switch (token->type) {
case NJS_TOKEN_OPEN_BRACKET:
node = njs_parser_node_new(parser, NJS_TOKEN_PROPERTY);
if (node == NULL) {
return NJS_ERROR;
}
node->u.operation = NJS_VMCODE_PROPERTY_GET;
node->left = parser->node;
node->token_line = token->line;
parser->node = NULL;
njs_lexer_consume_token(parser->lexer, 1);
njs_parser_next(parser, njs_parser_expression);
return njs_parser_after(parser, current, node, 1,
njs_parser_member_expression_bracket);
case NJS_TOKEN_DOT:
token = njs_lexer_peek_token(parser->lexer, token, 0);
if (token == NULL) {
return NJS_ERROR;
}
if (njs_lexer_token_is_identifier_name(token)) {
node = njs_parser_node_new(parser, NJS_TOKEN_PROPERTY);
if (node == NULL) {
return NJS_ERROR;
}
node->u.operation = NJS_VMCODE_PROPERTY_GET;
node->token_line = token->line;
prop_node = njs_parser_node_string(parser->vm, token, parser);
if (prop_node == NULL) {
return NJS_ERROR;
}
prop_node->token_line = token->line;
node->left = parser->node;
node->right = prop_node;
parser->node = node;
njs_lexer_consume_token(parser->lexer, 2);
return NJS_AGAIN;
}
njs_lexer_consume_token(parser->lexer, 1);
return NJS_DECLINED;
case NJS_TOKEN_GRAVE:
node = njs_parser_create_call(parser, parser->node, 0);
if (node == NULL) {
return NJS_ERROR;
}
node->token_line = token->line;
parser->node = node;
njs_parser_next(parser, njs_parser_template_literal);
break;
default:
return NJS_DONE;
}
return NJS_OK;
}
static njs_int_t
njs_parser_member_expression(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
njs_int_t ret;
/*
* PrimaryExpression
* MemberExpression [ Expression ]
* MemberExpression . IdentifierName
* MemberExpression TemplateLiteral
* SuperProperty
* MetaProperty
* new MemberExpression Arguments
*/
switch (token->type) {
/* SuperProperty */
case NJS_TOKEN_SUPER:
/* TODO: By specification. */
(void) njs_parser_super_property;
return njs_parser_not_supported(parser, token);
/* MetaProperty */
case NJS_TOKEN_IMPORT:
/* TODO: By specification. */
(void) njs_parser_member_expression_import;
return njs_parser_not_supported(parser, token);
case NJS_TOKEN_NEW:
njs_lexer_consume_token(parser->lexer, 1);
njs_parser_next(parser, njs_parser_member_expression_new);
break;
default:
ret = njs_parser_primary_expression_test(parser, token, current);
if (ret != NJS_OK) {
if (ret == NJS_DONE) {
njs_parser_next(parser, njs_parser_member_expression_next);
return NJS_OK;
}
if (njs_is_error(&parser->vm->retval)) {
return NJS_DONE;
}
return ret;
}
break;
}
return njs_parser_after(parser, current, NULL, 1,
njs_parser_member_expression_next);
}
static njs_int_t
njs_parser_member_expression_next(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
njs_int_t ret;
/*
* [ Expression ]
* . IdentifierName
* TemplateLiteral
*/
ret = njs_parser_property(parser, token, current);
switch (ret) {
case NJS_AGAIN:
return NJS_OK;
case NJS_DONE:
return njs_parser_stack_pop(parser);
case NJS_DECLINED:
return njs_parser_failed(parser);
default:
break;
}
return njs_parser_after(parser, current, NULL, 1,
njs_parser_member_expression_next);
}
static njs_int_t
njs_parser_member_expression_bracket(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
if (token->type != NJS_TOKEN_CLOSE_BRACKET) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
parser->target->right = parser->node;
parser->node = parser->target;
return njs_parser_stack_pop(parser);
}
static njs_int_t
njs_parser_member_expression_new_next(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
njs_int_t ret;
/*
* PrimaryExpression
* SuperProperty
* MetaProperty
* Arguments
*/
switch (token->type) {
/* SuperProperty */
case NJS_TOKEN_SUPER:
(void) njs_parser_super_property;
return njs_parser_not_supported(parser, token);
/* MetaProperty */
case NJS_TOKEN_IMPORT:
(void) njs_parser_member_expression_import;
return njs_parser_not_supported(parser, token);
default:
ret = njs_parser_primary_expression_test(parser, token, current);
if (ret != NJS_OK) {
if (ret == NJS_DONE) {
njs_parser_next(parser, njs_parser_member_expression_next);
return NJS_OK;
}
return ret;
}
return njs_parser_after(parser, current, NULL, 1,
njs_parser_member_expression_next);
}
}
static njs_int_t
njs_parser_super_property(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
/*
* [ Expression ]
* . IdentifierName
*/
if (token->type == NJS_TOKEN_OPEN_BRACKET) {
parser->node = NULL;
njs_parser_next(parser, njs_parser_expression);
return njs_parser_after(parser, current, NULL, 1,
njs_parser_close_bracked);
}
if (token->type != NJS_TOKEN_DOT) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
token = njs_lexer_token(parser->lexer, 0);
if (token == NULL) {
return NJS_ERROR;
}
if (!njs_lexer_token_is_identifier_name(token)) {
return njs_parser_failed(parser);
}
return njs_parser_stack_pop(parser);
}
static njs_int_t
njs_parser_member_expression_import(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
/*
* import . meta
*/
if (token->type != NJS_TOKEN_DOT) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
token = njs_lexer_token(parser->lexer, 0);
if (token == NULL) {
return NJS_ERROR;
}
if (token->type != NJS_TOKEN_META) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
return njs_parser_stack_pop(parser);
}
static njs_int_t
njs_parser_member_expression_new(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
/*
* new MemberExpression Arguments
* new . target
*/
if (token->type != NJS_TOKEN_DOT) {
njs_parser_next(parser, njs_parser_member_expression_new_next);
return njs_parser_after(parser, current, NULL, 1,
njs_parser_member_expression_new_after);
}
/* njs_lexer_consume_token(parser->lexer, 1); */
token = njs_lexer_token(parser->lexer, 0);
if (token == NULL) {
return NJS_ERROR;
}
if (token->type != NJS_TOKEN_TARGET) {
return njs_parser_failed(parser);
}
/* njs_lexer_consume_token(parser->lexer, 1); */
/* return njs_parser_stack_pop(parser); */
return njs_parser_not_supported(parser, token);
}
static njs_int_t
njs_parser_member_expression_new_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
njs_parser_node_t *func;
if (token->type != NJS_TOKEN_OPEN_PARENTHESIS) {
parser->node = njs_parser_create_call(parser, parser->node, 1);
if (parser->node == NULL) {
return NJS_ERROR;
}
parser->node->token_line = token->line;
return njs_parser_stack_pop(parser);
}
func = njs_parser_create_call(parser, parser->node, 1);
if (func == NULL) {
return NJS_ERROR;
}
func->token_line = token->line;
parser->node = func;
njs_lexer_consume_token(parser->lexer, 1);
njs_parser_next(parser, njs_parser_arguments);
return njs_parser_after(parser, current, func, 1,
njs_parser_member_expression_new_args);
}
static njs_int_t
njs_parser_member_expression_new_args(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
parser->node = parser->target;
return njs_parser_stack_pop(parser);
}
static njs_parser_node_t *
njs_parser_create_call(njs_parser_t *parser, njs_parser_node_t *node,
uint8_t ctor)
{
njs_parser_node_t *func;
switch (node->token_type) {
case NJS_TOKEN_NAME:
func = node;
func->token_type = NJS_TOKEN_FUNCTION_CALL;
break;
case NJS_TOKEN_PROPERTY:
func = njs_parser_node_new(parser, NJS_TOKEN_METHOD_CALL);
if (func == NULL) {
return NULL;
}
func->left = node;
break;
default:
/*
* NJS_TOKEN_METHOD_CALL,
* NJS_TOKEN_FUNCTION_CALL,
* NJS_TOKEN_FUNCTION_EXPRESSION,
* NJS_TOKEN_OPEN_PARENTHESIS,
* NJS_TOKEN_EVAL.
*/
func = njs_parser_node_new(parser, NJS_TOKEN_FUNCTION_CALL);
if (func == NULL) {
return NULL;
}
func->left = node;
break;
}
func->ctor = ctor;
return func;
}
static njs_int_t
njs_parser_call_expression(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
njs_int_t ret;
/*
* CoverCallExpressionAndAsyncArrowHead
* SuperCall
* ImportCall
* CallExpression Arguments
* CallExpression [ Expression ]
* CallExpression . IdentifierName
* CallExpression TemplateLiteral
*/
switch (token->type) {
/* MemberExpression or SuperCall */
case NJS_TOKEN_SUPER:
return njs_parser_not_supported(parser, token);
case NJS_TOKEN_IMPORT:
return njs_parser_not_supported(parser, token);
default:
break;
}
njs_parser_next(parser, njs_parser_member_expression);
ret = njs_parser_after(parser, current, NULL, 1,
njs_parser_call_expression_args);
if (ret != NJS_OK) {
return NJS_ERROR;
}
return njs_parser_after(parser, current, NULL, 1,
njs_parser_call_expression_after);
}
static njs_int_t
njs_parser_call_expression_args(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
njs_parser_node_t *func;
if (token->type != NJS_TOKEN_OPEN_PARENTHESIS) {
return njs_parser_failed(parser);
}
func = njs_parser_create_call(parser, parser->node, 0);
if (func == NULL) {
return NJS_ERROR;
}
func->token_line = token->line;
parser->node = func;
njs_lexer_consume_token(parser->lexer, 1);
njs_parser_next(parser, njs_parser_arguments);
return njs_parser_after(parser, current, func, 1,
njs_parser_left_hand_side_expression_node);
}
static njs_int_t
njs_parser_call_expression_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
njs_int_t ret;
njs_parser_node_t *func;
/*
* Arguments
* [ Expression ]
* . IdentifierName
* TemplateLiteral
*/
switch (token->type) {
case NJS_TOKEN_OPEN_PARENTHESIS:
func = njs_parser_create_call(parser, parser->node, 0);
if (func == NULL) {
return NJS_ERROR;
}
func->token_line = token->line;
parser->node = func;
njs_lexer_consume_token(parser->lexer, 1);
njs_parser_next(parser, njs_parser_arguments);
ret = njs_parser_after(parser, current, func, 1,
njs_parser_left_hand_side_expression_node);
if (ret != NJS_OK) {
return NJS_ERROR;
}
break;
default:
ret = njs_parser_property(parser, token, current);
switch (ret) {
case NJS_AGAIN:
return NJS_OK;
case NJS_DONE:
return njs_parser_stack_pop(parser);
case NJS_DECLINED:
return njs_parser_failed(parser);
default:
break;
}
break;
}
return njs_parser_after(parser, current, NULL, 1,
njs_parser_call_expression_after);
}
static njs_int_t
njs_parser_arguments(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
/*
* )
* ArgumentList )
* ArgumentList , )
*/
if (token->type == NJS_TOKEN_CLOSE_PARENTHESIS) {
njs_lexer_consume_token(parser->lexer, 1);
return njs_parser_stack_pop(parser);
}
njs_parser_next(parser, njs_parser_argument_list);
return njs_parser_after(parser, current, NULL, 1,
njs_parser_parenthesis_or_comma);
}
static njs_int_t
njs_parser_parenthesis_or_comma(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
if (token->type == NJS_TOKEN_CLOSE_PARENTHESIS) {
njs_lexer_consume_token(parser->lexer, 1);
return njs_parser_stack_pop(parser);
}
if (token->type != NJS_TOKEN_COMMA) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
token = njs_lexer_token(parser->lexer, 0);
if (njs_slow_path(token == NULL)) {
return NJS_ERROR;
}
if (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
return njs_parser_stack_pop(parser);
}
static njs_int_t
njs_parser_argument_list(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
/*
* AssignmentExpression
* ... AssignmentExpression
* ArgumentList , AssignmentExpression
* ArgumentList , ... AssignmentExpression
*/
if (token->type == NJS_TOKEN_ELLIPSIS) {
njs_lexer_consume_token(parser->lexer, 1);
}
njs_parser_next(parser, njs_parser_assignment_expression);
return njs_parser_after(parser, current, parser->node, 1,
njs_parser_argument_list_after);
}
static njs_int_t
njs_parser_argument_list_after(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
njs_parser_node_t *node;
node = njs_parser_node_new(parser, NJS_TOKEN_ARGUMENT);
if (node == NULL) {
return NJS_ERROR;
}
if (parser->target->index == 0) {
node->index = NJS_SCOPE_CALLEE_ARGUMENTS;
} else {
node->index = parser->target->index + sizeof(njs_value_t);
}
node->token_line = token->line;
node->left = parser->node;
parser->node->dest = node;
parser->target->right = node;
parser->node = node;
if (token->type == NJS_TOKEN_COMMA) {
njs_lexer_consume_token(parser->lexer, 1);
token = njs_lexer_token(parser->lexer, 0);
if (token == NULL) {
return NJS_ERROR;
}
if (token->type == NJS_TOKEN_CLOSE_PARENTHESIS) {
return njs_parser_stack_pop(parser);
}
return njs_parser_argument_list(parser, token, current);
}
return njs_parser_stack_pop(parser);
}
static njs_int_t
njs_parser_optional_expression_after(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
if (token->type != NJS_TOKEN_CONDITIONAL) {
return njs_parser_stack_pop(parser);
}
token = njs_lexer_peek_token(parser->lexer, token, 0);
if (token == NULL) {
return NJS_ERROR;
}
if (token->type != NJS_TOKEN_DOT) {
return njs_parser_stack_pop(parser);
}
njs_parser_next(parser, njs_parser_optional_chain);
return njs_parser_after(parser, current, NULL, 1,
njs_parser_optional_expression_after);
}
static njs_int_t
njs_parser_optional_chain(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
njs_int_t ret;
njs_parser_node_t *func;
/*
* ? . Arguments
* ? . [ Expression ]
* ? . IdentifierName
* ? . TemplateLiteral
* OptionalChain Arguments
* OptionalChain [ Expression ]
* OptionalChain . IdentifierName
* OptionalChain TemplateLiteral
*/
if (token->type != NJS_TOKEN_CONDITIONAL) {
return njs_parser_failed(parser);
}
token = njs_lexer_peek_token(parser->lexer, token, 0);
if (token == NULL) {
return NJS_ERROR;
}
if (token->type != NJS_TOKEN_DOT) {
return njs_parser_failed(parser);
}
njs_lexer_consume_token(parser->lexer, 1);
token = njs_lexer_token(parser->lexer, 0);
if (token == NULL) {
return NJS_ERROR;
}
switch (token->type) {
case NJS_TOKEN_OPEN_PARENTHESIS:
func = njs_parser_create_call(parser, parser->node, 0);
if (func == NULL) {
return NJS_ERROR;
}
func->token_line = token->line;
parser->node = func;
njs_lexer_consume_token(parser->lexer, 2);
njs_parser_next(parser, njs_parser_arguments);
ret = njs_parser_after(parser, current, func, 1,
njs_parser_left_hand_side_expression_node);
if (ret != NJS_OK) {
return NJS_ERROR;
}
break;
default:
ret = njs_parser_property(parser, token, current);
switch (ret) {
case NJS_DONE:
case NJS_DECLINED:
return njs_parser_failed(parser);
default:
break;
}
break;
}
return njs_parser_after(parser, current, NULL, 1,
njs_parser_optional_chain_after);
}
static njs_int_t
njs_parser_optional_chain_after(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
njs_int_t ret;
njs_parser_node_t *func;
/*
* OptionalChain Arguments
* OptionalChain [ Expression ]
* OptionalChain . IdentifierName
* OptionalChain TemplateLiteral
*/
switch (token->type) {
case NJS_TOKEN_OPEN_PARENTHESIS:
func = njs_parser_create_call(parser, parser->node, 0);
if (func == NULL) {
return NJS_ERROR;
}
func->token_line = token->line;
parser->node = func;
njs_lexer_consume_token(parser->lexer, 1);
njs_parser_next(parser, njs_parser_arguments);
ret = njs_parser_after(parser, current, func, 1,
njs_parser_left_hand_side_expression_node);
if (ret != NJS_OK) {
return NJS_ERROR;
}
break;
default:
ret = njs_parser_property(parser, token, current);
switch (ret) {
case NJS_AGAIN:
return NJS_OK;
case NJS_DONE:
return njs_parser_stack_pop(parser);
case NJS_DECLINED:
return njs_parser_failed(parser);
default:
break;
}
break;
}
return njs_parser_after(parser, current, NULL, 1,
njs_parser_optional_chain_after);
}
static njs_int_t
njs_parser_new_expression(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
if (token->type != NJS_TOKEN_NEW) {
parser->node = NULL;
njs_parser_next(parser, njs_parser_member_expression_new);
return NJS_OK;
}
njs_lexer_consume_token(parser->lexer, 1);
return njs_parser_after(parser, current, NULL, 1,
njs_parser_new_expression_after);
}
static njs_int_t
njs_parser_new_expression_after(njs_parser_t *parser, njs_lexer_token_t *token,
njs_queue_link_t *current)
{
njs_parser_node_t *func;
if (token->type == NJS_TOKEN_OPEN_PARENTHESIS) {
njs_parser_next(parser, njs_parser_member_expression_new_after);
return NJS_OK;
}
func = njs_parser_create_call(parser, parser->node, 1);
if (func == NULL) {
return NJS_ERROR;
}
func->token_line = token->line;
parser->node = func;
return njs_parser_stack_pop(parser);
}
static njs_int_t
njs_parser_left_hand_side_expression(njs_parser_t *parser,
njs_lexer_token_t *token, njs_queue_link_t *current)
{
/*
* NewExpression = new MemberExpression
* CallExpression = MemberExpression Arguments
* OptionalExpression = MemberExpression OptionalChain
*/
switch (token->type) {
/* NewExpression or MemberExpression */
case NJS_TOKEN_NEW:
token = njs_lexer_peek_token(parser->lexer, token, 0);
if (token == NULL) {
return NJS_ERROR;
}
if (token->type == NJS_TOKEN_NEW) {
njs_lexer_consume_token(parser->lexer, 1);
njs_parser_next(parser, njs_parser_new_expression);