| |
| /* |
| * 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); |
|