Coverage Report

Created: 2024-07-23 06:06

/src/njs/src/njs_parser.c
Line
Count
Source (jump to first uncovered line)
1
2
/*
3
 * Copyright (C) Igor Sysoev
4
 * Copyright (C) Alexander Borisov
5
 * Copyright (C) NGINX, Inc.
6
 */
7
8
9
#include <njs_main.h>
10
11
12
static njs_int_t njs_parser_scope_begin(njs_parser_t *parser, njs_scope_t type,
13
    njs_bool_t init_this);
14
static void njs_parser_scope_end(njs_parser_t *parser);
15
16
static njs_int_t njs_parser_check_error_state(njs_parser_t *parser,
17
    njs_lexer_token_t *token, njs_queue_link_t *current);
18
19
static njs_int_t njs_parser_primary_expression_test(njs_parser_t *parser,
20
    njs_lexer_token_t *token, njs_queue_link_t *current);
21
static njs_int_t njs_parser_regexp_literal(njs_parser_t *parser,
22
    njs_lexer_token_t *token, njs_queue_link_t *current);
23
static njs_int_t njs_parser_template_literal(njs_parser_t *parser,
24
    njs_lexer_token_t *token, njs_queue_link_t *current);
25
static njs_int_t njs_parser_template_literal_string(njs_parser_t *parser,
26
    njs_lexer_token_t *token, njs_queue_link_t *current);
27
static njs_int_t njs_parser_template_literal_expression(
28
    njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
29
static njs_int_t njs_parser_cover_parenthesized_expression(
30
    njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
31
static njs_int_t njs_parser_binding_identifier_pattern(njs_parser_t *parser,
32
    njs_lexer_token_t *token, njs_queue_link_t *current);
33
static njs_int_t njs_parser_cover_parenthesized_expression_after(
34
    njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
35
static njs_int_t njs_parser_cover_parenthesized_expression_end(
36
    njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
37
38
static njs_int_t njs_parser_array_literal(njs_parser_t *parser,
39
    njs_lexer_token_t *token, njs_queue_link_t *current);
40
static njs_int_t njs_parser_array_element_list(njs_parser_t *parser,
41
    njs_lexer_token_t *token, njs_queue_link_t *current);
42
static njs_int_t njs_parser_array_after(njs_parser_t *parser,
43
    njs_lexer_token_t *token, njs_queue_link_t *current);
44
static njs_int_t njs_parser_array_spread_element(njs_parser_t *parser,
45
    njs_lexer_token_t *token, njs_queue_link_t *current);
46
47
static njs_int_t njs_parser_object_literal(njs_parser_t *parser,
48
    njs_lexer_token_t *token, njs_queue_link_t *current);
49
static njs_int_t njs_parser_object_literal_after(njs_parser_t *parser,
50
    njs_lexer_token_t *token, njs_queue_link_t *current);
51
static njs_int_t njs_parser_property_definition_list(njs_parser_t *parser,
52
    njs_lexer_token_t *token, njs_queue_link_t *current);
53
static njs_int_t njs_parser_property_definition_list_after(
54
    njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
55
static njs_int_t njs_parser_property_definition(njs_parser_t *parser,
56
    njs_lexer_token_t *token, njs_queue_link_t *current);
57
static njs_int_t njs_parser_property_definition_after(njs_parser_t *parser,
58
    njs_lexer_token_t *token, njs_queue_link_t *current);
59
static njs_int_t njs_parser_computed_property_name_after(njs_parser_t *parser,
60
    njs_lexer_token_t *token, njs_queue_link_t *current);
61
static njs_int_t njs_parser_computed_property_async_after(njs_parser_t *parser,
62
    njs_lexer_token_t *token, njs_queue_link_t *current);
63
static njs_int_t njs_parser_computed_property_name_handler(njs_parser_t *parser,
64
    njs_lexer_token_t *token, njs_queue_link_t *current, njs_bool_t async);
65
66
static njs_int_t njs_parser_initializer(njs_parser_t *parser,
67
    njs_lexer_token_t *token, njs_queue_link_t *current);
68
static njs_int_t njs_parser_initializer_after(njs_parser_t *parser,
69
    njs_lexer_token_t *token, njs_queue_link_t *current);
70
static njs_int_t njs_parser_initializer_assign(njs_parser_t *parser,
71
    njs_token_type_t type);
72
73
static njs_int_t njs_parser_member_expression(njs_parser_t *parser,
74
    njs_lexer_token_t *token, njs_queue_link_t *current);
75
static njs_int_t njs_parser_member_expression_next(njs_parser_t *parser,
76
    njs_lexer_token_t *token, njs_queue_link_t *current);
77
static njs_int_t njs_parser_member_expression_bracket(njs_parser_t *parser,
78
    njs_lexer_token_t *token, njs_queue_link_t *current);
79
static njs_int_t njs_parser_member_expression_new_next(njs_parser_t *parser,
80
    njs_lexer_token_t *token, njs_queue_link_t *current);
81
static njs_int_t njs_parser_super_property(njs_parser_t *parser,
82
    njs_lexer_token_t *token, njs_queue_link_t *current);
83
static njs_int_t njs_parser_member_expression_import(njs_parser_t *parser,
84
    njs_lexer_token_t *token, njs_queue_link_t *current);
85
static njs_int_t njs_parser_member_expression_new(njs_parser_t *parser,
86
    njs_lexer_token_t *token, njs_queue_link_t *current);
87
static njs_int_t njs_parser_member_expression_new_after(njs_parser_t *parser,
88
    njs_lexer_token_t *token, njs_queue_link_t *current);
89
static njs_int_t njs_parser_member_expression_new_args(njs_parser_t *parser,
90
    njs_lexer_token_t *token, njs_queue_link_t *current);
91
92
static njs_parser_node_t *njs_parser_create_call(njs_parser_t *parser,
93
    njs_parser_node_t *node, uint8_t ctor);
94
static njs_int_t njs_parser_call_expression(njs_parser_t *parser,
95
    njs_lexer_token_t *token, njs_queue_link_t *current);
96
static njs_int_t njs_parser_call_expression_args(njs_parser_t *parser,
97
    njs_lexer_token_t *token, njs_queue_link_t *current);
98
static njs_int_t njs_parser_call_expression_after(njs_parser_t *parser,
99
    njs_lexer_token_t *token, njs_queue_link_t *current);
100
static njs_int_t njs_parser_arguments(njs_parser_t *parser,
101
    njs_lexer_token_t *token, njs_queue_link_t *current);
102
static njs_int_t njs_parser_parenthesis_or_comma(njs_parser_t *parser,
103
    njs_lexer_token_t *token, njs_queue_link_t *current);
104
static njs_int_t njs_parser_argument_list(njs_parser_t *parser,
105
    njs_lexer_token_t *token, njs_queue_link_t *current);
106
static njs_int_t njs_parser_argument_list_after(njs_parser_t *parser,
107
    njs_lexer_token_t *token, njs_queue_link_t *current);
108
static njs_int_t njs_parser_optional_expression_after(njs_parser_t *parser,
109
    njs_lexer_token_t *token, njs_queue_link_t *current);
110
static njs_int_t njs_parser_optional_chain(njs_parser_t *parser,
111
    njs_lexer_token_t *token, njs_queue_link_t *current);
112
static njs_int_t njs_parser_optional_chain_after(njs_parser_t *parser,
113
    njs_lexer_token_t *token, njs_queue_link_t *current);
114
static njs_int_t njs_parser_new_expression(njs_parser_t *parser,
115
    njs_lexer_token_t *token, njs_queue_link_t *current);
116
static njs_int_t njs_parser_new_expression_after(njs_parser_t *parser,
117
    njs_lexer_token_t *token, njs_queue_link_t *current);
118
static njs_int_t njs_parser_left_hand_side_expression(njs_parser_t *parser,
119
    njs_lexer_token_t *token, njs_queue_link_t *current);
120
static njs_int_t njs_parser_left_hand_side_expression_after(
121
    njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
122
static njs_int_t njs_parser_left_hand_side_expression_node(
123
    njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
124
static njs_int_t njs_parser_left_hand_side_expression_optional(
125
    njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
126
static njs_int_t njs_parser_update_expression(njs_parser_t *parser,
127
    njs_lexer_token_t *token, njs_queue_link_t *current);
128
static njs_int_t njs_parser_update_expression_post(njs_parser_t *parser,
129
    njs_lexer_token_t *token, njs_queue_link_t *current);
130
static njs_int_t njs_parser_update_expression_unary(njs_parser_t *parser,
131
    njs_lexer_token_t *token, njs_queue_link_t *current);
132
133
static njs_int_t njs_parser_unary_expression(njs_parser_t *parser,
134
    njs_lexer_token_t *token, njs_queue_link_t *current);
135
static njs_int_t njs_parser_unary_expression_after(njs_parser_t *parser,
136
    njs_lexer_token_t *token, njs_queue_link_t *current);
137
static njs_int_t njs_parser_unary_expression_next(njs_parser_t *parser,
138
    njs_lexer_token_t *token, njs_queue_link_t *current);
139
static njs_int_t njs_parser_await(njs_parser_t *parser,
140
    njs_lexer_token_t *token, njs_queue_link_t *current);
141
static njs_int_t njs_parser_await_after(njs_parser_t *parser,
142
    njs_lexer_token_t *token, njs_queue_link_t *current);
143
144
static njs_int_t njs_parser_exponentiation_expression(njs_parser_t *parser,
145
    njs_lexer_token_t *token, njs_queue_link_t *current);
146
static njs_int_t njs_parser_exponentiation_expression_match(
147
    njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
148
149
static njs_int_t njs_parser_multiplicative_expression(njs_parser_t *parser,
150
    njs_lexer_token_t *token, njs_queue_link_t *current);
151
static njs_int_t njs_parser_multiplicative_expression_match(
152
    njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
153
154
static njs_int_t njs_parser_additive_expression(njs_parser_t *parser,
155
    njs_lexer_token_t *token, njs_queue_link_t *current);
156
static njs_int_t njs_parser_additive_expression_match(njs_parser_t *parser,
157
    njs_lexer_token_t *token, njs_queue_link_t *current);
158
159
static njs_int_t njs_parser_shift_expression(njs_parser_t *parser,
160
    njs_lexer_token_t *token, njs_queue_link_t *current);
161
static njs_int_t njs_parser_shift_expression_match(njs_parser_t *parser,
162
    njs_lexer_token_t *token, njs_queue_link_t *current);
163
164
static njs_int_t njs_parser_relational_expression(njs_parser_t *parser,
165
    njs_lexer_token_t *token, njs_queue_link_t *current);
166
static njs_int_t njs_parser_relational_expression_match(njs_parser_t *parser,
167
    njs_lexer_token_t *token, njs_queue_link_t *current);
168
169
static njs_int_t njs_parser_equality_expression(njs_parser_t *parser,
170
    njs_lexer_token_t *token, njs_queue_link_t *current);
171
static njs_int_t njs_parser_equality_expression_match(njs_parser_t *parser,
172
    njs_lexer_token_t *token, njs_queue_link_t *current);
173
174
static njs_int_t njs_parser_bitwise_AND_expression(njs_parser_t *parser,
175
    njs_lexer_token_t *token, njs_queue_link_t *current);
176
static njs_int_t njs_parser_bitwise_AND_expression_and(njs_parser_t *parser,
177
    njs_lexer_token_t *token, njs_queue_link_t *current);
178
static njs_int_t njs_parser_bitwise_XOR_expression(njs_parser_t *parser,
179
    njs_lexer_token_t *token, njs_queue_link_t *current);
180
static njs_int_t njs_parser_bitwise_XOR_expression_xor(njs_parser_t *parser,
181
    njs_lexer_token_t *token, njs_queue_link_t *current);
182
static njs_int_t njs_parser_bitwise_OR_expression(njs_parser_t *parser,
183
    njs_lexer_token_t *token, njs_queue_link_t *current);
184
static njs_int_t njs_parser_bitwise_OR_expression_or(njs_parser_t *parser,
185
    njs_lexer_token_t *token, njs_queue_link_t *current);
186
187
static njs_int_t njs_parser_logical_AND_expression(njs_parser_t *parser,
188
    njs_lexer_token_t *token, njs_queue_link_t *current);
189
static njs_int_t njs_parser_logical_AND_expression_and(njs_parser_t *parser,
190
    njs_lexer_token_t *token, njs_queue_link_t *current);
191
static njs_int_t njs_parser_logical_OR_expression(njs_parser_t *parser,
192
    njs_lexer_token_t *token, njs_queue_link_t *current);
193
static njs_int_t njs_parser_logical_OR_expression_or(njs_parser_t *parser,
194
    njs_lexer_token_t *token, njs_queue_link_t *current);
195
static njs_int_t njs_parser_coalesce_expression(njs_parser_t *parser,
196
    njs_lexer_token_t *token, njs_queue_link_t *current);
197
static njs_int_t njs_parser_short_circuit_expression(njs_parser_t *parser,
198
    njs_lexer_token_t *token, njs_queue_link_t *current);
199
200
static njs_int_t njs_parser_conditional_expression(njs_parser_t *parser,
201
    njs_lexer_token_t *token, njs_queue_link_t *current);
202
static njs_int_t njs_parser_conditional_question_mark(njs_parser_t *parser,
203
    njs_lexer_token_t *token, njs_queue_link_t *current);
204
static njs_int_t njs_parser_conditional_colon(njs_parser_t *parser,
205
    njs_lexer_token_t *token, njs_queue_link_t *current);
206
static njs_int_t njs_parser_conditional_colon_after(njs_parser_t *parser,
207
    njs_lexer_token_t *token, njs_queue_link_t *current);
208
209
static njs_int_t njs_parser_assignment_expression(njs_parser_t *parser,
210
    njs_lexer_token_t *token, njs_queue_link_t *current);
211
static njs_int_t njs_parser_match_arrow_expression(njs_parser_t *parser,
212
    njs_lexer_token_t *token);
213
static njs_int_t njs_parser_assignment_expression_after(njs_parser_t *parser,
214
    njs_lexer_token_t *token, njs_queue_link_t *current);
215
static njs_int_t njs_parser_assignment_operator(njs_parser_t *parser,
216
    njs_lexer_token_t *token, njs_queue_link_t *current);
217
static njs_int_t njs_parser_assignment_operator_after(njs_parser_t *parser,
218
    njs_lexer_token_t *token, njs_queue_link_t *current);
219
220
static njs_int_t njs_parser_expression(njs_parser_t *parser,
221
    njs_lexer_token_t *token, njs_queue_link_t *current);
222
static njs_int_t njs_parser_expression_comma(njs_parser_t *parser,
223
    njs_lexer_token_t *token, njs_queue_link_t *current);
224
225
static njs_int_t njs_parser_statement(njs_parser_t *parser,
226
    njs_lexer_token_t *token, njs_queue_link_t *current);
227
static njs_int_t njs_parser_statement_wo_node(njs_parser_t *parser,
228
    njs_lexer_token_t *token, njs_queue_link_t *current);
229
static njs_int_t njs_parser_statement_after(njs_parser_t *parser,
230
    njs_lexer_token_t *token, njs_queue_link_t *current);
231
static njs_int_t njs_parser_declaration(njs_parser_t *parser,
232
    njs_lexer_token_t *token, njs_queue_link_t *current);
233
static njs_int_t njs_parser_hoistable_declaration(njs_parser_t *parser,
234
    njs_lexer_token_t *token, njs_queue_link_t *current);
235
236
static njs_int_t njs_parser_block_statement(njs_parser_t *parser,
237
    njs_lexer_token_t *token, njs_queue_link_t *current);
238
static njs_int_t njs_parser_block_statement_open_brace(njs_parser_t *parser,
239
    njs_lexer_token_t *token, njs_queue_link_t *current);
240
static njs_int_t njs_parser_block_statement_close_brace(njs_parser_t *parser,
241
    njs_lexer_token_t *token, njs_queue_link_t *current);
242
static njs_int_t njs_parser_statement_list(njs_parser_t *parser,
243
    njs_lexer_token_t *token, njs_queue_link_t *current);
244
static njs_int_t njs_parser_statement_list_next(njs_parser_t *parser,
245
    njs_lexer_token_t *token, njs_queue_link_t *current);
246
static njs_int_t njs_parser_statement_list_item(njs_parser_t *parser,
247
    njs_lexer_token_t *token, njs_queue_link_t *current);
248
249
static njs_int_t njs_parser_lexical_declaration(njs_parser_t *parser,
250
    njs_lexer_token_t *token, njs_queue_link_t *current);
251
static njs_int_t njs_parser_variable_statement(njs_parser_t *parser,
252
    njs_lexer_token_t *token, njs_queue_link_t *current);
253
static njs_int_t njs_parser_variable_declaration_list(njs_parser_t *parser,
254
    njs_lexer_token_t *token, njs_queue_link_t *current);
255
static njs_int_t njs_parser_variable_declaration_list_next(
256
    njs_parser_t *parser, njs_lexer_token_t *token, njs_queue_link_t *current);
257
static njs_int_t njs_parser_variable_declaration(njs_parser_t *parser,
258
    njs_lexer_token_t *token, njs_queue_link_t *current);
259
260
static njs_int_t njs_parser_binding_pattern(njs_parser_t *parser,
261
    njs_lexer_token_t *token, njs_queue_link_t *current);
262
static njs_int_t njs_parser_object_binding_pattern(njs_parser_t *parser,
263
    njs_lexer_token_t *token, njs_queue_link_t *current);
264
static njs_int_t njs_parser_array_binding_pattern(njs_parser_t *parser,
265
    njs_lexer_token_t *token, njs_queue_link_t *current);
266
267
static njs_int_t njs_parser_expression_statement(njs_parser_t *parser,
268
    njs_lexer_token_t *token, njs_queue_link_t *current);
269
static njs_int_t njs_parser_expression_statement_after(njs_parser_t *parser,
270
    njs_lexer_token_t *token, njs_queue_link_t *current);
271
272
static njs_int_t njs_parser_if_statement(njs_parser_t *parser,
273
    njs_lexer_token_t *token, njs_queue_link_t *current);
274
static njs_int_t njs_parser_if_close_parenthesis(njs_parser_t *parser,
275
    njs_lexer_token_t *token, njs_queue_link_t *current);
276
static njs_int_t njs_parser_else_statement(njs_parser_t *parser,
277
    njs_lexer_token_t *token, njs_queue_link_t *current);
278
static njs_int_t njs_parser_else_statement_after(njs_parser_t *parser,
279
    njs_lexer_token_t *token, njs_queue_link_t *current);
280
281
static njs_int_t njs_parser_iteration_statement_do(njs_parser_t *parser,
282
    njs_lexer_token_t *token, njs_queue_link_t *current);
283
static njs_int_t njs_parser_iteration_statement_do_while(njs_parser_t *parser,
284
    njs_lexer_token_t *token, njs_queue_link_t *current);
285
static njs_int_t njs_parser_do_while_semicolon(njs_parser_t *parser,
286
    njs_lexer_token_t *token, njs_queue_link_t *current);
287
288
static njs_int_t njs_parser_iteration_statement_while(njs_parser_t *parser,
289
    njs_lexer_token_t *token, njs_queue_link_t *current);
290
static njs_int_t njs_parser_while_statement(njs_parser_t *parser,
291
    njs_lexer_token_t *token, njs_queue_link_t *current);
292
static njs_int_t njs_parser_while_after(njs_parser_t *parser,
293
    njs_lexer_token_t *token, njs_queue_link_t *current);
294
295
static njs_int_t njs_parser_iteration_statement_for(njs_parser_t *parser,
296
    njs_lexer_token_t *token, njs_queue_link_t *current);
297
static njs_int_t njs_parser_for_expression_map_continue(
298
    njs_parser_t *parser, njs_lexer_token_t *token,
299
    njs_queue_link_t *current);
300
static njs_int_t njs_parser_for_expression_map_reparse(
301
    njs_parser_t *parser, njs_lexer_token_t *token,
302
    njs_queue_link_t *current);
303
static njs_int_t njs_parser_expression_continue_op(njs_parser_t *parser,
304
    njs_lexer_token_t *token, njs_queue_link_t *current);
305
static njs_int_t njs_parser_expression_continue_assign_comma(
306
    njs_parser_t *parser, njs_lexer_token_t *token,
307
    njs_queue_link_t *current);
308
static njs_int_t njs_parser_for_in_statement_statement(njs_parser_t *parser,
309
    njs_lexer_token_t *token, njs_queue_link_t *current);
310
static njs_int_t njs_parser_iteration_statement_for_map(njs_parser_t *parser,
311
    njs_lexer_token_t *token, njs_queue_link_t *current);
312
static njs_int_t njs_parser_for_var_binding_or_var_list(njs_parser_t *parser,
313
    njs_lexer_token_t *token, njs_queue_link_t *current,
314
    njs_token_type_t token_type);
315
static njs_int_t njs_parser_for_var_in_statement(njs_parser_t *parser,
316
    njs_lexer_token_t *token, njs_queue_link_t *current);
317
static njs_int_t njs_parser_for_var_in_statement_after(njs_parser_t *parser,
318
    njs_lexer_token_t *token, njs_queue_link_t *current);
319
static njs_int_t njs_parser_for_var_in_of_expression(njs_parser_t *parser,
320
    njs_lexer_token_t *token, njs_queue_link_t *current);
321
static njs_int_t njs_parser_for_in_statement(njs_parser_t *parser,
322
    njs_lexer_token_t *token, njs_queue_link_t *current);
323
static njs_int_t njs_parser_for_in_statement_after(njs_parser_t *parser,
324
    njs_lexer_token_t *token, njs_queue_link_t *current);
325
static njs_int_t njs_parser_for_expression(njs_parser_t *parser,
326
    njs_lexer_token_t *token, njs_queue_link_t *current);
327
static njs_int_t njs_parser_for_expression_end(njs_parser_t *parser,
328
    njs_lexer_token_t *token, njs_queue_link_t *current);
329
static njs_int_t njs_parser_for_end(njs_parser_t *parser,
330
    njs_lexer_token_t *token, njs_queue_link_t *current);
331
332
static njs_int_t njs_parser_switch_statement(njs_parser_t *parser,
333
    njs_lexer_token_t *token, njs_queue_link_t *current);
334
static njs_int_t njs_parser_switch_statement_after(njs_parser_t *parser,
335
    njs_lexer_token_t *token, njs_queue_link_t *current);
336
static njs_int_t njs_parser_switch_block(njs_parser_t *parser,
337
    njs_lexer_token_t *token, njs_queue_link_t *current);
338
static njs_int_t njs_parser_switch_block_after(njs_parser_t *parser,
339
    njs_lexer_token_t *token, njs_queue_link_t *current);
340
static njs_int_t njs_parser_switch_case(njs_parser_t *parser,
341
    njs_lexer_token_t *token, njs_queue_link_t *current);
342
static njs_int_t njs_parser_switch_case_wo_def(njs_parser_t *parser,
343
    njs_lexer_token_t *token, njs_queue_link_t *current);
344
static njs_int_t njs_parser_switch_case_def(njs_parser_t *parser,
345
    njs_lexer_token_t *token, njs_queue_link_t *current,
346
    njs_bool_t with_default);
347
static njs_int_t njs_parser_switch_case_after(njs_parser_t *parser,
348
    njs_lexer_token_t *token, njs_queue_link_t *current);
349
static njs_int_t njs_parser_switch_case_block(njs_parser_t *parser,
350
    njs_lexer_token_t *token, njs_queue_link_t *current);
351
static njs_int_t njs_parser_switch_case_after_wo_def(njs_parser_t *parser,
352
    njs_lexer_token_t *token, njs_queue_link_t *current);
353
static njs_int_t njs_parser_switch_case_block_wo_def(njs_parser_t *parser,
354
    njs_lexer_token_t *token, njs_queue_link_t *current);
355
356
static njs_int_t njs_parser_continue_statement(njs_parser_t *parser,
357
    njs_lexer_token_t *token, njs_queue_link_t *current);
358
359
static njs_int_t njs_parser_break_statement(njs_parser_t *parser,
360
    njs_lexer_token_t *token, njs_queue_link_t *current);
361
362
static njs_int_t njs_parser_break_continue(njs_parser_t *parser,
363
    njs_lexer_token_t *token, njs_token_type_t type);
364
365
static njs_int_t njs_parser_return_statement(njs_parser_t *parser,
366
    njs_lexer_token_t *token, njs_queue_link_t *current);
367
static njs_int_t njs_parser_return_statement_after(njs_parser_t *parser,
368
    njs_lexer_token_t *token, njs_queue_link_t *current);
369
370
static njs_int_t njs_parser_with_statement(njs_parser_t *parser,
371
    njs_lexer_token_t *token, njs_queue_link_t *current);
372
373
static njs_int_t njs_parser_labelled_statement(njs_parser_t *parser,
374
    njs_lexer_token_t *token, njs_queue_link_t *current);
375
static njs_int_t njs_parser_labelled_statement_after(njs_parser_t *parser,
376
    njs_lexer_token_t *token, njs_queue_link_t *current);
377
378
static njs_int_t njs_parser_throw_statement(njs_parser_t *parser,
379
    njs_lexer_token_t *token, njs_queue_link_t *current);
380
static njs_int_t njs_parser_throw_statement_after(njs_parser_t *parser,
381
    njs_lexer_token_t *token, njs_queue_link_t *current);
382
383
static njs_int_t njs_parser_try_statement(njs_parser_t *parser,
384
    njs_lexer_token_t *token, njs_queue_link_t *current);
385
static njs_int_t njs_parser_catch_or_finally(njs_parser_t *parser,
386
    njs_lexer_token_t *token, njs_queue_link_t *current);
387
static njs_int_t njs_parser_catch_after(njs_parser_t *parser,
388
    njs_lexer_token_t *token, njs_queue_link_t *current);
389
static njs_int_t njs_parser_catch_parenthesis(njs_parser_t *parser,
390
    njs_lexer_token_t *token, njs_queue_link_t *current);
391
static njs_int_t njs_parser_catch_statement_open_brace(njs_parser_t *parser,
392
    njs_lexer_token_t *token, njs_queue_link_t *current);
393
static njs_int_t njs_parser_catch_finally(njs_parser_t *parser,
394
    njs_lexer_token_t *token, njs_queue_link_t *current);
395
396
static njs_int_t njs_parser_debugger_statement(njs_parser_t *parser,
397
    njs_lexer_token_t *token, njs_queue_link_t *current);
398
399
static njs_int_t njs_parser_function_declaration(njs_parser_t *parser,
400
    njs_lexer_token_t *token, njs_queue_link_t *current);
401
static njs_int_t njs_parser_function_declaration_after(njs_parser_t *parser,
402
    njs_lexer_token_t *token, njs_queue_link_t *current);
403
static njs_int_t njs_parser_function_parse(njs_parser_t *parser,
404
    njs_lexer_token_t *token, njs_queue_link_t *current);
405
static njs_int_t njs_parser_function_expression(njs_parser_t *parser,
406
    njs_lexer_token_t *token, njs_queue_link_t *current);
407
static njs_int_t njs_parser_function_expression_after(njs_parser_t *parser,
408
    njs_lexer_token_t *token, njs_queue_link_t *current);
409
static njs_int_t njs_parser_unique_formal_parameters(njs_parser_t *parser,
410
    njs_lexer_token_t *token, njs_queue_link_t *current);
411
static njs_int_t njs_parser_formal_parameters(njs_parser_t *parser,
412
    njs_lexer_token_t *token, njs_queue_link_t *current);
413
static njs_int_t njs_parser_formal_parameters_after(njs_parser_t *parser,
414
    njs_lexer_token_t *token, njs_queue_link_t *current);
415
416
static njs_int_t njs_parser_arrow_function(njs_parser_t *parser,
417
    njs_lexer_token_t *token, njs_queue_link_t *current);
418
static njs_int_t njs_parser_arrow_function_args_after(njs_parser_t *parser,
419
    njs_lexer_token_t *token, njs_queue_link_t *current);
420
static njs_int_t njs_parser_arrow_function_arrow(njs_parser_t *parser,
421
    njs_lexer_token_t *token, njs_queue_link_t *current);
422
static njs_int_t njs_parser_arrow_function_body_after(njs_parser_t *parser,
423
    njs_lexer_token_t *token, njs_queue_link_t *current);
424
425
static njs_int_t njs_parser_method_definition(njs_parser_t *parser,
426
    njs_lexer_token_t *token, njs_queue_link_t *current);
427
static njs_int_t njs_parser_get_set(njs_parser_t *parser,
428
    njs_lexer_token_t *token, njs_queue_link_t *current);
429
static njs_int_t njs_parser_get_set_after(njs_parser_t *parser,
430
    njs_lexer_token_t *token, njs_queue_link_t *current);
431
static njs_int_t njs_parser_get_after(njs_parser_t *parser,
432
    njs_lexer_token_t *token, njs_queue_link_t *current);
433
static njs_int_t njs_parser_set_after(njs_parser_t *parser,
434
    njs_lexer_token_t *token, njs_queue_link_t *current);
435
static njs_int_t njs_parser_function_lambda(njs_parser_t *parser,
436
    njs_lexer_token_t *token, njs_queue_link_t *current);
437
static njs_int_t njs_parser_function_lambda_args_after(njs_parser_t *parser,
438
    njs_lexer_token_t *token, njs_queue_link_t *current);
439
static njs_int_t njs_parser_function_lambda_body_after(njs_parser_t *parser,
440
    njs_lexer_token_t *token, njs_queue_link_t *current);
441
442
static njs_int_t njs_parser_export(njs_parser_t *parser,
443
    njs_lexer_token_t *token, njs_queue_link_t *current);
444
static njs_int_t njs_parser_export_after(njs_parser_t *parser,
445
    njs_lexer_token_t *token, njs_queue_link_t *current);
446
447
static njs_int_t njs_parser_import(njs_parser_t *parser,
448
    njs_lexer_token_t *token, njs_queue_link_t *current);
449
static njs_int_t njs_parser_export_sink(njs_parser_t *parser);
450
451
static njs_parser_node_t *njs_parser_return_set(njs_parser_t *parser,
452
    njs_parser_node_t *expr);
453
static njs_parser_node_t *njs_parser_variable_node(njs_parser_t *parser,
454
    uintptr_t unique_id, njs_variable_type_t type, njs_variable_t  **retvar);
455
456
static njs_parser_node_t *njs_parser_reference(njs_parser_t *parser,
457
    njs_lexer_token_t *token);
458
459
static njs_parser_node_t *njs_parser_argument(njs_parser_t *parser,
460
    njs_parser_node_t *expr, njs_index_t index);
461
462
static njs_int_t njs_parser_object_property(njs_parser_t *parser,
463
    njs_parser_node_t *parent, njs_parser_node_t *property,
464
    njs_parser_node_t *value, njs_bool_t proto_init);
465
static njs_int_t njs_parser_property_accessor(njs_parser_t *parser,
466
    njs_parser_node_t *parent, njs_parser_node_t *property,
467
    njs_parser_node_t *value, njs_token_type_t accessor);
468
static njs_int_t njs_parser_array_item(njs_parser_t *parser,
469
    njs_parser_node_t *array, njs_parser_node_t *value);
470
static njs_int_t njs_parser_template_string(njs_parser_t *parser,
471
    njs_lexer_token_t *token);
472
static njs_token_type_t njs_parser_escape_string_create(njs_parser_t *parser,
473
    njs_lexer_token_t *token, njs_value_t *value);
474
static njs_int_t njs_parser_escape_string_calc_length(njs_parser_t *parser,
475
    njs_lexer_token_t *token, size_t *out_size, size_t *out_length);
476
477
static void njs_parser_serialize_tree(njs_chb_t *chain,
478
    njs_parser_node_t *node, njs_int_t *ret, size_t indent);
479
static njs_int_t njs_parser_serialize_node(njs_chb_t *chain,
480
    njs_parser_node_t *node);
481
482
483
#define njs_parser_chain_top(parser)                                          \
484
79.5k
    ((parser)->scope->top)
485
486
487
#define njs_parser_chain_top_set(parser, node)                                \
488
445k
    (parser)->scope->top = node
489
490
491
njs_inline njs_int_t
492
njs_parser_not_supported(njs_parser_t *parser, njs_lexer_token_t *token)
493
2.69k
{
494
2.69k
    if (token->type != NJS_TOKEN_END) {
495
2.10k
        njs_parser_syntax_error(parser, "Token \"%V\" not supported "
496
2.10k
                                "in this version", &token->text);
497
2.10k
    } else {
498
591
        njs_parser_syntax_error(parser, "Not supported in this version");
499
591
    }
500
501
2.69k
    return NJS_DONE;
502
2.69k
}
503
504
505
njs_inline njs_int_t
506
njs_parser_reject(njs_parser_t *parser)
507
6.56k
{
508
6.56k
    njs_queue_link_t          *link;
509
6.56k
    njs_parser_stack_entry_t  *entry;
510
511
181k
    while (!njs_queue_is_empty(&parser->stack)) {
512
181k
        entry = njs_queue_link_data(njs_queue_first(&parser->stack),
513
181k
                                    njs_parser_stack_entry_t, link);
514
515
181k
        link = njs_queue_first(&parser->stack);
516
181k
        njs_queue_remove(link);
517
518
181k
        if (!entry->optional) {
519
6.56k
            njs_parser_next(parser, entry->state);
520
6.56k
            parser->target = entry->node;
521
522
6.56k
            return NJS_DECLINED;
523
6.56k
        }
524
181k
    }
525
526
0
    return njs_parser_failed(parser);
527
6.56k
}
528
529
530
njs_int_t
531
njs_parser_init(njs_vm_t *vm, njs_parser_t *parser, njs_parser_scope_t *scope,
532
    njs_str_t *file, u_char *start, u_char *end, njs_uint_t runtime)
533
51.0k
{
534
51.0k
    njs_lexer_t  *lexer;
535
536
51.0k
    njs_memzero(parser, sizeof(njs_parser_t));
537
538
51.0k
    parser->scope = scope;
539
540
51.0k
    lexer = &parser->lexer0;
541
51.0k
    parser->lexer = lexer;
542
543
51.0k
    parser->use_lhs = 0;
544
545
51.0k
    return njs_lexer_init(vm, lexer, file, start, end, runtime, 0);
546
51.0k
}
547
548
549
njs_int_t
550
njs_parser(njs_vm_t *vm, njs_parser_t *parser)
551
51.0k
{
552
51.0k
    njs_int_t                        ret;
553
51.0k
    njs_str_t                        str;
554
51.0k
    njs_lexer_token_t                *token;
555
51.0k
    const njs_lexer_keyword_entry_t  *keyword;
556
557
51.0k
    parser->vm = vm;
558
559
51.0k
    njs_set_invalid(&vm->exception);
560
561
51.0k
    if (parser->scope == NULL) {
562
51.0k
        ret = njs_parser_scope_begin(parser,
563
51.0k
                                     parser->module ? NJS_SCOPE_FUNCTION
564
51.0k
                                                    : NJS_SCOPE_GLOBAL, 1);
565
51.0k
        if (njs_slow_path(ret != NJS_OK)) {
566
0
            return NJS_ERROR;
567
0
        }
568
569
51.0k
    } else {
570
0
        parser->scope->top = NULL;
571
0
        parser->node = NULL;
572
0
        parser->ret = NJS_OK;
573
0
    }
574
575
    /* Add this as first variable. */
576
51.0k
    njs_string_get(&njs_string_undefined, &str);
577
578
51.0k
    keyword = njs_lexer_keyword(str.start, str.length);
579
51.0k
    if (njs_slow_path(keyword == NULL)) {
580
0
        return NJS_ERROR;
581
0
    }
582
583
51.0k
    parser->undefined_id = (uintptr_t) keyword->value;
584
585
51.0k
    njs_queue_init(&parser->stack);
586
587
51.0k
    parser->target = NULL;
588
51.0k
    njs_parser_next(parser, njs_parser_statement_list);
589
590
51.0k
    ret = njs_parser_after(parser, njs_queue_first(&parser->stack),
591
51.0k
                           NULL, 0, njs_parser_check_error_state);
592
51.0k
    if (ret != NJS_OK) {
593
0
        return ret;
594
0
    }
595
596
64.4M
    do {
597
64.4M
        token = njs_lexer_token(parser->lexer, 0);
598
64.4M
        if (njs_slow_path(token == NULL)) {
599
0
            return NJS_ERROR;
600
0
        }
601
602
64.4M
        parser->ret = parser->state(parser, token,
603
64.4M
                                    njs_queue_first(&parser->stack));
604
605
64.4M
    } while (parser->ret != NJS_DONE && parser->ret != NJS_ERROR);
606
607
51.0k
    if (parser->ret != NJS_DONE) {
608
4.34k
        return NJS_ERROR;
609
4.34k
    }
610
611
46.7k
    if (njs_is_error(&vm->exception)) {
612
32.4k
        return NJS_ERROR;
613
32.4k
    }
614
615
14.2k
    if (parser->node == NULL) {
616
        /* Empty string, just semicolons or variables declarations. */
617
618
0
        parser->node = njs_parser_node_new(parser, 0);
619
0
        if (njs_slow_path(parser->node == NULL)) {
620
0
            return NJS_ERROR;
621
0
        }
622
0
    }
623
624
14.2k
    if (parser->module) {
625
0
        ret = njs_parser_export_sink(parser);
626
0
        if (ret != NJS_OK) {
627
0
            return NJS_ERROR;
628
0
        }
629
630
14.2k
    } else {
631
14.2k
        parser->node->token_type = NJS_TOKEN_END;
632
14.2k
        parser->node->token_line = parser->lexer->line;
633
634
14.2k
        njs_parser_chain_top_set(parser, parser->node);
635
14.2k
    }
636
637
14.2k
    return NJS_OK;
638
14.2k
}
639
640
641
static njs_int_t
642
njs_parser_check_error_state(njs_parser_t *parser, njs_lexer_token_t *token,
643
    njs_queue_link_t *current)
644
2
{
645
2
    return njs_parser_failed(parser);
646
2
}
647
648
649
njs_int_t
650
njs_parser_failed_state(njs_parser_t *parser, njs_lexer_token_t *token,
651
    njs_queue_link_t *current)
652
20.0k
{
653
20.0k
    if (token->type != NJS_TOKEN_END) {
654
20.0k
        njs_parser_syntax_error(parser, "Unexpected token \"%V\"",
655
20.0k
                                &token->text);
656
20.0k
    } else {
657
8
        njs_parser_syntax_error(parser, "Unexpected end of input");
658
8
    }
659
660
20.0k
    return NJS_DONE;
661
20.0k
}
662
663
664
static njs_int_t
665
njs_parser_scope_begin(njs_parser_t *parser, njs_scope_t type,
666
    njs_bool_t init_this)
667
250k
{
668
250k
    njs_variable_t                   *var;
669
250k
    njs_parser_scope_t               *scope, *parent;
670
250k
    const njs_lexer_keyword_entry_t  *keyword;
671
672
250k
    static const njs_str_t  njs_this_str = njs_str("this");
673
674
250k
    scope = njs_mp_zalloc(parser->vm->mem_pool, sizeof(njs_parser_scope_t));
675
250k
    if (njs_slow_path(scope == NULL)) {
676
0
        return NJS_ERROR;
677
0
    }
678
679
250k
    scope->type = type;
680
681
250k
    njs_rbtree_init(&scope->variables, njs_parser_scope_rbtree_compare);
682
250k
    njs_rbtree_init(&scope->labels, njs_parser_scope_rbtree_compare);
683
250k
    njs_rbtree_init(&scope->references, njs_parser_scope_rbtree_compare);
684
685
250k
    parent = parser->scope;
686
250k
    scope->parent = parent;
687
250k
    parser->scope = scope;
688
689
250k
    if (type == NJS_SCOPE_FUNCTION || type == NJS_SCOPE_GLOBAL) {
690
147k
        if (init_this) {
691
            /* Add this as first variable. */
692
111k
            keyword = njs_lexer_keyword(njs_this_str.start,
693
111k
                                        njs_this_str.length);
694
111k
            if (njs_slow_path(keyword == NULL)) {
695
0
                return NJS_ERROR;
696
0
            }
697
698
111k
            var = njs_variable_add(parser, scope, (uintptr_t) keyword->value,
699
111k
                                   NJS_VARIABLE_VAR);
700
111k
            if (njs_slow_path(var == NULL)) {
701
0
                return NJS_ERROR;
702
0
            }
703
704
111k
            var->index = njs_scope_index(type, 0, NJS_LEVEL_LOCAL,
705
111k
                                         NJS_VARIABLE_VAR);
706
111k
        }
707
147k
    }
708
709
250k
    scope->items = 1;
710
711
250k
    return NJS_OK;
712
250k
}
713
714
715
static void
716
njs_parser_scope_end(njs_parser_t *parser)
717
117k
{
718
117k
    njs_parser_scope_t  *scope, *parent;
719
720
117k
    scope = parser->scope;
721
722
117k
    parent = scope->parent;
723
117k
    parser->scope = parent;
724
117k
}
725
726
727
intptr_t
728
njs_parser_scope_rbtree_compare(njs_rbtree_node_t *node1,
729
    njs_rbtree_node_t *node2)
730
5.52M
{
731
5.52M
    njs_variable_node_t  *lex_node1, *lex_node2;
732
733
5.52M
    lex_node1 = (njs_variable_node_t *) node1;
734
5.52M
    lex_node2 = (njs_variable_node_t *) node2;
735
736
5.52M
    if (lex_node1->key < lex_node2->key) {
737
1.44M
        return -1;
738
1.44M
    }
739
740
4.08M
    if (lex_node1->key > lex_node2->key) {
741
3.74M
        return 1;
742
3.74M
    }
743
744
338k
    return 0;
745
4.08M
}
746
747
748
static njs_int_t
749
njs_parser_generator_expression(njs_parser_t *parser, njs_lexer_token_t *token,
750
    njs_queue_link_t *current)
751
0
{
752
0
    return njs_parser_not_supported(parser, token);
753
0
}
754
755
756
static njs_int_t
757
njs_parser_class_expression(njs_parser_t *parser, njs_lexer_token_t *token,
758
    njs_queue_link_t *current)
759
0
{
760
0
    return njs_parser_not_supported(parser, token);
761
0
}
762
763
764
static njs_int_t
765
njs_parser_async_generator_expression(njs_parser_t *parser,
766
    njs_lexer_token_t *token, njs_queue_link_t *current)
767
0
{
768
0
    return njs_parser_not_supported(parser, token);
769
0
}
770
771
772
static njs_int_t
773
njs_parser_generator_declaration(njs_parser_t *parser, njs_lexer_token_t *token,
774
    njs_queue_link_t *current)
775
0
{
776
0
    return njs_parser_not_supported(parser, token);
777
0
}
778
779
780
static njs_int_t
781
njs_parser_class_declaration(njs_parser_t *parser, njs_lexer_token_t *token,
782
    njs_queue_link_t *current)
783
0
{
784
0
    return njs_parser_not_supported(parser, token);
785
0
}
786
787
788
static njs_int_t
789
njs_parser_function_or_generator_handler(njs_parser_t *parser,
790
    njs_lexer_token_t *token, njs_queue_link_t *current, njs_bool_t is_async)
791
6.08k
{
792
6.08k
    njs_parser_node_t  *node, *cur;
793
794
6.08k
    cur = parser->node;
795
796
6.08k
    if (token->type == NJS_TOKEN_MULTIPLICATION) {
797
0
        njs_lexer_consume_token(parser->lexer, 1);
798
0
        njs_parser_next(parser, njs_parser_generator_declaration);
799
800
6.08k
    } else {
801
6.08k
        if (is_async) {
802
0
            node = njs_parser_node_new(parser,
803
0
                                       NJS_TOKEN_ASYNC_FUNCTION_DECLARATION);
804
6.08k
        } else {
805
6.08k
            node = njs_parser_node_new(parser, NJS_TOKEN_FUNCTION_DECLARATION);
806
6.08k
        }
807
808
6.08k
        if (node == NULL) {
809
0
            return NJS_ERROR;
810
0
        }
811
812
6.08k
        node->token_line = token->line;
813
6.08k
        parser->node = node;
814
815
6.08k
        njs_lexer_consume_token(parser->lexer, 1);
816
6.08k
        njs_parser_next(parser, njs_parser_function_declaration);
817
6.08k
    }
818
819
6.08k
    return njs_parser_after(parser, current, cur, 1,
820
6.08k
                            njs_parser_statement_after);
821
6.08k
}
822
823
824
static njs_int_t
825
njs_parser_function_or_generator(njs_parser_t *parser,
826
    njs_lexer_token_t *token, njs_queue_link_t *current)
827
510k
{
828
510k
    if (token->type != NJS_TOKEN_FUNCTION) {
829
504k
        return NJS_DECLINED;
830
504k
    }
831
832
6.08k
    return njs_parser_function_or_generator_handler(parser, token, current, 0);
833
510k
}
834
835
836
static njs_int_t
837
njs_parser_async_function_or_generator(njs_parser_t *parser,
838
    njs_lexer_token_t *token, njs_queue_link_t *current)
839
504k
{
840
504k
    if (token->type != NJS_TOKEN_ASYNC) {
841
504k
        return NJS_DECLINED;
842
504k
    }
843
844
0
    token = njs_lexer_peek_token(parser->lexer, token, 1);
845
0
    if (token == NULL) {
846
0
        return NJS_ERROR;
847
0
    }
848
849
0
    if (token->type != NJS_TOKEN_FUNCTION) {
850
0
        return NJS_DECLINED;
851
0
    }
852
853
0
    njs_lexer_consume_token(parser->lexer, 1);
854
855
0
    return njs_parser_function_or_generator_handler(parser, token, current, 1);
856
0
}
857
858
859
njs_inline njs_int_t
860
njs_parser_expect_semicolon(njs_parser_t *parser, njs_lexer_token_t *token)
861
333k
{
862
333k
    if (token->type != NJS_TOKEN_SEMICOLON) {
863
294k
        if (parser->strict_semicolon
864
294k
            || (token->type != NJS_TOKEN_END
865
294k
                && token->type != NJS_TOKEN_CLOSE_BRACE
866
294k
                && parser->lexer->prev_type != NJS_TOKEN_LINE_END))
867
3.42k
        {
868
3.42k
            return NJS_DECLINED;
869
3.42k
        }
870
871
291k
        return NJS_OK;
872
294k
    }
873
874
38.5k
    njs_lexer_consume_token(parser->lexer, 1);
875
876
38.5k
    return NJS_OK;
877
333k
}
878
879
880
static njs_int_t
881
njs_parser_semicolon(njs_parser_t *parser, njs_lexer_token_t *token,
882
    njs_queue_link_t *current)
883
11.0k
{
884
11.0k
    if (njs_parser_expect_semicolon(parser, token) != NJS_OK) {
885
387
        return njs_parser_failed(parser);
886
387
    }
887
888
10.6k
    return njs_parser_stack_pop(parser);
889
11.0k
}
890
891
892
static njs_int_t
893
njs_parser_close_bracked(njs_parser_t *parser, njs_lexer_token_t *token,
894
    njs_queue_link_t *current)
895
0
{
896
0
    if (token->type != NJS_TOKEN_CLOSE_BRACKET) {
897
0
        return njs_parser_failed(parser);
898
0
    }
899
900
0
    njs_lexer_consume_token(parser->lexer, 1);
901
902
0
    return njs_parser_stack_pop(parser);
903
0
}
904
905
906
static njs_int_t
907
njs_parser_close_parenthesis(njs_parser_t *parser, njs_lexer_token_t *token,
908
    njs_queue_link_t *current)
909
23.8k
{
910
23.8k
    if (parser->ret != NJS_OK) {
911
1.85k
        return njs_parser_failed(parser);
912
1.85k
    }
913
914
21.9k
    if (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) {
915
341
        return njs_parser_failed(parser);
916
341
    }
917
918
21.6k
    njs_lexer_consume_token(parser->lexer, 1);
919
920
21.6k
    return njs_parser_stack_pop(parser);
921
21.9k
}
922
923
924
static njs_int_t
925
njs_parser_expression_parenthesis(njs_parser_t *parser,
926
    njs_lexer_token_t *token, njs_queue_link_t *current)
927
6.28k
{
928
6.28k
    if (token->type != NJS_TOKEN_OPEN_PARENTHESIS) {
929
0
        return njs_parser_failed(parser);
930
0
    }
931
932
6.28k
    njs_lexer_consume_token(parser->lexer, 1);
933
934
6.28k
    parser->node = NULL;
935
936
6.28k
    njs_parser_next(parser, njs_parser_expression);
937
938
6.28k
    return njs_parser_after(parser, current, NULL, 0,
939
6.28k
                            njs_parser_close_parenthesis);
940
6.28k
}
941
942
943
static njs_int_t
944
njs_parser_iteration_statement_for_end(njs_parser_t *parser,
945
    njs_lexer_token_t *token, njs_queue_link_t *current)
946
17.3k
{
947
17.3k
    parser->node->token_line = (uint32_t) (uintptr_t) parser->target;
948
17.3k
    parser->target = NULL;
949
950
17.3k
    njs_parser_scope_end(parser);
951
952
17.3k
    return njs_parser_stack_pop(parser);
953
17.3k
}
954
955
956
/*
957
 * 12.2 Primary Expression.
958
 */
959
static njs_int_t
960
njs_parser_primary_expression_test(njs_parser_t *parser,
961
    njs_lexer_token_t *token, njs_queue_link_t *current)
962
1.72M
{
963
1.72M
    njs_int_t          ret;
964
1.72M
    njs_lexer_token_t  *next;
965
1.72M
    njs_parser_node_t  *node;
966
967
1.72M
    switch (token->type) {
968
    /* IdentifierReference */
969
1.07k
    case NJS_TOKEN_THIS:
970
1.08k
    case NJS_TOKEN_NULL:
971
509k
    case NJS_TOKEN_NAME:
972
510k
    case NJS_TOKEN_YIELD:
973
510k
    case NJS_TOKEN_AWAIT:
974
510k
        goto reference;
975
976
0
    case NJS_TOKEN_TRUE:
977
0
        node = njs_parser_node_new(parser, token->type);
978
0
        if (node == NULL) {
979
0
            return NJS_ERROR;
980
0
        }
981
982
0
        node->u.value = njs_value_true;
983
0
        node->token_line = token->line;
984
985
0
        parser->node = node;
986
0
        goto done;
987
988
818
    case NJS_TOKEN_FALSE:
989
818
        node = njs_parser_node_new(parser, token->type);
990
818
        if (node == NULL) {
991
0
            return NJS_ERROR;
992
0
        }
993
994
818
        node->u.value = njs_value_false;
995
818
        node->token_line = token->line;
996
997
818
        parser->node = node;
998
818
        goto done;
999
1000
1.06M
    case NJS_TOKEN_NUMBER:
1001
1.06M
        node = njs_parser_node_new(parser, NJS_TOKEN_NUMBER);
1002
1.06M
        if (node == NULL) {
1003
0
            return NJS_ERROR;
1004
0
        }
1005
1006
1.06M
        njs_set_number(&node->u.value, token->number);
1007
1.06M
        node->token_line = token->line;
1008
1009
1.06M
        parser->node = node;
1010
1.06M
        goto done;
1011
1012
1.16k
    case NJS_TOKEN_STRING:
1013
1.16k
        node = njs_parser_node_new(parser, NJS_TOKEN_STRING);
1014
1.16k
        if (node == NULL) {
1015
0
            return NJS_ERROR;
1016
0
        }
1017
1018
1.16k
        node->token_line = token->line;
1019
1020
1.16k
        ret = njs_parser_string_create(parser->vm, token, &node->u.value);
1021
1.16k
        if (ret != NJS_OK) {
1022
0
            return NJS_ERROR;
1023
0
        }
1024
1025
1.16k
        parser->node = node;
1026
1.16k
        goto done;
1027
1028
2.04k
    case NJS_TOKEN_ESCAPE_STRING:
1029
        /* Internal optimization. This is not in the specification. */
1030
1031
2.04k
        node = njs_parser_node_new(parser, NJS_TOKEN_STRING);
1032
2.04k
        if (node == NULL) {
1033
0
            return NJS_ERROR;
1034
0
        }
1035
1036
2.04k
        node->token_line = token->line;
1037
1038
2.04k
        ret = njs_parser_escape_string_create(parser, token, &node->u.value);
1039
2.04k
        if (ret != NJS_TOKEN_STRING) {
1040
1.63k
            return NJS_ERROR;
1041
1.63k
        }
1042
1043
411
        parser->node = node;
1044
411
        goto done;
1045
1046
539
    case NJS_TOKEN_UNTERMINATED_STRING:
1047
        /* Internal optimization. This is not in the specification. */
1048
1049
539
        njs_parser_syntax_error(parser, "Unterminated string \"%V\"",
1050
539
                                &token->text);
1051
539
        return NJS_ERROR;
1052
1053
    /* ArrayLiteral */
1054
6.90k
    case NJS_TOKEN_OPEN_BRACKET:
1055
6.90k
        node = njs_parser_node_new(parser, NJS_TOKEN_ARRAY);
1056
6.90k
        if (node == NULL) {
1057
0
            return NJS_ERROR;
1058
0
        }
1059
1060
6.90k
        node->token_line = token->line;
1061
6.90k
        parser->node = node;
1062
1063
6.90k
        njs_parser_next(parser, njs_parser_array_literal);
1064
6.90k
        break;
1065
1066
    /* ObjectLiteral */
1067
8.83k
    case NJS_TOKEN_OPEN_BRACE:
1068
8.83k
        node = njs_parser_node_new(parser, NJS_TOKEN_OBJECT);
1069
8.83k
        if (node == NULL) {
1070
0
            return NJS_ERROR;
1071
0
        }
1072
1073
8.83k
        node->token_line = token->line;
1074
8.83k
        parser->node = node;
1075
1076
8.83k
        njs_parser_next(parser, njs_parser_object_literal);
1077
8.83k
        break;
1078
1079
    /* FunctionExpression */
1080
53.2k
    case NJS_TOKEN_FUNCTION:
1081
53.2k
        token = njs_lexer_peek_token(parser->lexer, token, 0);
1082
53.2k
        if (token == NULL) {
1083
0
            return NJS_ERROR;
1084
0
        }
1085
1086
        /* GeneratorExpression */
1087
53.2k
        if (token->type == NJS_TOKEN_MULTIPLICATION) {
1088
0
            njs_parser_next(parser, njs_parser_generator_expression);
1089
1090
53.2k
        } else {
1091
53.2k
            node = njs_parser_node_new(parser, NJS_TOKEN_FUNCTION_EXPRESSION);
1092
53.2k
            if (node == NULL) {
1093
0
                return NJS_ERROR;
1094
0
            }
1095
1096
53.2k
            node->token_line = token->line;
1097
53.2k
            parser->node = node;
1098
1099
53.2k
            njs_parser_next(parser, njs_parser_function_expression);
1100
53.2k
        }
1101
1102
53.2k
        break;
1103
1104
    /* ClassExpression */
1105
53.2k
    case NJS_TOKEN_CLASS:
1106
0
        njs_parser_next(parser, njs_parser_class_expression);
1107
0
        return NJS_OK;
1108
1109
    /* AsyncFunctionExpression */
1110
0
    case NJS_TOKEN_ASYNC:
1111
0
        next = njs_lexer_peek_token(parser->lexer, token, 1);
1112
0
        if (next == NULL) {
1113
0
            return NJS_ERROR;
1114
0
        }
1115
1116
0
        if (next->type != NJS_TOKEN_FUNCTION) {
1117
0
            goto reference;
1118
0
        }
1119
1120
0
        njs_lexer_consume_token(parser->lexer, 1);
1121
1122
0
        next = njs_lexer_peek_token(parser->lexer, next, 0);
1123
0
        if (njs_slow_path(next == NULL)) {
1124
0
            return NJS_ERROR;
1125
0
        }
1126
1127
        /* GeneratorExpression */
1128
0
        if (next->type == NJS_TOKEN_MULTIPLICATION) {
1129
0
            njs_parser_next(parser, njs_parser_async_generator_expression);
1130
1131
0
        } else {
1132
0
            node = njs_parser_node_new(parser,
1133
0
                                       NJS_TOKEN_ASYNC_FUNCTION_EXPRESSION);
1134
0
            if (node == NULL) {
1135
0
                return NJS_ERROR;
1136
0
            }
1137
1138
0
            node->token_line = next->line;
1139
0
            parser->node = node;
1140
1141
0
            njs_parser_next(parser, njs_parser_function_expression);
1142
0
        }
1143
1144
0
        break;
1145
1146
    /* RegularExpressionLiteral */
1147
14.1k
    case NJS_TOKEN_DIVISION:
1148
15.5k
    case NJS_TOKEN_DIVISION_ASSIGNMENT:
1149
15.5k
        node = njs_parser_node_new(parser, NJS_TOKEN_REGEXP);
1150
15.5k
        if (node == NULL) {
1151
0
            return NJS_ERROR;
1152
0
        }
1153
1154
15.5k
        node->token_line = token->line;
1155
15.5k
        parser->node = node;
1156
1157
15.5k
        ret = njs_parser_regexp_literal(parser, token, current);
1158
15.5k
        if (ret != NJS_OK) {
1159
2.00k
            return NJS_ERROR;
1160
2.00k
        }
1161
1162
13.5k
        goto done;
1163
1164
    /* TemplateLiteral */
1165
13.5k
    case NJS_TOKEN_GRAVE:
1166
2.15k
        node = njs_parser_node_new(parser, NJS_TOKEN_TEMPLATE_LITERAL);
1167
2.15k
        if (node == NULL) {
1168
0
            return NJS_ERROR;
1169
0
        }
1170
1171
2.15k
        node->token_line = token->line;
1172
2.15k
        parser->node = node;
1173
1174
2.15k
        njs_parser_next(parser, njs_parser_template_literal);
1175
2.15k
        return NJS_OK;
1176
1177
    /* CoverParenthesizedExpressionAndArrowParameterList */
1178
53.3k
    case NJS_TOKEN_OPEN_PARENTHESIS:
1179
53.3k
        njs_lexer_consume_token(parser->lexer, 1);
1180
1181
        /* TODO: By specification. */
1182
53.3k
        (void) njs_parser_cover_parenthesized_expression;
1183
1184
53.3k
        parser->node = NULL;
1185
1186
53.3k
        njs_parser_next(parser, njs_parser_expression);
1187
1188
53.3k
        return njs_parser_after(parser, current, NULL, 0,
1189
2.15k
                                njs_parser_close_parenthesis);
1190
1191
10.3k
    default:
1192
10.3k
        if (njs_lexer_token_is_identifier_reference(token)) {
1193
3.78k
            goto reference;
1194
3.78k
        }
1195
1196
6.55k
        return njs_parser_reject(parser);
1197
1.72M
    }
1198
1199
68.9k
    njs_lexer_consume_token(parser->lexer, 1);
1200
1201
68.9k
    return NJS_OK;
1202
1203
514k
reference:
1204
1205
514k
    node = njs_parser_reference(parser, token);
1206
514k
    if (node == NULL) {
1207
267
        return NJS_ERROR;
1208
267
    }
1209
1210
513k
    node->token_line = token->line;
1211
513k
    parser->node = node;
1212
1213
1.59M
done:
1214
1215
1.59M
    njs_lexer_consume_token(parser->lexer, 1);
1216
1217
1.59M
    return NJS_DONE;
1218
513k
}
1219
1220
1221
static njs_int_t
1222
njs_parser_regexp_literal(njs_parser_t *parser, njs_lexer_token_t *token,
1223
    njs_queue_link_t *current)
1224
15.5k
{
1225
15.5k
    u_char                *p;
1226
15.5k
    njs_str_t             text;
1227
15.5k
    njs_int_t             ret;
1228
15.5k
    njs_lexer_t           *lexer;
1229
15.5k
    njs_value_t           *value, retval;
1230
15.5k
    njs_regex_flags_t     flags;
1231
15.5k
    njs_regexp_pattern_t  *pattern;
1232
1233
15.5k
    static const njs_value_t  string_message = njs_string("message");
1234
1235
15.5k
    value = &parser->node->u.value;
1236
15.5k
    lexer = parser->lexer;
1237
1238
15.5k
    if (token->type == NJS_TOKEN_DIVISION_ASSIGNMENT) {
1239
1.41k
        lexer->start--;
1240
1.41k
    }
1241
1242
1.14M
    for (p = lexer->start; p < lexer->end; p++) {
1243
1244
1.14M
        switch (*p) {
1245
0
        case '\n':
1246
0
        case '\r':
1247
0
            goto failed;
1248
1249
2.14k
        case '[':
1250
1.37M
            while (1) {
1251
1.37M
                if (++p >= lexer->end) {
1252
511
                    goto failed;
1253
511
                }
1254
1255
1.37M
                if (*p == ']') {
1256
1.43k
                    break;
1257
1.43k
                }
1258
1259
1.37M
                switch (*p) {
1260
0
                case '\n':
1261
206
                case '\r':
1262
206
                    goto failed;
1263
1264
2.70k
                case '\\':
1265
2.70k
                    if (++p >= lexer->end || *p == '\n' || *p == '\r') {
1266
0
                        goto failed;
1267
0
                    }
1268
1269
2.70k
                    break;
1270
1.37M
                }
1271
1.37M
            }
1272
1273
1.43k
            break;
1274
1275
4.05k
        case '\\':
1276
4.05k
            if (++p >= lexer->end || *p == '\n' || *p == '\r') {
1277
0
                goto failed;
1278
0
            }
1279
1280
4.05k
            break;
1281
1282
13.8k
        case '/':
1283
13.8k
            text.start = lexer->start;
1284
13.8k
            text.length = p - text.start;
1285
13.8k
            p++;
1286
13.8k
            lexer->start = p;
1287
1288
13.8k
            flags = njs_regexp_flags(&p, lexer->end);
1289
1290
13.8k
            if (njs_slow_path(flags < 0)) {
1291
0
                njs_parser_syntax_error(parser, "Invalid RegExp flags \"%*s\"",
1292
0
                                        p - lexer->start, lexer->start);
1293
1294
0
                return NJS_ERROR;
1295
0
            }
1296
1297
13.8k
            lexer->start = p;
1298
1299
13.8k
            pattern = njs_regexp_pattern_create(parser->vm, text.start,
1300
13.8k
                                                text.length, flags);
1301
1302
13.8k
            if (njs_slow_path(pattern == NULL)) {
1303
259
                retval = njs_vm_exception(parser->vm);
1304
259
                ret = njs_value_property(parser->vm, &retval,
1305
259
                                         njs_value_arg(&string_message),
1306
259
                                         &retval);
1307
259
                if (njs_slow_path(ret != NJS_OK)) {
1308
0
                    return NJS_ERROR;
1309
0
                }
1310
1311
259
                njs_string_get(&retval, &text);
1312
1313
259
                njs_parser_syntax_error(parser, "%V", &text);
1314
1315
259
                return NJS_ERROR;
1316
259
            }
1317
1318
13.5k
            value->data.u.data = pattern;
1319
1320
13.5k
            return NJS_OK;
1321
1.14M
        }
1322
1.14M
    }
1323
1324
1.75k
failed:
1325
1326
1.75k
    njs_parser_syntax_error(parser, "Unterminated RegExp \"%*s\"",
1327
1.75k
                            p - (lexer->start - 1), lexer->start - 1);
1328
1.75k
    return NJS_ERROR;
1329
15.5k
}
1330
1331
1332
static njs_int_t
1333
njs_parser_template_literal(njs_parser_t *parser, njs_lexer_token_t *token,
1334
    njs_queue_link_t *current)
1335
118k
{
1336
118k
    njs_index_t        index;
1337
118k
    njs_parser_node_t  *node, *array, *template, *temp;
1338
1339
118k
    temp = njs_parser_node_new(parser, 0);
1340
118k
    if (temp == NULL) {
1341
0
        return NJS_ERROR;
1342
0
    }
1343
1344
118k
    array = njs_parser_node_new(parser, NJS_TOKEN_ARRAY);
1345
118k
    if (array == NULL) {
1346
0
        return NJS_ERROR;
1347
0
    }
1348
1349
118k
    array->token_line = token->line;
1350
1351
118k
    template = parser->node;
1352
1353
118k
    index = njs_scope_temp_index(template->scope);
1354
118k
    if (njs_slow_path(index == NJS_INDEX_ERROR)) {
1355
0
        return NJS_ERROR;
1356
0
    }
1357
1358
118k
    if (template->token_type != NJS_TOKEN_TEMPLATE_LITERAL) {
1359
116k
        node = njs_parser_argument(parser, array, index);
1360
116k
        if (node == NULL) {
1361
0
            return NJS_ERROR;
1362
0
        }
1363
1364
116k
        node->temporary = 1;
1365
1366
116k
        template->right = node;
1367
116k
        temp->right = node;
1368
1369
116k
        index = njs_scope_temp_index(template->scope);
1370
116k
        if (njs_slow_path(index == NJS_INDEX_ERROR)) {
1371
0
            return NJS_ERROR;
1372
0
        }
1373
1374
116k
    } else {
1375
2.15k
        template->left = array;
1376
2.15k
        temp->right = template;
1377
2.15k
    }
1378
1379
118k
    temp->temporary = 1;
1380
118k
    temp->left = template;
1381
118k
    temp->index = index;
1382
1383
118k
    parser->target = temp;
1384
1385
118k
    token->text.start++;
1386
118k
    token->text.length = 0;
1387
1388
118k
    njs_parser_next(parser, njs_parser_template_literal_string);
1389
1390
118k
    return NJS_OK;
1391
118k
}
1392
1393
1394
static njs_int_t
1395
njs_parser_template_literal_string(njs_parser_t *parser,
1396
    njs_lexer_token_t *token, njs_queue_link_t *current)
1397
121k
{
1398
121k
    njs_int_t          ret, ret_item;
1399
121k
    njs_parser_node_t  *template;
1400
1401
121k
    template = parser->target->left;
1402
1403
121k
    ret = njs_parser_template_string(parser, token);
1404
121k
    if (ret == NJS_ERROR) {
1405
3
        njs_parser_syntax_error(parser, "Unterminated template literal");
1406
3
        return NJS_DONE;
1407
3
    }
1408
1409
121k
    if (template->token_type != NJS_TOKEN_TEMPLATE_LITERAL) {
1410
117k
        ret_item = njs_parser_array_item(parser, template->right->left,
1411
117k
                                         parser->node);
1412
1413
117k
    } else {
1414
3.75k
        ret_item = njs_parser_array_item(parser, template->left, parser->node);
1415
3.75k
    }
1416
1417
121k
    if (ret_item != NJS_OK) {
1418
0
        return NJS_ERROR;
1419
0
    }
1420
1421
121k
    if (ret == NJS_DONE) {
1422
118k
        parser->node = template;
1423
1424
118k
        njs_parser_node_free(parser, parser->target);
1425
118k
        njs_lexer_consume_token(parser->lexer, 1);
1426
1427
118k
        return njs_parser_stack_pop(parser);
1428
118k
    }
1429
1430
3.04k
    parser->node = NULL;
1431
1432
3.04k
    njs_parser_next(parser, njs_parser_expression);
1433
1434
3.04k
    njs_lexer_consume_token(parser->lexer, 1);
1435
1436
3.04k
    return njs_parser_after(parser, current, parser->target, 0,
1437
121k
                            njs_parser_template_literal_expression);
1438
121k
}
1439
1440
1441
static njs_int_t
1442
njs_parser_template_literal_expression(njs_parser_t *parser,
1443
    njs_lexer_token_t *token, njs_queue_link_t *current)
1444
3.04k
{
1445
3.04k
    njs_int_t          ret;
1446
3.04k
    njs_parser_node_t  *template, *node, *parent;
1447
1448
3.04k
    if (parser->ret != NJS_OK) {
1449
0
        return njs_parser_failed(parser);
1450
0
    }
1451
1452
3.04k
    if (token->type != NJS_TOKEN_CLOSE_BRACE) {
1453
0
        njs_parser_syntax_error(parser, "Missing \"}\" in template expression");
1454
0
        return NJS_DONE;
1455
0
    }
1456
1457
3.04k
    parent = parser->target->right;
1458
3.04k
    template = parser->target->left;
1459
1460
3.04k
    if (template->token_type != NJS_TOKEN_TEMPLATE_LITERAL) {
1461
1.44k
        node = njs_parser_argument(parser, parser->node, parser->target->index);
1462
1.44k
        if (node == NULL) {
1463
0
            return NJS_ERROR;
1464
0
        }
1465
1466
1.44k
        parent->right = node;
1467
1.44k
        parent = node;
1468
1469
1.44k
        parser->target->index = njs_scope_temp_index(node->scope);
1470
1.44k
        if (njs_slow_path(parser->target->index == NJS_INDEX_ERROR)) {
1471
0
            return NJS_ERROR;
1472
0
        }
1473
1474
1.60k
    } else {
1475
1.60k
        ret = njs_parser_array_item(parser, template->left, parser->node);
1476
1.60k
        if (ret != NJS_OK) {
1477
0
            return NJS_ERROR;
1478
0
        }
1479
1.60k
    }
1480
1481
3.04k
    parser->target->right = parent;
1482
1483
3.04k
    parser->node = NULL;
1484
1485
3.04k
    njs_parser_next(parser, njs_parser_template_literal_string);
1486
1487
3.04k
    token->text.length = 0;
1488
3.04k
    token->text.start += 1;
1489
1490
3.04k
    return NJS_OK;
1491
3.04k
}
1492
1493
1494
static njs_int_t
1495
njs_parser_cover_parenthesized_expression(njs_parser_t *parser,
1496
    njs_lexer_token_t *token, njs_queue_link_t *current)
1497
0
{
1498
0
    switch (token->type) {
1499
0
    case NJS_TOKEN_CLOSE_PARENTHESIS:
1500
0
        (void) njs_parser_stack_pop(parser);
1501
0
        break;
1502
1503
0
    case NJS_TOKEN_ELLIPSIS:
1504
0
        njs_parser_next(parser, njs_parser_binding_identifier_pattern);
1505
0
        break;
1506
1507
0
    default:
1508
0
        parser->node = NULL;
1509
1510
0
        njs_parser_next(parser, njs_parser_expression);
1511
1512
0
        return njs_parser_after(parser, current, NULL, 0,
1513
0
                               njs_parser_cover_parenthesized_expression_after);
1514
0
    }
1515
1516
0
    njs_lexer_consume_token(parser->lexer, 1);
1517
1518
0
    return NJS_OK;
1519
0
}
1520
1521
1522
static njs_int_t
1523
njs_parser_binding_identifier_pattern(njs_parser_t *parser,
1524
    njs_lexer_token_t *token, njs_queue_link_t *current)
1525
0
{
1526
    /*
1527
     * BindingIdentifier )
1528
     * BindingPattern )
1529
     */
1530
1531
0
    switch (token->type) {
1532
1533
    /* BindingIdentifier */
1534
0
    case NJS_TOKEN_NAME:
1535
0
        njs_parser_next(parser, njs_parser_cover_parenthesized_expression_end);
1536
0
        break;
1537
1538
0
    case NJS_TOKEN_YIELD:
1539
0
        njs_parser_next(parser, njs_parser_cover_parenthesized_expression_end);
1540
0
        break;
1541
1542
0
    case NJS_TOKEN_AWAIT:
1543
0
        njs_parser_next(parser, njs_parser_cover_parenthesized_expression_end);
1544
0
        break;
1545
1546
    /* BindingPattern */
1547
0
    case NJS_TOKEN_OPEN_BRACKET:
1548
0
        njs_parser_next(parser, njs_parser_array_binding_pattern);
1549
1550
0
        njs_lexer_consume_token(parser->lexer, 1);
1551
0
        return njs_parser_after(parser, current, NULL, 0,
1552
0
                                njs_parser_cover_parenthesized_expression_end);
1553
1554
0
    case NJS_TOKEN_OPEN_BRACE:
1555
0
        njs_parser_next(parser, njs_parser_object_binding_pattern);
1556
1557
0
        njs_lexer_consume_token(parser->lexer, 1);
1558
0
        return njs_parser_after(parser, current, NULL, 0,
1559
0
                                njs_parser_cover_parenthesized_expression_end);
1560
1561
0
    default:
1562
0
        return NJS_ERROR;
1563
0
    }
1564
1565
0
    njs_lexer_consume_token(parser->lexer, 1);
1566
1567
0
    return NJS_OK;
1568
0
}
1569
1570
1571
static njs_int_t
1572
njs_parser_cover_parenthesized_expression_after(njs_parser_t *parser,
1573
    njs_lexer_token_t *token, njs_queue_link_t *current)
1574
0
{
1575
    /*
1576
     * )
1577
     * ,)
1578
     * , ... BindingIdentifier )
1579
     * , ... BindingPattern )
1580
     */
1581
1582
0
    if (token->type == NJS_TOKEN_CLOSE_PARENTHESIS) {
1583
0
        goto shift_stack;
1584
0
    }
1585
1586
0
    if (token->type != NJS_TOKEN_COMMA) {
1587
0
        return njs_parser_failed(parser);
1588
0
    }
1589
1590
0
    njs_lexer_consume_token(parser->lexer, 1);
1591
1592
0
    token = njs_lexer_token(parser->lexer, 0);
1593
0
    if (njs_slow_path(token == NULL)) {
1594
0
        return NJS_ERROR;
1595
0
    }
1596
1597
0
    if (token->type == NJS_TOKEN_CLOSE_PARENTHESIS) {
1598
0
        goto shift_stack;
1599
0
    }
1600
1601
0
    if(token->type != NJS_TOKEN_ELLIPSIS) {
1602
0
        return njs_parser_failed(parser);
1603
0
    }
1604
1605
0
    njs_lexer_consume_token(parser->lexer, 1);
1606
1607
0
    njs_parser_next(parser, njs_parser_binding_identifier_pattern);
1608
1609
0
    return NJS_OK;
1610
1611
0
shift_stack:
1612
1613
0
    njs_lexer_consume_token(parser->lexer, 1);
1614
1615
0
    return njs_parser_stack_pop(parser);
1616
0
}
1617
1618
1619
static njs_int_t
1620
njs_parser_cover_parenthesized_expression_end(njs_parser_t *parser,
1621
    njs_lexer_token_t *token, njs_queue_link_t *current)
1622
0
{
1623
0
    if (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) {
1624
0
        return njs_parser_failed(parser);
1625
0
    }
1626
1627
0
    njs_lexer_consume_token(parser->lexer, 1);
1628
1629
0
    return njs_parser_stack_pop(parser);
1630
0
}
1631
1632
1633
/*
1634
 * 12.2.5 Array Initializer.
1635
 */
1636
static njs_int_t
1637
njs_parser_array_literal(njs_parser_t *parser, njs_lexer_token_t *token,
1638
    njs_queue_link_t *current)
1639
6.90k
{
1640
6.90k
    parser->target = parser->node;
1641
6.90k
    parser->node = NULL;
1642
1643
6.90k
    njs_parser_next(parser, njs_parser_array_element_list);
1644
1645
6.90k
    return NJS_OK;
1646
6.90k
}
1647
1648
1649
static njs_int_t
1650
njs_parser_array_element_list(njs_parser_t *parser, njs_lexer_token_t *token,
1651
    njs_queue_link_t *current)
1652
1.15M
{
1653
1.15M
    njs_parser_node_t  *array;
1654
1655
1.15M
    array = parser->target;
1656
1657
1.15M
    switch (token->type) {
1658
6.14k
    case NJS_TOKEN_CLOSE_BRACKET:
1659
6.14k
        njs_lexer_consume_token(parser->lexer, 1);
1660
1661
6.14k
        parser->node = array;
1662
1663
6.14k
        return njs_parser_stack_pop(parser);
1664
1665
126k
    case NJS_TOKEN_COMMA:
1666
126k
        njs_lexer_consume_token(parser->lexer, 1);
1667
1668
126k
        array->ctor = 1;
1669
126k
        array->u.length++;
1670
1671
126k
        return NJS_OK;
1672
1673
0
    case NJS_TOKEN_ELLIPSIS:
1674
#if 0
1675
        njs_lexer_consume_token(parser->lexer, 1);
1676
1677
        njs_parser_next(parser, njs_parser_assignment_expression);
1678
1679
        return njs_parser_after(parser, current, array, 0,
1680
                                njs_parser_array_spread_element);
1681
#else
1682
0
        (void) njs_parser_array_spread_element;
1683
0
        return njs_parser_failed(parser);
1684
0
#endif
1685
1686
1.02M
    default:
1687
1.02M
        break;
1688
1.15M
    }
1689
1690
1.02M
    njs_parser_next(parser, njs_parser_assignment_expression);
1691
1692
1.02M
    return njs_parser_after(parser, current, array, 0, njs_parser_array_after);
1693
1.15M
}
1694
1695
1696
static njs_int_t
1697
njs_parser_array_after(njs_parser_t *parser, njs_lexer_token_t *token,
1698
    njs_queue_link_t *current)
1699
1.02M
{
1700
1.02M
    njs_int_t  ret;
1701
1702
1.02M
    if (parser->ret != NJS_OK) {
1703
1
        return njs_parser_failed(parser);
1704
1
    }
1705
1706
1.02M
    ret = njs_parser_array_item(parser, parser->target, parser->node);
1707
1.02M
    if (ret != NJS_OK) {
1708
0
        return NJS_ERROR;
1709
0
    }
1710
1711
1.02M
    switch (token->type) {
1712
1.02M
    case NJS_TOKEN_COMMA:
1713
1.02M
        njs_lexer_consume_token(parser->lexer, 1);
1714
1715
        /* Fall through. */
1716
1717
1.02M
    case NJS_TOKEN_CLOSE_BRACKET:
1718
1.02M
        njs_parser_next(parser, njs_parser_array_element_list);
1719
1.02M
        break;
1720
1721
0
    default:
1722
0
        return njs_parser_failed(parser);
1723
1.02M
    }
1724
1725
1.02M
    return NJS_OK;
1726
1.02M
}
1727
1728
1729
static njs_int_t
1730
njs_parser_array_spread_element(njs_parser_t *parser, njs_lexer_token_t *token,
1731
    njs_queue_link_t *current)
1732
0
{
1733
0
    if (parser->ret != NJS_OK || token->type != NJS_TOKEN_CLOSE_BRACKET) {
1734
0
        return njs_parser_failed(parser);
1735
0
    }
1736
1737
0
    njs_lexer_consume_token(parser->lexer, 1);
1738
1739
0
    parser->node = parser->target;
1740
1741
0
    return njs_parser_stack_pop(parser);
1742
0
}
1743
1744
1745
/*
1746
 * 12.2.6 Object Initializer.
1747
 */
1748
static njs_int_t
1749
njs_parser_object_literal(njs_parser_t *parser, njs_lexer_token_t *token,
1750
    njs_queue_link_t *current)
1751
8.83k
{
1752
8.83k
    njs_parser_node_t *node;
1753
1754
8.83k
    node = njs_parser_node_new(parser, 0);
1755
8.83k
    if (node == NULL) {
1756
0
        return NJS_ERROR;
1757
0
    }
1758
1759
8.83k
    node->left = parser->node;
1760
1761
8.83k
    parser->node = NULL;
1762
8.83k
    parser->target = node;
1763
1764
8.83k
    njs_parser_next(parser, njs_parser_property_definition_list);
1765
1766
8.83k
    return njs_parser_after(parser, current, node, 1,
1767
8.83k
                            njs_parser_object_literal_after);
1768
8.83k
}
1769
1770
1771
static njs_int_t
1772
njs_parser_object_literal_after(njs_parser_t *parser, njs_lexer_token_t *token,
1773
    njs_queue_link_t *current)
1774
5.91k
{
1775
5.91k
    if (token->type == NJS_TOKEN_COMMA) {
1776
0
        njs_lexer_consume_token(parser->lexer, 1);
1777
1778
0
        token = njs_lexer_token(parser->lexer, 1);
1779
0
        if (token == NULL) {
1780
0
            return NJS_ERROR;
1781
0
        }
1782
0
    }
1783
1784
5.91k
    if (token->type != NJS_TOKEN_CLOSE_BRACE) {
1785
0
        return njs_parser_failed(parser);
1786
0
    }
1787
1788
5.91k
    njs_lexer_consume_token(parser->lexer, 1);
1789
1790
5.91k
    parser->node = parser->target->left;
1791
1792
5.91k
    njs_parser_node_free(parser, parser->target);
1793
5.91k
    parser->target = NULL;
1794
1795
5.91k
    return njs_parser_stack_pop(parser);
1796
5.91k
}
1797
1798
1799
static njs_int_t
1800
njs_parser_property_definition_list(njs_parser_t *parser,
1801
    njs_lexer_token_t *token, njs_queue_link_t *current)
1802
8.83k
{
1803
8.83k
    njs_parser_next(parser, njs_parser_property_definition);
1804
1805
8.83k
    return njs_parser_after(parser, current, parser->target, 1,
1806
8.83k
                            njs_parser_property_definition_list_after);
1807
8.83k
}
1808
1809
1810
static njs_int_t
1811
njs_parser_property_definition_list_after(njs_parser_t *parser,
1812
    njs_lexer_token_t *token, njs_queue_link_t *current)
1813
7.75k
{
1814
7.75k
    if (token->type != NJS_TOKEN_COMMA) {
1815
5.91k
        return njs_parser_stack_pop(parser);
1816
5.91k
    }
1817
1818
1.83k
    njs_lexer_consume_token(parser->lexer, 1);
1819
1820
1.83k
    njs_parser_next(parser, njs_parser_property_definition);
1821
1822
1.83k
    return njs_parser_after(parser, current, parser->target, 1,
1823
7.75k
                            njs_parser_property_definition_list_after);
1824
7.75k
}
1825
1826
1827
njs_inline njs_parser_node_t *
1828
njs_parser_property_name_node(njs_parser_t *parser, njs_lexer_token_t *token)
1829
9.50k
{
1830
9.50k
    njs_int_t          ret;
1831
9.50k
    njs_parser_node_t  *property;
1832
1833
9.50k
    if (token->type == NJS_TOKEN_NUMBER) {
1834
1.88k
        property = njs_parser_node_new(parser, NJS_TOKEN_NUMBER);
1835
1.88k
        if (property != NULL) {
1836
1.88k
             njs_set_number(&property->u.value, token->number);
1837
1.88k
        }
1838
1839
7.61k
    } else if (token->type == NJS_TOKEN_ESCAPE_STRING) {
1840
1.30k
        property = njs_parser_node_new(parser, NJS_TOKEN_STRING);
1841
1842
1.30k
        if (property != NULL) {
1843
1.30k
            ret = njs_parser_escape_string_create(parser, token,
1844
1.30k
                                                  &property->u.value);
1845
1.30k
            if (ret != NJS_TOKEN_STRING) {
1846
269
                return NULL;
1847
269
            }
1848
1.30k
        }
1849
1850
6.31k
    } else {
1851
6.31k
        property = njs_parser_node_string(parser->vm, token, parser);
1852
6.31k
    }
1853
1854
9.23k
    if (property != NULL) {
1855
9.23k
        property->token_line = token->line;
1856
9.23k
    }
1857
1858
9.23k
    return property;
1859
9.50k
}
1860
1861
1862
njs_inline njs_int_t
1863
njs_parser_property_name(njs_parser_t *parser, njs_queue_link_t *current,
1864
    unsigned consume)
1865
4.39k
{
1866
4.39k
    njs_lexer_token_t  *token;
1867
4.39k
    njs_parser_node_t  *property;
1868
1869
4.39k
    if (consume > 1) {
1870
4.39k
        token = njs_lexer_token(parser->lexer, 0);
1871
4.39k
        if (token == NULL) {
1872
0
            return NJS_ERROR;
1873
0
        }
1874
1875
4.39k
        property = njs_parser_property_name_node(parser, token);
1876
4.39k
        if (property == NULL) {
1877
0
            return NJS_ERROR;
1878
0
        }
1879
1880
4.39k
        parser->target->right = property;
1881
4.39k
        parser->target->index = (token->type == NJS_TOKEN_NAME);
1882
4.39k
    }
1883
1884
4.39k
    njs_lexer_consume_token(parser->lexer, consume);
1885
1886
4.39k
    parser->node = NULL;
1887
1888
4.39k
    njs_parser_next(parser, njs_parser_assignment_expression);
1889
1890
4.39k
    return njs_parser_after(parser, current, parser->target, 1,
1891
4.39k
                            njs_parser_property_definition_after);
1892
4.39k
}
1893
1894
1895
static njs_int_t
1896
njs_parser_property_definition_ident(njs_parser_t *parser,
1897
    njs_lexer_token_t *token, njs_parser_node_t *temp)
1898
0
{
1899
0
    temp->right = njs_parser_node_string(parser->vm, token, parser);
1900
0
    if (temp->right == NULL) {
1901
0
        return NJS_ERROR;
1902
0
    }
1903
1904
0
    temp->right->index = NJS_TOKEN_OPEN_BRACKET;
1905
1906
0
    parser->node = njs_parser_reference(parser, token);
1907
0
    if (parser->node == NULL) {
1908
0
        return NJS_ERROR;
1909
0
    }
1910
1911
0
    njs_lexer_consume_token(parser->lexer, 1);
1912
1913
0
    token = njs_lexer_token(parser->lexer, 0);
1914
0
    if (token == NULL) {
1915
0
        return NJS_ERROR;
1916
0
    }
1917
1918
    /* CoverInitializedName */
1919
0
    if (token->type == NJS_TOKEN_ASSIGNMENT) {
1920
0
        return njs_parser_not_supported(parser, token);
1921
0
    }
1922
1923
0
    njs_parser_next(parser, njs_parser_property_definition_after);
1924
1925
0
    return NJS_OK;
1926
0
}
1927
1928
1929
static njs_int_t
1930
njs_parser_property_definition(njs_parser_t *parser, njs_lexer_token_t *token,
1931
    njs_queue_link_t *current)
1932
10.6k
{
1933
10.6k
    njs_str_t          *name;
1934
10.6k
    njs_token_type_t   accessor;
1935
10.6k
    njs_lexer_token_t  *next;
1936
10.6k
    njs_parser_node_t  *temp, *property;
1937
1938
10.6k
    temp = parser->target;
1939
1940
10.6k
    switch (token->type) {
1941
1.16k
    case NJS_TOKEN_CLOSE_BRACE:
1942
1.16k
        return njs_parser_stack_pop(parser);
1943
1944
    /* PropertyName */
1945
272
    case NJS_TOKEN_STRING:
1946
272
    case NJS_TOKEN_ESCAPE_STRING:
1947
1.96k
    case NJS_TOKEN_NUMBER:
1948
1.96k
        next = njs_lexer_peek_token(parser->lexer, token, 0);
1949
1.96k
        if (next == NULL) {
1950
0
            return NJS_ERROR;
1951
0
        }
1952
1953
1.96k
        if (next->type == NJS_TOKEN_COLON) {
1954
61
            return njs_parser_property_name(parser, current, 2);
1955
1956
1.90k
        } else if (next->type == NJS_TOKEN_OPEN_PARENTHESIS) {
1957
1.90k
            goto method_definition;
1958
1.90k
        }
1959
1960
0
        njs_lexer_consume_token(parser->lexer, 1);
1961
1962
0
        return njs_parser_failed(parser);
1963
1964
    /* ComputedPropertyName */
1965
0
    case NJS_TOKEN_OPEN_BRACKET:
1966
0
        njs_lexer_consume_token(parser->lexer, 1);
1967
1968
0
        njs_parser_next(parser, njs_parser_assignment_expression);
1969
1970
0
        return njs_parser_after(parser, current, temp, 1,
1971
1.96k
                                njs_parser_computed_property_name_after);
1972
1973
0
    case NJS_TOKEN_ELLIPSIS:
1974
0
        return njs_parser_not_supported(parser, token);
1975
1976
0
    case NJS_TOKEN_ASYNC:
1977
0
        token = njs_lexer_peek_token(parser->lexer, token, 0);
1978
0
        if (token == NULL) {
1979
0
            return NJS_ERROR;
1980
0
        }
1981
1982
0
        if (token->type == NJS_TOKEN_OPEN_BRACKET) {
1983
0
            njs_lexer_consume_token(parser->lexer, 2);
1984
1985
0
            njs_parser_next(parser, njs_parser_assignment_expression);
1986
1987
0
            return njs_parser_after(parser, current, temp, 1,
1988
0
                                    njs_parser_computed_property_async_after);
1989
0
        }
1990
1991
0
        if (token->type == NJS_TOKEN_COLON) {
1992
0
            return njs_parser_property_name(parser, current, 2);
1993
0
        }
1994
1995
0
        if (!njs_lexer_token_is_identifier_name(token)) {
1996
0
            return njs_parser_failed(parser);
1997
0
        }
1998
1999
0
        next = njs_lexer_peek_token(parser->lexer, token, 0);
2000
0
        if (next == NULL) {
2001
0
            return NJS_ERROR;
2002
0
        }
2003
2004
0
        if (next->type == NJS_TOKEN_OPEN_PARENTHESIS) {
2005
0
            goto method_definition;
2006
0
        }
2007
2008
0
        njs_lexer_consume_token(parser->lexer, 1);
2009
2010
0
        return njs_parser_failed(parser);
2011
2012
7.54k
    default:
2013
7.54k
        if (!njs_lexer_token_is_identifier_name(token)) {
2014
0
            return njs_parser_reject(parser);
2015
0
        }
2016
2017
7.54k
        next = njs_lexer_peek_token(parser->lexer, token, 0);
2018
7.54k
        if (next == NULL) {
2019
0
            return NJS_ERROR;
2020
0
        }
2021
2022
        /* PropertyName */
2023
7.54k
        if (next->type == NJS_TOKEN_COLON) {
2024
4.33k
            return njs_parser_property_name(parser, current, 2);
2025
2026
        /* MethodDefinition */
2027
4.33k
        } else if (next->type == NJS_TOKEN_OPEN_PARENTHESIS) {
2028
1.70k
            goto method_definition;
2029
2030
1.70k
        } else if (njs_lexer_token_is_reserved(token)) {
2031
0
            njs_lexer_consume_token(parser->lexer, 1);
2032
2033
0
            return njs_parser_failed(parser);
2034
0
        }
2035
2036
1.50k
        name = &token->text;
2037
2038
1.50k
        if (name->length == 3 && (memcmp(name->start, "get", 3) == 0
2039
1.50k
                                  || memcmp(name->start, "set", 3) == 0))
2040
1.50k
        {
2041
1.50k
            accessor = (name->start[0] == 'g') ? NJS_TOKEN_PROPERTY_GETTER
2042
1.50k
                                               : NJS_TOKEN_PROPERTY_SETTER;
2043
2044
1.50k
            temp->right = (njs_parser_node_t *) (uintptr_t) accessor;
2045
2046
1.50k
            njs_parser_next(parser, njs_parser_get_set);
2047
2048
1.50k
            return NJS_OK;
2049
1.50k
        }
2050
2051
0
        return njs_parser_property_definition_ident(parser, token, temp);
2052
10.6k
    }
2053
2054
3.60k
method_definition:
2055
2056
3.60k
    property = njs_parser_property_name_node(parser, token);
2057
3.60k
    if (property == NULL) {
2058
0
        return NJS_ERROR;
2059
0
    }
2060
2061
3.60k
    temp->right = property;
2062
3.60k
    temp->right->index = NJS_TOKEN_OPEN_BRACKET;
2063
2064
3.60k
    njs_parser_next(parser, njs_parser_method_definition);
2065
2066
3.60k
    return njs_parser_after(parser, current, temp, 1,
2067
3.60k
                            njs_parser_property_definition_after);
2068
3.60k
}
2069
2070
2071
static njs_int_t
2072
njs_parser_property_definition_after(njs_parser_t *parser,
2073
    njs_lexer_token_t *token, njs_queue_link_t *current)
2074
6.40k
{
2075
6.40k
    njs_int_t          ret;
2076
6.40k
    njs_str_t          name;
2077
6.40k
    njs_bool_t         proto_init;
2078
6.40k
    njs_parser_node_t  *property, *temp;
2079
2080
6.40k
    static const njs_str_t  proto_string = njs_str("__proto__");
2081
2082
6.40k
    temp = parser->target;
2083
6.40k
    property = temp->right;
2084
2085
6.40k
    proto_init = 0;
2086
2087
6.40k
    if (property->index != NJS_TOKEN_OPEN_BRACKET
2088
6.40k
        && njs_is_string(&property->u.value))
2089
3.56k
    {
2090
3.56k
        njs_string_get(&property->u.value, &name);
2091
2092
3.56k
        if (njs_slow_path(njs_strstr_eq(&name, &proto_string))) {
2093
600
            if (temp->token_type == NJS_TOKEN_PROTO_INIT) {
2094
0
                njs_parser_syntax_error(parser,
2095
0
                                   "Duplicate __proto__ fields are not allowed "
2096
0
                                   "in object literals");
2097
0
                return NJS_ERROR;
2098
0
            }
2099
2100
600
            temp->token_type = NJS_TOKEN_PROTO_INIT;
2101
600
            proto_init = 1;
2102
600
        }
2103
3.56k
    }
2104
2105
6.40k
    if (property->index != 0) {
2106
2.77k
        property->index = 0;
2107
2.77k
    }
2108
2109
6.40k
    ret = njs_parser_object_property(parser, temp->left, property,
2110
6.40k
                                     parser->node, proto_init);
2111
6.40k
    if (ret != NJS_OK) {
2112
0
        return NJS_ERROR;
2113
0
    }
2114
2115
6.40k
    temp->right = NULL;
2116
2117
6.40k
    return njs_parser_stack_pop(parser);
2118
6.40k
}
2119
2120
2121
static njs_int_t
2122
njs_parser_computed_property_name_after(njs_parser_t *parser,
2123
    njs_lexer_token_t *token, njs_queue_link_t *current)
2124
0
{
2125
0
    return njs_parser_computed_property_name_handler(parser, token, current, 0);
2126
0
}
2127
2128
2129
static njs_int_t
2130
njs_parser_computed_property_async_after(njs_parser_t *parser,
2131
    njs_lexer_token_t *token, njs_queue_link_t *current)
2132
0
{
2133
0
    return njs_parser_computed_property_name_handler(parser, token, current, 1);
2134
0
}
2135
2136
2137
static njs_int_t
2138
njs_parser_computed_property_name_handler(njs_parser_t *parser,
2139
    njs_lexer_token_t *token, njs_queue_link_t *current, njs_bool_t async)
2140
0
{
2141
0
    njs_token_type_t   type;
2142
0
    njs_parser_node_t  *expr, *target;
2143
2144
0
    if (token->type != NJS_TOKEN_CLOSE_BRACKET) {
2145
0
        return njs_parser_failed(parser);
2146
0
    }
2147
2148
0
    njs_lexer_consume_token(parser->lexer, 1);
2149
2150
0
    token = njs_lexer_token(parser->lexer, 0);
2151
0
    if (token == NULL) {
2152
0
        return NJS_ERROR;
2153
0
    }
2154
2155
0
    target = parser->target;
2156
2157
    /*
2158
     * For further identification.
2159
     * In njs_parser_property_definition_after() index will be reset to zero.
2160
     */
2161
0
    parser->node->index = NJS_TOKEN_OPEN_BRACKET;
2162
2163
0
    target->right = parser->node;
2164
2165
0
    if (!async && token->type == NJS_TOKEN_COLON) {
2166
0
        return njs_parser_property_name(parser, current, 1);
2167
2168
    /* MethodDefinition */
2169
0
    } else if (token->type == NJS_TOKEN_OPEN_PARENTHESIS) {
2170
0
        type = (async) ? NJS_TOKEN_ASYNC_FUNCTION : NJS_TOKEN_FUNCTION;
2171
2172
0
        expr = njs_parser_node_new(parser, type);
2173
0
        if (expr == NULL) {
2174
0
            return NJS_ERROR;
2175
0
        }
2176
2177
0
        expr->token_line = token->line;
2178
2179
0
        parser->node = expr;
2180
2181
0
        njs_lexer_consume_token(parser->lexer, 1);
2182
0
        njs_parser_next(parser, njs_parser_function_lambda);
2183
2184
0
        return njs_parser_after(parser, current, parser->target, 1,
2185
0
                                njs_parser_property_definition_after);
2186
0
    }
2187
2188
0
    return njs_parser_failed(parser);
2189
0
}
2190
2191
2192
static njs_int_t
2193
njs_parser_initializer(njs_parser_t *parser, njs_lexer_token_t *token,
2194
    njs_queue_link_t *current)
2195
5.42k
{
2196
5.42k
    njs_parser_node_t  *node;
2197
2198
5.42k
    if (token->type != NJS_TOKEN_ASSIGNMENT) {
2199
0
        return njs_parser_failed(parser);
2200
0
    }
2201
2202
5.42k
    njs_lexer_consume_token(parser->lexer, 1);
2203
2204
5.42k
    node = parser->node;
2205
2206
5.42k
    parser->node = NULL;
2207
2208
5.42k
    njs_parser_next(parser, njs_parser_assignment_expression);
2209
2210
5.42k
    return njs_parser_after(parser, current, node, 1,
2211
5.42k
                            njs_parser_initializer_after);
2212
5.42k
}
2213
2214
2215
static njs_int_t
2216
njs_parser_initializer_after(njs_parser_t *parser, njs_lexer_token_t *token,
2217
    njs_queue_link_t *current)
2218
13.1k
{
2219
13.1k
    njs_parser_node_t  *stmt;
2220
2221
13.1k
    stmt = njs_parser_node_new(parser, NJS_TOKEN_STATEMENT);
2222
13.1k
    if (stmt == NULL) {
2223
0
        return NJS_ERROR;
2224
0
    }
2225
2226
13.1k
    stmt->left = NULL;
2227
13.1k
    stmt->right = parser->target;
2228
2229
13.1k
    parser->target->right = parser->node;
2230
13.1k
    parser->node = stmt;
2231
2232
13.1k
    return njs_parser_stack_pop(parser);
2233
13.1k
}
2234
2235
2236
static njs_int_t
2237
njs_parser_initializer_assign(njs_parser_t *parser, njs_token_type_t type)
2238
13.1k
{
2239
13.1k
    njs_parser_node_t  *assign;
2240
2241
13.1k
    assign = njs_parser_node_new(parser, type);
2242
13.1k
    if (assign == NULL) {
2243
0
        return NJS_ERROR;
2244
0
    }
2245
2246
13.1k
    assign->u.operation = NJS_VMCODE_MOVE;
2247
13.1k
    assign->left = parser->node;
2248
2249
    /* assign->right in njs_parser_initializer_after. */
2250
2251
13.1k
    parser->node = assign;
2252
2253
13.1k
    return NJS_OK;
2254
13.1k
}
2255
2256
2257
/*
2258
 * 12.3 Left-Hand-Side Expressions.
2259
 */
2260
static njs_int_t
2261
njs_parser_property(njs_parser_t *parser, njs_lexer_token_t *token,
2262
    njs_queue_link_t *current)
2263
1.81M
{
2264
1.81M
    njs_parser_node_t  *node, *prop_node;
2265
2266
    /*
2267
     * [ Expression ]
2268
     * . IdentifierName
2269
     * TemplateLiteral
2270
     */
2271
2272
1.81M
    switch (token->type) {
2273
7.80k
    case NJS_TOKEN_OPEN_BRACKET:
2274
7.80k
        node = njs_parser_node_new(parser, NJS_TOKEN_PROPERTY);
2275
7.80k
        if (node == NULL) {
2276
0
            return NJS_ERROR;
2277
0
        }
2278
2279
7.80k
        node->u.operation = NJS_VMCODE_PROPERTY_GET;
2280
7.80k
        node->left = parser->node;
2281
7.80k
        node->token_line = token->line;
2282
2283
7.80k
        parser->node = NULL;
2284
2285
7.80k
        njs_lexer_consume_token(parser->lexer, 1);
2286
2287
7.80k
        njs_parser_next(parser, njs_parser_expression);
2288
2289
7.80k
        return njs_parser_after(parser, current, node, 1,
2290
7.80k
                                njs_parser_member_expression_bracket);
2291
2292
33.5k
    case NJS_TOKEN_DOT:
2293
33.5k
        token = njs_lexer_peek_token(parser->lexer, token, 0);
2294
33.5k
        if (token == NULL) {
2295
0
            return NJS_ERROR;
2296
0
        }
2297
2298
33.5k
        if (njs_lexer_token_is_identifier_name(token)) {
2299
33.5k
            node = njs_parser_node_new(parser, NJS_TOKEN_PROPERTY);
2300
33.5k
            if (node == NULL) {
2301
0
                return NJS_ERROR;
2302
0
            }
2303
2304
33.5k
            node->u.operation = NJS_VMCODE_PROPERTY_GET;
2305
33.5k
            node->token_line = token->line;
2306
2307
33.5k
            prop_node = njs_parser_node_string(parser->vm, token, parser);
2308
33.5k
            if (prop_node == NULL) {
2309
0
                return NJS_ERROR;
2310
0
            }
2311
2312
33.5k
            prop_node->token_line = token->line;
2313
2314
33.5k
            node->left = parser->node;
2315
33.5k
            node->right = prop_node;
2316
2317
33.5k
            parser->node = node;
2318
2319
33.5k
            njs_lexer_consume_token(parser->lexer, 2);
2320
33.5k
            return NJS_AGAIN;
2321
33.5k
        }
2322
2323
0
        njs_lexer_consume_token(parser->lexer, 1);
2324
2325
0
        return NJS_DECLINED;
2326
2327
116k
    case NJS_TOKEN_GRAVE:
2328
116k
        node = njs_parser_create_call(parser, parser->node, 0);
2329
116k
        if (node == NULL) {
2330
0
            return NJS_ERROR;
2331
0
        }
2332
2333
116k
        node->token_line = token->line;
2334
2335
116k
        parser->node = node;
2336
2337
116k
        njs_parser_next(parser, njs_parser_template_literal);
2338
2339
116k
        break;
2340
2341
1.65M
    default:
2342
1.65M
        return NJS_DONE;
2343
1.81M
    }
2344
2345
116k
    return NJS_OK;
2346
1.81M
}
2347
2348
2349
static njs_int_t
2350
njs_parser_member_expression(njs_parser_t *parser, njs_lexer_token_t *token,
2351
    njs_queue_link_t *current)
2352
1.72M
{
2353
1.72M
    njs_int_t  ret;
2354
2355
    /*
2356
     * PrimaryExpression
2357
     * MemberExpression [ Expression ]
2358
     * MemberExpression . IdentifierName
2359
     * MemberExpression TemplateLiteral
2360
     * SuperProperty
2361
     * MetaProperty
2362
     * new MemberExpression Arguments
2363
     */
2364
2365
1.72M
    switch (token->type) {
2366
    /* SuperProperty */
2367
0
    case NJS_TOKEN_SUPER:
2368
        /* TODO: By specification. */
2369
0
        (void) njs_parser_super_property;
2370
0
        return njs_parser_not_supported(parser, token);
2371
2372
    /* MetaProperty */
2373
0
    case NJS_TOKEN_IMPORT:
2374
        /* TODO: By specification. */
2375
0
        (void) njs_parser_member_expression_import;
2376
0
        return njs_parser_not_supported(parser, token);
2377
2378
206
    case NJS_TOKEN_NEW:
2379
206
        njs_lexer_consume_token(parser->lexer, 1);
2380
2381
206
        njs_parser_next(parser, njs_parser_member_expression_new);
2382
206
        break;
2383
2384
1.72M
    default:
2385
1.72M
        ret = njs_parser_primary_expression_test(parser, token, current);
2386
2387
1.72M
        if (ret != NJS_OK) {
2388
1.60M
            if (ret == NJS_DONE) {
2389
1.59M
                njs_parser_next(parser, njs_parser_member_expression_next);
2390
1.59M
                return NJS_OK;
2391
1.59M
            }
2392
2393
11.0k
            if (njs_is_error(&parser->vm->exception)) {
2394
4.44k
                return NJS_DONE;
2395
4.44k
            }
2396
2397
6.55k
            return ret;
2398
11.0k
        }
2399
2400
124k
        break;
2401
1.72M
    }
2402
2403
124k
    return njs_parser_after(parser, current, NULL, 1,
2404
1.72M
                            njs_parser_member_expression_next);
2405
1.72M
}
2406
2407
2408
static njs_int_t
2409
njs_parser_member_expression_next(njs_parser_t *parser,
2410
    njs_lexer_token_t *token, njs_queue_link_t *current)
2411
1.79M
{
2412
1.79M
    njs_int_t  ret;
2413
2414
    /*
2415
     * [ Expression ]
2416
     * . IdentifierName
2417
     * TemplateLiteral
2418
     */
2419
2420
1.79M
    ret = njs_parser_property(parser, token, current);
2421
2422
1.79M
    switch (ret) {
2423
33.5k
    case NJS_AGAIN:
2424
33.5k
        return NJS_OK;
2425
2426
1.63M
    case NJS_DONE:
2427
1.63M
        return njs_parser_stack_pop(parser);
2428
2429
0
    case NJS_DECLINED:
2430
0
        return njs_parser_failed(parser);
2431
2432
124k
    default:
2433
124k
        break;
2434
1.79M
    }
2435
2436
124k
    return njs_parser_after(parser, current, NULL, 1,
2437
1.79M
                            njs_parser_member_expression_next);
2438
1.79M
}
2439
2440
2441
static njs_int_t
2442
njs_parser_member_expression_bracket(njs_parser_t *parser,
2443
    njs_lexer_token_t *token, njs_queue_link_t *current)
2444
7.58k
{
2445
7.58k
    if (token->type != NJS_TOKEN_CLOSE_BRACKET) {
2446
0
        return njs_parser_failed(parser);
2447
0
    }
2448
2449
7.58k
    njs_lexer_consume_token(parser->lexer, 1);
2450
2451
7.58k
    parser->target->right = parser->node;
2452
7.58k
    parser->node = parser->target;
2453
2454
7.58k
    return njs_parser_stack_pop(parser);
2455
7.58k
}
2456
2457
2458
static njs_int_t
2459
njs_parser_member_expression_new_next(njs_parser_t *parser,
2460
    njs_lexer_token_t *token, njs_queue_link_t *current)
2461
206
{
2462
206
    njs_int_t  ret;
2463
2464
    /*
2465
     * PrimaryExpression
2466
     * SuperProperty
2467
     * MetaProperty
2468
     * Arguments
2469
     */
2470
2471
206
    switch (token->type) {
2472
    /* SuperProperty */
2473
0
    case NJS_TOKEN_SUPER:
2474
0
        (void) njs_parser_super_property;
2475
0
        return njs_parser_not_supported(parser, token);
2476
2477
    /* MetaProperty */
2478
0
    case NJS_TOKEN_IMPORT:
2479
0
        (void) njs_parser_member_expression_import;
2480
0
        return njs_parser_not_supported(parser, token);
2481
2482
206
    default:
2483
206
        ret = njs_parser_primary_expression_test(parser, token, current);
2484
2485
206
        if (ret != NJS_OK) {
2486
206
            if (ret == NJS_DONE) {
2487
206
                njs_parser_next(parser, njs_parser_member_expression_next);
2488
206
                return NJS_OK;
2489
206
            }
2490
2491
0
            return ret;
2492
206
        }
2493
2494
0
        return njs_parser_after(parser, current, NULL, 1,
2495
206
                                njs_parser_member_expression_next);
2496
206
    }
2497
206
}
2498
2499
2500
static njs_int_t
2501
njs_parser_super_property(njs_parser_t *parser, njs_lexer_token_t *token,
2502
    njs_queue_link_t *current)
2503
0
{
2504
    /*
2505
     * [ Expression ]
2506
     * . IdentifierName
2507
     */
2508
2509
0
    if (token->type == NJS_TOKEN_OPEN_BRACKET) {
2510
0
        parser->node = NULL;
2511
2512
0
        njs_parser_next(parser, njs_parser_expression);
2513
2514
0
        return njs_parser_after(parser, current, NULL, 1,
2515
0
                                njs_parser_close_bracked);
2516
0
    }
2517
2518
0
    if (token->type != NJS_TOKEN_DOT) {
2519
0
        return njs_parser_failed(parser);
2520
0
    }
2521
2522
0
    njs_lexer_consume_token(parser->lexer, 1);
2523
2524
0
    token = njs_lexer_token(parser->lexer, 0);
2525
0
    if (token == NULL) {
2526
0
        return NJS_ERROR;
2527
0
    }
2528
2529
0
    if (!njs_lexer_token_is_identifier_name(token)) {
2530
0
        return njs_parser_failed(parser);
2531
0
    }
2532
2533
0
    return njs_parser_stack_pop(parser);
2534
0
}
2535
2536
2537
static njs_int_t
2538
njs_parser_member_expression_import(njs_parser_t *parser,
2539
    njs_lexer_token_t *token, njs_queue_link_t *current)
2540
0
{
2541
    /*
2542
     * import . meta
2543
     */
2544
2545
0
    if (token->type != NJS_TOKEN_DOT) {
2546
0
        return njs_parser_failed(parser);
2547
0
    }
2548
2549
0
    njs_lexer_consume_token(parser->lexer, 1);
2550
2551
0
    token = njs_lexer_token(parser->lexer, 0);
2552
0
    if (token == NULL) {
2553
0
        return NJS_ERROR;
2554
0
    }
2555
2556
0
    if (token->type != NJS_TOKEN_META) {
2557
0
        return njs_parser_failed(parser);
2558
0
    }
2559
2560
0
    njs_lexer_consume_token(parser->lexer, 1);
2561
2562
0
    return njs_parser_stack_pop(parser);
2563
0
}
2564
2565
2566
static njs_int_t
2567
njs_parser_member_expression_new(njs_parser_t *parser,
2568
    njs_lexer_token_t *token, njs_queue_link_t *current)
2569
206
{
2570
    /*
2571
     * new MemberExpression Arguments
2572
     * new . target
2573
     */
2574
2575
206
    if (token->type != NJS_TOKEN_DOT) {
2576
206
        njs_parser_next(parser, njs_parser_member_expression_new_next);
2577
2578
206
        return njs_parser_after(parser, current, NULL, 1,
2579
206
                                njs_parser_member_expression_new_after);
2580
206
    }
2581
2582
    /* njs_lexer_consume_token(parser->lexer, 1); */
2583
2584
0
    token = njs_lexer_token(parser->lexer, 0);
2585
0
    if (token == NULL) {
2586
0
        return NJS_ERROR;
2587
0
    }
2588
2589
0
    if (token->type != NJS_TOKEN_TARGET) {
2590
0
        return njs_parser_failed(parser);
2591
0
    }
2592
2593
    /* njs_lexer_consume_token(parser->lexer, 1); */
2594
2595
    /* return njs_parser_stack_pop(parser); */
2596
0
    return njs_parser_not_supported(parser, token);
2597
0
}
2598
2599
2600
static njs_int_t
2601
njs_parser_member_expression_new_after(njs_parser_t *parser,
2602
    njs_lexer_token_t *token, njs_queue_link_t *current)
2603
206
{
2604
206
    njs_parser_node_t  *func;
2605
2606
206
    if (token->type != NJS_TOKEN_OPEN_PARENTHESIS) {
2607
16
        parser->node = njs_parser_create_call(parser, parser->node, 1);
2608
16
        if (parser->node == NULL) {
2609
0
            return NJS_ERROR;
2610
0
        }
2611
2612
16
        parser->node->token_line = token->line;
2613
2614
16
        return njs_parser_stack_pop(parser);
2615
16
    }
2616
2617
190
    func = njs_parser_create_call(parser, parser->node, 1);
2618
190
    if (func == NULL) {
2619
0
        return NJS_ERROR;
2620
0
    }
2621
2622
190
    func->token_line = token->line;
2623
190
    parser->node = func;
2624
2625
190
    njs_lexer_consume_token(parser->lexer, 1);
2626
190
    njs_parser_next(parser, njs_parser_arguments);
2627
2628
190
    return njs_parser_after(parser, current, func, 1,
2629
190
                            njs_parser_member_expression_new_args);
2630
190
}
2631
2632
2633
static njs_int_t
2634
njs_parser_member_expression_new_args(njs_parser_t *parser,
2635
    njs_lexer_token_t *token, njs_queue_link_t *current)
2636
189
{
2637
189
    parser->node = parser->target;
2638
2639
189
    return njs_parser_stack_pop(parser);
2640
189
}
2641
2642
2643
static njs_parser_node_t *
2644
njs_parser_create_call(njs_parser_t *parser, njs_parser_node_t *node,
2645
    uint8_t ctor)
2646
140k
{
2647
140k
    njs_parser_node_t  *func;
2648
2649
140k
    switch (node->token_type) {
2650
21.8k
    case NJS_TOKEN_NAME:
2651
21.8k
        func = node;
2652
21.8k
        func->token_type = NJS_TOKEN_FUNCTION_CALL;
2653
2654
21.8k
        break;
2655
2656
3.90k
    case NJS_TOKEN_PROPERTY:
2657
3.90k
        func = njs_parser_node_new(parser, NJS_TOKEN_METHOD_CALL);
2658
3.90k
        if (func == NULL) {
2659
0
            return NULL;
2660
0
        }
2661
2662
3.90k
        func->left = node;
2663
3.90k
        break;
2664
2665
114k
    default:
2666
        /*
2667
         * NJS_TOKEN_METHOD_CALL,
2668
         * NJS_TOKEN_FUNCTION_CALL,
2669
         * NJS_TOKEN_FUNCTION_EXPRESSION,
2670
         * NJS_TOKEN_OPEN_PARENTHESIS,
2671
         * NJS_TOKEN_EVAL.
2672
         */
2673
114k
        func = njs_parser_node_new(parser, NJS_TOKEN_FUNCTION_CALL);
2674
114k
        if (func == NULL) {
2675
0
            return NULL;
2676
0
        }
2677
2678
114k
        func->left = node;
2679
114k
        break;
2680
140k
    }
2681
2682
140k
    func->ctor = ctor;
2683
2684
140k
    return func;
2685
140k
}
2686
2687
2688
static njs_int_t
2689
njs_parser_call_expression(njs_parser_t *parser, njs_lexer_token_t *token,
2690
    njs_queue_link_t *current)
2691
429
{
2692
429
    njs_int_t  ret;
2693
2694
    /*
2695
     * CoverCallExpressionAndAsyncArrowHead
2696
     * SuperCall
2697
     * ImportCall
2698
     * CallExpression Arguments
2699
     * CallExpression [ Expression ]
2700
     * CallExpression . IdentifierName
2701
     * CallExpression TemplateLiteral
2702
     */
2703
2704
429
    switch (token->type) {
2705
    /* MemberExpression or SuperCall */
2706
0
    case NJS_TOKEN_SUPER:
2707
0
        return njs_parser_not_supported(parser, token);
2708
2709
429
    case NJS_TOKEN_IMPORT:
2710
429
        return njs_parser_not_supported(parser, token);
2711
2712
0
    default:
2713
0
        break;
2714
429
    }
2715
2716
0
    njs_parser_next(parser, njs_parser_member_expression);
2717
2718
0
    ret = njs_parser_after(parser, current, NULL, 1,
2719
0
                           njs_parser_call_expression_args);
2720
0
    if (ret != NJS_OK) {
2721
0
        return NJS_ERROR;
2722
0
    }
2723
2724
0
    return njs_parser_after(parser, current, NULL, 1,
2725
0
                            njs_parser_call_expression_after);
2726
0
}
2727
2728
2729
static njs_int_t
2730
njs_parser_call_expression_args(njs_parser_t *parser, njs_lexer_token_t *token,
2731
    njs_queue_link_t *current)
2732
0
{
2733
0
    njs_parser_node_t  *func;
2734
2735
0
    if (token->type != NJS_TOKEN_OPEN_PARENTHESIS) {
2736
0
        return njs_parser_failed(parser);
2737
0
    }
2738
2739
0
    func = njs_parser_create_call(parser, parser->node, 0);
2740
0
    if (func == NULL) {
2741
0
        return NJS_ERROR;
2742
0
    }
2743
2744
0
    func->token_line = token->line;
2745
0
    parser->node = func;
2746
2747
0
    njs_lexer_consume_token(parser->lexer, 1);
2748
0
    njs_parser_next(parser, njs_parser_arguments);
2749
2750
0
    return njs_parser_after(parser, current, func, 1,
2751
0
                            njs_parser_left_hand_side_expression_node);
2752
0
}
2753
2754
2755
static njs_int_t
2756
njs_parser_call_expression_after(njs_parser_t *parser,
2757
    njs_lexer_token_t *token, njs_queue_link_t *current)
2758
0
{
2759
0
    njs_int_t          ret;
2760
0
    njs_parser_node_t  *func;
2761
2762
    /*
2763
     * Arguments
2764
     * [ Expression ]
2765
     * . IdentifierName
2766
     * TemplateLiteral
2767
     */
2768
2769
0
    switch (token->type) {
2770
0
    case NJS_TOKEN_OPEN_PARENTHESIS:
2771
0
        func = njs_parser_create_call(parser, parser->node, 0);
2772
0
        if (func == NULL) {
2773
0
            return NJS_ERROR;
2774
0
        }
2775
2776
0
        func->token_line = token->line;
2777
0
        parser->node = func;
2778
2779
0
        njs_lexer_consume_token(parser->lexer, 1);
2780
0
        njs_parser_next(parser, njs_parser_arguments);
2781
2782
0
        ret = njs_parser_after(parser, current, func, 1,
2783
0
                               njs_parser_left_hand_side_expression_node);
2784
0
        if (ret != NJS_OK) {
2785
0
            return NJS_ERROR;
2786
0
        }
2787
2788
0
        break;
2789
2790
0
    default:
2791
0
        ret = njs_parser_property(parser, token, current);
2792
2793
0
        switch (ret) {
2794
0
        case NJS_AGAIN:
2795
0
            return NJS_OK;
2796
2797
0
        case NJS_DONE:
2798
0
            return njs_parser_stack_pop(parser);
2799
2800
0
        case NJS_DECLINED:
2801
0
            return njs_parser_failed(parser);
2802
2803
0
        default:
2804
0
            break;
2805
0
        }
2806
2807
0
        break;
2808
0
    }
2809
2810
0
    return njs_parser_after(parser, current, NULL, 1,
2811
0
                            njs_parser_call_expression_after);
2812
0
}
2813
2814
2815
static njs_int_t
2816
njs_parser_arguments(njs_parser_t *parser, njs_lexer_token_t *token,
2817
    njs_queue_link_t *current)
2818
23.9k
{
2819
    /*
2820
     * )
2821
     * ArgumentList )
2822
     * ArgumentList , )
2823
     */
2824
2825
23.9k
    if (token->type == NJS_TOKEN_CLOSE_PARENTHESIS) {
2826
7.84k
        njs_lexer_consume_token(parser->lexer, 1);
2827
7.84k
        return njs_parser_stack_pop(parser);
2828
7.84k
    }
2829
2830
16.0k
    parser->scope->in_args++;
2831
2832
16.0k
    njs_parser_next(parser, njs_parser_argument_list);
2833
2834
16.0k
    return njs_parser_after(parser, current, NULL, 1,
2835
23.9k
                            njs_parser_parenthesis_or_comma);
2836
23.9k
}
2837
2838
2839
static njs_int_t
2840
njs_parser_parenthesis_or_comma(njs_parser_t *parser, njs_lexer_token_t *token,
2841
    njs_queue_link_t *current)
2842
12.6k
{
2843
12.6k
    parser->scope->in_args--;
2844
2845
12.6k
    if (token->type == NJS_TOKEN_CLOSE_PARENTHESIS) {
2846
10.1k
        njs_lexer_consume_token(parser->lexer, 1);
2847
10.1k
        return njs_parser_stack_pop(parser);
2848
10.1k
    }
2849
2850
2.56k
    if (token->type != NJS_TOKEN_COMMA) {
2851
2.56k
        return njs_parser_failed(parser);
2852
2.56k
    }
2853
2854
0
    njs_lexer_consume_token(parser->lexer, 1);
2855
2856
0
    token = njs_lexer_token(parser->lexer, 0);
2857
0
    if (njs_slow_path(token == NULL)) {
2858
0
        return NJS_ERROR;
2859
0
    }
2860
2861
0
    if (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) {
2862
0
        return njs_parser_failed(parser);
2863
0
    }
2864
2865
0
    njs_lexer_consume_token(parser->lexer, 1);
2866
2867
0
    return njs_parser_stack_pop(parser);
2868
0
}
2869
2870
2871
static njs_int_t
2872
njs_parser_argument_list(njs_parser_t *parser, njs_lexer_token_t *token,
2873
    njs_queue_link_t *current)
2874
21.7k
{
2875
    /*
2876
     * AssignmentExpression
2877
     * ... AssignmentExpression
2878
     * ArgumentList , AssignmentExpression
2879
     * ArgumentList , ... AssignmentExpression
2880
     */
2881
2882
#if 0 /* TODO. */
2883
    if (token->type == NJS_TOKEN_ELLIPSIS) {
2884
        njs_lexer_consume_token(parser->lexer, 1);
2885
    }
2886
#endif
2887
2888
21.7k
    njs_parser_next(parser, njs_parser_assignment_expression);
2889
2890
21.7k
    return njs_parser_after(parser, current, parser->node, 1,
2891
21.7k
                            njs_parser_argument_list_after);
2892
21.7k
}
2893
2894
2895
static njs_int_t
2896
njs_parser_argument_list_after(njs_parser_t *parser, njs_lexer_token_t *token,
2897
    njs_queue_link_t *current)
2898
18.3k
{
2899
18.3k
    njs_parser_node_t  *node;
2900
2901
18.3k
    node = njs_parser_node_new(parser, NJS_TOKEN_ARGUMENT);
2902
18.3k
    if (node == NULL) {
2903
0
        return NJS_ERROR;
2904
0
    }
2905
2906
18.3k
    node->index = njs_scope_temp_index(node->scope);
2907
18.3k
    if (njs_slow_path(node->index == NJS_INDEX_ERROR)) {
2908
0
        return NJS_ERROR;
2909
0
    }
2910
2911
18.3k
    node->token_line = token->line;
2912
18.3k
    node->left = parser->node;
2913
2914
18.3k
    parser->node->dest = node;
2915
18.3k
    parser->target->right = node;
2916
18.3k
    parser->node = node;
2917
2918
18.3k
    if (token->type == NJS_TOKEN_COMMA) {
2919
5.69k
        njs_lexer_consume_token(parser->lexer, 1);
2920
2921
5.69k
        token = njs_lexer_token(parser->lexer, 0);
2922
5.69k
        if (token == NULL) {
2923
0
            return NJS_ERROR;
2924
0
        }
2925
2926
5.69k
        if (token->type == NJS_TOKEN_CLOSE_PARENTHESIS) {
2927
19
            return njs_parser_stack_pop(parser);
2928
19
        }
2929
2930
5.67k
        return njs_parser_argument_list(parser, token, current);
2931
5.69k
    }
2932
2933
12.6k
    return njs_parser_stack_pop(parser);
2934
18.3k
}
2935
2936
2937
static njs_int_t
2938
njs_parser_optional_expression_after(njs_parser_t *parser,
2939
    njs_lexer_token_t *token, njs_queue_link_t *current)
2940
836
{
2941
836
    if (token->type != NJS_TOKEN_CONDITIONAL) {
2942
0
        return njs_parser_stack_pop(parser);
2943
0
    }
2944
2945
836
    token = njs_lexer_peek_token(parser->lexer, token, 0);
2946
836
    if (token == NULL) {
2947
0
        return NJS_ERROR;
2948
0
    }
2949
2950
836
    if (token->type != NJS_TOKEN_DOT) {
2951
836
        return njs_parser_stack_pop(parser);
2952
836
    }
2953
2954
0
    njs_parser_next(parser, njs_parser_optional_chain);
2955
2956
0
    return njs_parser_after(parser, current, NULL, 1,
2957
836
                            njs_parser_optional_expression_after);
2958
836
}
2959
2960
2961
static njs_int_t
2962
njs_parser_optional_chain(njs_parser_t *parser, njs_lexer_token_t *token,
2963
    njs_queue_link_t *current)
2964
0
{
2965
0
    njs_int_t          ret;
2966
0
    njs_parser_node_t  *func;
2967
2968
    /*
2969
     * ? . Arguments
2970
     * ? . [ Expression ]
2971
     * ? . IdentifierName
2972
     * ? . TemplateLiteral
2973
     * OptionalChain Arguments
2974
     * OptionalChain [ Expression ]
2975
     * OptionalChain . IdentifierName
2976
     * OptionalChain TemplateLiteral
2977
     */
2978
2979
0
    if (token->type != NJS_TOKEN_CONDITIONAL) {
2980
0
        return njs_parser_failed(parser);
2981
0
    }
2982
2983
0
    token = njs_lexer_peek_token(parser->lexer, token, 0);
2984
0
    if (token == NULL) {
2985
0
        return NJS_ERROR;
2986
0
    }
2987
2988
0
    if (token->type != NJS_TOKEN_DOT) {
2989
0
        return njs_parser_failed(parser);
2990
0
    }
2991
2992
0
    njs_lexer_consume_token(parser->lexer, 1);
2993
2994
0
    token = njs_lexer_token(parser->lexer, 0);
2995
0
    if (token == NULL) {
2996
0
        return NJS_ERROR;
2997
0
    }
2998
2999
0
    switch (token->type) {
3000
0
    case NJS_TOKEN_OPEN_PARENTHESIS:
3001
0
        func = njs_parser_create_call(parser, parser->node, 0);
3002
0
        if (func == NULL) {
3003
0
            return NJS_ERROR;
3004
0
        }
3005
3006
0
        func->token_line = token->line;
3007
0
        parser->node = func;
3008
3009
0
        njs_lexer_consume_token(parser->lexer, 2);
3010
0
        njs_parser_next(parser, njs_parser_arguments);
3011
3012
0
        ret = njs_parser_after(parser, current, func, 1,
3013
0
                               njs_parser_left_hand_side_expression_node);
3014
0
        if (ret != NJS_OK) {
3015
0
            return NJS_ERROR;
3016
0
        }
3017
3018
0
        break;
3019
3020
0
    default:
3021
0
        ret = njs_parser_property(parser, token, current);
3022
3023
0
        switch (ret) {
3024
0
        case NJS_DONE:
3025
0
        case NJS_DECLINED:
3026
0
            return njs_parser_failed(parser);
3027
3028
0
        default:
3029
0
            break;
3030
0
        }
3031
3032
0
        break;
3033
0
    }
3034
3035
0
    return njs_parser_after(parser, current, NULL, 1,
3036
0
                            njs_parser_optional_chain_after);
3037
0
}
3038
3039
3040
static njs_int_t
3041
njs_parser_optional_chain_after(njs_parser_t *parser, njs_lexer_token_t *token,
3042
    njs_queue_link_t *current)
3043
17.8k
{
3044
17.8k
    njs_int_t          ret;
3045
17.8k
    njs_parser_node_t  *func;
3046
3047
    /*
3048
     * OptionalChain Arguments
3049
     * OptionalChain [ Expression ]
3050
     * OptionalChain . IdentifierName
3051
     * OptionalChain TemplateLiteral
3052
     */
3053
3054
17.8k
    switch (token->type) {
3055
35
    case NJS_TOKEN_OPEN_PARENTHESIS:
3056
35
        func = njs_parser_create_call(parser, parser->node, 0);
3057
35
        if (func == NULL) {
3058
0
            return NJS_ERROR;
3059
0
        }
3060
3061
35
        func->token_line = token->line;
3062
35
        parser->node = func;
3063
3064
35
        njs_lexer_consume_token(parser->lexer, 1);
3065
35
        njs_parser_next(parser, njs_parser_arguments);
3066
3067
35
        ret = njs_parser_after(parser, current, func, 1,
3068
35
                               njs_parser_left_hand_side_expression_node);
3069
35
        if (ret != NJS_OK) {
3070
0
            return NJS_ERROR;
3071
0
        }
3072
3073
35
        break;
3074
3075
17.8k
    default:
3076
17.8k
        ret = njs_parser_property(parser, token, current);
3077
3078
17.8k
        switch (ret) {
3079
50
        case NJS_AGAIN:
3080
50
            return NJS_OK;
3081
3082
17.5k
        case NJS_DONE:
3083
17.5k
            return njs_parser_stack_pop(parser);
3084
3085
0
        case NJS_DECLINED:
3086
0
            return njs_parser_failed(parser);
3087
3088
267
        default:
3089
267
            break;
3090
17.8k
        }
3091
3092
267
        break;
3093
17.8k
    }
3094
3095
302
    return njs_parser_after(parser, current, NULL, 1,
3096
17.8k
                            njs_parser_optional_chain_after);
3097
17.8k
}
3098
3099
3100
static njs_int_t
3101
njs_parser_new_expression(njs_parser_t *parser, njs_lexer_token_t *token,
3102
    njs_queue_link_t *current)
3103
0
{
3104
0
    if (token->type != NJS_TOKEN_NEW) {
3105
0
        parser->node = NULL;
3106
3107
0
        njs_parser_next(parser, njs_parser_member_expression_new);
3108
3109
0
        return NJS_OK;
3110
0
    }
3111
3112
0
    njs_lexer_consume_token(parser->lexer, 1);
3113
3114
0
    return njs_parser_after(parser, current, NULL, 1,
3115
0
                            njs_parser_new_expression_after);
3116
0
}
3117
3118
3119
static njs_int_t
3120
njs_parser_new_expression_after(njs_parser_t *parser, njs_lexer_token_t *token,
3121
    njs_queue_link_t *current)
3122
0
{
3123
0
    njs_parser_node_t  *func;
3124
3125
0
    if (token->type == NJS_TOKEN_OPEN_PARENTHESIS) {
3126
0
        njs_parser_next(parser, njs_parser_member_expression_new_after);
3127
0
        return NJS_OK;
3128
0
    }
3129
3130
0
    func = njs_parser_create_call(parser, parser->node, 1);
3131
0
    if (func == NULL) {
3132
0
        return NJS_ERROR;
3133
0
    }
3134
3135
0
    func->token_line = token->line;
3136
0
    parser->node = func;
3137
3138
0
    return njs_parser_stack_pop(parser);
3139
0
}
3140
3141
3142
static njs_int_t
3143
njs_parser_left_hand_side_expression(njs_parser_t *parser,
3144
    njs_lexer_token_t *token, njs_queue_link_t *current)
3145
1.72M
{
3146
    /*
3147
     * NewExpression = new MemberExpression
3148
     * CallExpression = MemberExpression Arguments
3149
     * OptionalExpression = MemberExpression OptionalChain
3150
     */
3151
3152
1.72M
    switch (token->type) {
3153
    /* NewExpression or MemberExpression */
3154
206
    case NJS_TOKEN_NEW:
3155
206
        token = njs_lexer_peek_token(parser->lexer, token, 0);
3156
206
        if (token == NULL) {
3157
0
            return NJS_ERROR;
3158
0
        }
3159
3160
206
        if (token->type == NJS_TOKEN_NEW) {
3161
0
            njs_lexer_consume_token(parser->lexer, 1);
3162
3163
0
            njs_parser_next(parser, njs_parser_new_expression);
3164
3165
0
            return njs_parser_after(parser, current, NULL, 1,
3166
0
                                    njs_parser_left_hand_side_expression_after);
3167
0
        }
3168
3169
206
        break;
3170
3171
    /* CallExpression or MemberExpression */
3172
206
    case NJS_TOKEN_SUPER:
3173
429
    case NJS_TOKEN_IMPORT:
3174
429
        token = njs_lexer_peek_token(parser->lexer, token, 0);
3175
429
        if (token == NULL) {
3176
0
            return NJS_ERROR;
3177
0
        }
3178
3179
429
        if (token->type == NJS_TOKEN_OPEN_PARENTHESIS) {
3180
429
            njs_parser_next(parser, njs_parser_call_expression);
3181
429
            return NJS_OK;
3182
429
        }
3183
3184
0
        break;
3185
3186
1.72M
    default:
3187
1.72M
        break;
3188
1.72M
    }
3189
3190
1.72M
    njs_parser_next(parser, njs_parser_member_expression);
3191
3192
1.72M
    return njs_parser_after(parser, current, NULL, 1,
3193
1.72M
                            njs_parser_left_hand_side_expression_after);
3194
1.72M
}
3195
3196
3197
static njs_int_t
3198
njs_parser_left_hand_side_expression_after(njs_parser_t *parser,
3199
    njs_lexer_token_t *token, njs_queue_link_t *current)
3200
1.63M
{
3201
1.63M
    njs_int_t          ret;
3202
1.63M
    njs_parser_node_t  *func;
3203
3204
1.63M
    switch (token->type) {
3205
    /* CallExpression */
3206
23.6k
    case NJS_TOKEN_OPEN_PARENTHESIS:
3207
23.6k
        func = njs_parser_create_call(parser, parser->node, 0);
3208
23.6k
        if (func == NULL) {
3209
0
            return NJS_ERROR;
3210
0
        }
3211
3212
23.6k
        func->token_line = token->line;
3213
23.6k
        parser->node = func;
3214
3215
23.6k
        njs_lexer_consume_token(parser->lexer, 1);
3216
23.6k
        njs_parser_next(parser, njs_parser_arguments);
3217
3218
23.6k
        ret = njs_parser_after(parser, current, func, 1,
3219
23.6k
                               njs_parser_left_hand_side_expression_node);
3220
23.6k
        if (ret != NJS_OK) {
3221
0
            return NJS_ERROR;
3222
0
        }
3223
3224
23.6k
        return njs_parser_after(parser, current, NULL, 1,
3225
23.6k
                                njs_parser_left_hand_side_expression_optional);
3226
3227
    /* OptionalExpression */
3228
836
    case NJS_TOKEN_CONDITIONAL:
3229
836
        njs_parser_next(parser, njs_parser_optional_expression_after);
3230
836
        break;
3231
3232
1.61M
    default:
3233
1.61M
        return njs_parser_stack_pop(parser);
3234
1.63M
    }
3235
3236
836
    return NJS_OK;
3237
1.63M
}
3238
3239
3240
static njs_int_t
3241
njs_parser_left_hand_side_expression_node(njs_parser_t *parser,
3242
    njs_lexer_token_t *token, njs_queue_link_t *current)
3243
17.7k
{
3244
17.7k
    parser->node = parser->target;
3245
3246
17.7k
    return njs_parser_stack_pop(parser);
3247
17.7k
}
3248
3249
3250
static njs_int_t
3251
njs_parser_left_hand_side_expression_optional(njs_parser_t *parser,
3252
    njs_lexer_token_t *token, njs_queue_link_t *current)
3253
17.7k
{
3254
    /* OptionalExpression */
3255
17.7k
    if (token->type == NJS_TOKEN_CONDITIONAL) {
3256
0
        njs_parser_next(parser, njs_parser_optional_expression_after);
3257
0
        return NJS_OK;
3258
0
    }
3259
3260
17.7k
    njs_parser_next(parser, njs_parser_optional_chain_after);
3261
3262
17.7k
    return NJS_OK;
3263
17.7k
}
3264
3265
3266
static njs_int_t
3267
njs_parser_expression_node(njs_parser_t *parser, njs_lexer_token_t *token,
3268
    njs_queue_link_t *current, njs_token_type_t type, njs_vmcode_t operation,
3269
    njs_parser_state_func_t after)
3270
8.14M
{
3271
8.14M
    njs_parser_node_t  *node;
3272
3273
8.14M
    if (parser->target != NULL) {
3274
22.5k
        parser->target->right = parser->node;
3275
22.5k
        parser->target->right->dest = parser->target;
3276
22.5k
        parser->node = parser->target;
3277
22.5k
    }
3278
3279
8.14M
    if (token->type != type) {
3280
8.12M
        return njs_parser_stack_pop(parser);
3281
8.12M
    }
3282
3283
23.6k
    node = njs_parser_node_new(parser, type);
3284
23.6k
    if (node == NULL) {
3285
0
        return NJS_ERROR;
3286
0
    }
3287
3288
23.6k
    node->token_line = token->line;
3289
23.6k
    node->u.operation = operation;
3290
23.6k
    node->left = parser->node;
3291
23.6k
    node->left->dest = node;
3292
3293
23.6k
    njs_lexer_consume_token(parser->lexer, 1);
3294
3295
23.6k
    return njs_parser_after(parser, current, node, 1, after);
3296
23.6k
}
3297
3298
3299
/*
3300
 * 12.4 Update Expressions.
3301
 */
3302
static njs_int_t
3303
njs_parser_update_expression(njs_parser_t *parser, njs_lexer_token_t *token,
3304
    njs_queue_link_t *current)
3305
1.71M
{
3306
1.71M
    njs_vmcode_t       operation;
3307
1.71M
    njs_parser_node_t  *node;
3308
3309
1.71M
    switch (token->type) {
3310
883
    case NJS_TOKEN_INCREMENT:
3311
883
        operation = NJS_VMCODE_INCREMENT;
3312
883
        break;
3313
3314
3.44k
    case NJS_TOKEN_DECREMENT:
3315
3.44k
        operation = NJS_VMCODE_DECREMENT;
3316
3.44k
        break;
3317
3318
1.71M
    default:
3319
1.71M
        njs_parser_next(parser, njs_parser_left_hand_side_expression);
3320
3321
1.71M
        return njs_parser_after(parser, current, NULL, 1,
3322
1.71M
                                njs_parser_update_expression_post);
3323
1.71M
    }
3324
3325
4.33k
    node = njs_parser_node_new(parser, token->type);
3326
4.33k
    if (node == NULL) {
3327
0
        return NJS_ERROR;
3328
0
    }
3329
3330
4.33k
    node->token_line = token->line;
3331
4.33k
    node->u.operation = operation;
3332
3333
4.33k
    njs_lexer_consume_token(parser->lexer, 1);
3334
4.33k
    njs_parser_next(parser, njs_parser_left_hand_side_expression);
3335
3336
4.33k
    return njs_parser_after(parser, current, node, 1,
3337
4.33k
                            njs_parser_update_expression_unary);
3338
4.33k
}
3339
3340
3341
static njs_int_t
3342
njs_parser_update_expression_post(njs_parser_t *parser,
3343
    njs_lexer_token_t *token, njs_queue_link_t *current)
3344
1.62M
{
3345
1.62M
    njs_vmcode_t       operation;
3346
1.62M
    njs_token_type_t   type;
3347
1.62M
    njs_parser_node_t  *node;
3348
3349
    /* [no LineTerminator here] */
3350
3351
1.62M
    switch (token->type) {
3352
7.64k
    case NJS_TOKEN_INCREMENT:
3353
7.64k
        type = NJS_TOKEN_POST_INCREMENT;
3354
7.64k
        operation = NJS_VMCODE_POST_INCREMENT;
3355
7.64k
        break;
3356
3357
4.21k
    case NJS_TOKEN_DECREMENT:
3358
4.21k
        type = NJS_TOKEN_POST_DECREMENT;
3359
4.21k
        operation = NJS_VMCODE_POST_DECREMENT;
3360
4.21k
        break;
3361
3362
1.61M
    default:
3363
1.61M
        return njs_parser_stack_pop(parser);
3364
1.62M
    }
3365
3366
11.8k
    if (parser->lexer->prev_type == NJS_TOKEN_LINE_END) {
3367
435
        return njs_parser_stack_pop(parser);
3368
435
    }
3369
3370
11.4k
    if (!njs_parser_is_lvalue(parser->node)) {
3371
0
        njs_lexer_consume_token(parser->lexer, 1);
3372
3373
0
        njs_parser_ref_error(parser,
3374
0
                             "Invalid left-hand side in postfix operation");
3375
0
        return NJS_DONE;
3376
0
    }
3377
3378
11.4k
    node = njs_parser_node_new(parser, type);
3379
11.4k
    if (node == NULL) {
3380
0
        return NJS_ERROR;
3381
0
    }
3382
3383
11.4k
    node->token_line = token->line;
3384
11.4k
    node->u.operation = operation;
3385
11.4k
    node->left = parser->node;
3386
3387
11.4k
    parser->node = node;
3388
3389
11.4k
    njs_lexer_consume_token(parser->lexer, 1);
3390
3391
11.4k
    return njs_parser_stack_pop(parser);
3392
11.4k
}
3393
3394
3395
static njs_int_t
3396
njs_parser_update_expression_unary(njs_parser_t *parser,
3397
    njs_lexer_token_t *token, njs_queue_link_t *current)
3398
4.33k
{
3399
4.33k
    if (!njs_parser_is_lvalue(parser->node)) {
3400
0
        njs_parser_ref_error(parser,
3401
0
                             "Invalid left-hand side in prefix operation");
3402
0
        return NJS_DONE;
3403
0
    }
3404
3405
4.33k
    parser->target->left = parser->node;
3406
4.33k
    parser->node = parser->target;
3407
3408
4.33k
    return njs_parser_stack_pop(parser);
3409
4.33k
}
3410
3411
3412
/*
3413
 * 12.5 Unary Operators.
3414
 */
3415
static njs_int_t
3416
njs_parser_unary_expression(njs_parser_t *parser, njs_lexer_token_t *token,
3417
    njs_queue_link_t *current)
3418
1.74M
{
3419
1.74M
    njs_vmcode_t       operation;
3420
1.74M
    njs_token_type_t   type;
3421
1.74M
    njs_parser_node_t  *node;
3422
3423
1.74M
    switch (token->type) {
3424
16
    case NJS_TOKEN_DELETE:
3425
16
        type = NJS_TOKEN_DELETE;
3426
16
        operation = NJS_VMCODE_DELETE;
3427
16
        break;
3428
3429
146
    case NJS_TOKEN_VOID:
3430
146
        type = NJS_TOKEN_VOID;
3431
146
        operation = NJS_VMCODE_VOID;
3432
146
        break;
3433
3434
8
    case NJS_TOKEN_TYPEOF:
3435
8
        type = NJS_TOKEN_TYPEOF;
3436
8
        operation = NJS_VMCODE_TYPEOF;
3437
8
        break;
3438
3439
8.30k
    case NJS_TOKEN_ADDITION:
3440
8.30k
        type = NJS_TOKEN_UNARY_PLUS;
3441
8.30k
        operation = NJS_VMCODE_UNARY_PLUS;
3442
8.30k
        break;
3443
3444
13.0k
    case NJS_TOKEN_SUBTRACTION:
3445
13.0k
        type = NJS_TOKEN_UNARY_NEGATION;
3446
13.0k
        operation = NJS_VMCODE_UNARY_NEGATION;
3447
13.0k
        break;
3448
3449
1.18k
    case NJS_TOKEN_BITWISE_NOT:
3450
1.18k
        type = NJS_TOKEN_BITWISE_NOT;
3451
1.18k
        operation = NJS_VMCODE_BITWISE_NOT;
3452
1.18k
        break;
3453
3454
4.07k
    case NJS_TOKEN_LOGICAL_NOT:
3455
4.07k
        type = NJS_TOKEN_LOGICAL_NOT;
3456
4.07k
        operation = NJS_VMCODE_LOGICAL_NOT;
3457
4.07k
        break;
3458
3459
    /* AwaitExpression */
3460
2.30k
    case NJS_TOKEN_AWAIT:
3461
2.30k
        njs_parser_next(parser, njs_parser_await);
3462
2.30k
        return NJS_OK;
3463
3464
1.71M
    default:
3465
1.71M
        njs_parser_next(parser, njs_parser_update_expression);
3466
3467
1.71M
        return njs_parser_after(parser, current, parser->target, 1,
3468
1.74M
                                njs_parser_unary_expression_after);
3469
1.74M
    }
3470
3471
26.7k
    node = njs_parser_node_new(parser, type);
3472
26.7k
    if (node == NULL) {
3473
0
        return NJS_ERROR;
3474
0
    }
3475
3476
26.7k
    node->token_line = token->line;
3477
26.7k
    node->u.operation = operation;
3478
3479
26.7k
    parser->target = node;
3480
3481
26.7k
    njs_lexer_consume_token(parser->lexer, 1);
3482
3483
26.7k
    return njs_parser_after(parser, current, node, 1,
3484
26.7k
                            njs_parser_unary_expression_next);
3485
26.7k
}
3486
3487
3488
static njs_int_t
3489
njs_parser_unary_expression_after(njs_parser_t *parser,
3490
    njs_lexer_token_t *token, njs_queue_link_t *current)
3491
1.62M
{
3492
1.62M
    if (parser->target == NULL &&
3493
1.62M
        token->type == NJS_TOKEN_EXPONENTIATION)
3494
912
    {
3495
912
        return njs_parser_exponentiation_expression_match(parser, token,
3496
912
                                                          current);
3497
912
    }
3498
3499
1.62M
    return njs_parser_stack_pop(parser);
3500
1.62M
}
3501
3502
3503
static njs_int_t
3504
njs_parser_unary_expression_next(njs_parser_t *parser,
3505
    njs_lexer_token_t *token, njs_queue_link_t *current)
3506
25.8k
{
3507
25.8k
    double             num;
3508
25.8k
    njs_token_type_t   type;
3509
25.8k
    njs_parser_node_t  *node;
3510
3511
25.8k
    type = parser->target->token_type;
3512
25.8k
    node = parser->node;
3513
3514
25.8k
    if (token->type == NJS_TOKEN_EXPONENTIATION) {
3515
0
        njs_parser_syntax_error(parser, "Either left-hand side or entire "
3516
0
                                "exponentiation must be parenthesized");
3517
0
        return NJS_DONE;
3518
0
    }
3519
3520
25.8k
    if (node->token_type == NJS_TOKEN_NUMBER) {
3521
5.26k
        if (type == NJS_TOKEN_UNARY_PLUS) {
3522
            /* Skip the unary plus of number. */
3523
25
            return njs_parser_stack_pop(parser);
3524
25
        }
3525
3526
5.23k
        if (type == NJS_TOKEN_UNARY_NEGATION) {
3527
            /* Optimization of common negative number. */
3528
4.65k
            num = -njs_number(&node->u.value);
3529
4.65k
            njs_set_number(&node->u.value, num);
3530
3531
4.65k
            return njs_parser_stack_pop(parser);
3532
4.65k
        }
3533
5.23k
    }
3534
3535
21.1k
    if (type == NJS_TOKEN_DELETE) {
3536
16
        switch (node->token_type) {
3537
3538
11
        case NJS_TOKEN_PROPERTY:
3539
11
            node->token_type = NJS_TOKEN_PROPERTY_DELETE;
3540
11
            node->u.operation = NJS_VMCODE_PROPERTY_DELETE;
3541
3542
11
            return njs_parser_stack_pop(parser);
3543
3544
0
        case NJS_TOKEN_NAME:
3545
0
            njs_parser_syntax_error(parser,
3546
0
                                    "Delete of an unqualified identifier");
3547
0
            return NJS_DONE;
3548
3549
5
        default:
3550
5
            break;
3551
16
        }
3552
16
    }
3553
3554
21.1k
    if (type == NJS_TOKEN_TYPEOF && node->token_type == NJS_TOKEN_NAME) {
3555
0
        node->u.reference.type = NJS_TYPEOF;
3556
0
    }
3557
3558
21.1k
    parser->target->left = parser->node;
3559
21.1k
    parser->target->left->dest = parser->target;
3560
21.1k
    parser->node = parser->target;
3561
3562
21.1k
    return njs_parser_stack_pop(parser);
3563
21.1k
}
3564
3565
3566
static njs_int_t
3567
njs_parser_await(njs_parser_t *parser, njs_lexer_token_t *token,
3568
    njs_queue_link_t *current)
3569
2.30k
{
3570
2.30k
    njs_parser_node_t   *node;
3571
3572
2.30k
    if (!njs_function_scope(parser->scope)->async) {
3573
2.30k
        njs_parser_syntax_error(parser,
3574
2.30k
                                "await is only valid in async functions");
3575
2.30k
        return NJS_ERROR;
3576
2.30k
    }
3577
3578
1
    if (parser->scope->in_args > 0) {
3579
0
        njs_parser_syntax_error(parser, "await in arguments not supported");
3580
0
        return NJS_ERROR;
3581
0
    }
3582
3583
1
    node = njs_parser_node_new(parser, NJS_TOKEN_AWAIT);
3584
1
    if (njs_slow_path(node == NULL)) {
3585
0
        return NJS_ERROR;
3586
0
    }
3587
3588
1
    node->token_line = token->line;
3589
3590
1
    njs_lexer_consume_token(parser->lexer, 1);
3591
3592
1
    parser->node = NULL;
3593
3594
1
    njs_parser_next(parser, njs_parser_unary_expression);
3595
3596
1
    return njs_parser_after(parser, current, node, 0,
3597
1
                            njs_parser_await_after);
3598
1
}
3599
3600
3601
static njs_int_t
3602
njs_parser_await_after(njs_parser_t *parser, njs_lexer_token_t *token,
3603
    njs_queue_link_t *current)
3604
1
{
3605
1
    if (parser->ret != NJS_OK) {
3606
0
        return njs_parser_failed(parser);
3607
0
    }
3608
3609
1
    parser->target->right = parser->node;
3610
1
    parser->node = parser->target;
3611
3612
1
    return njs_parser_stack_pop(parser);
3613
1
}
3614
3615
3616
/*
3617
 * 12.6 Exponentiation Operator.
3618
 */
3619
static njs_int_t
3620
njs_parser_exponentiation_expression(njs_parser_t *parser,
3621
    njs_lexer_token_t *token, njs_queue_link_t *current)
3622
1.73M
{
3623
1.73M
    parser->target = NULL;
3624
3625
1.73M
    if (parser->use_lhs == 0) {
3626
1.72M
        njs_parser_next(parser, njs_parser_unary_expression);
3627
3628
        /* For UpdateExpression, see njs_parser_unary_expression_after. */
3629
3630
1.72M
        return NJS_OK;
3631
1.72M
    } else {
3632
10.1k
        parser->use_lhs = 0;
3633
3634
10.1k
        return njs_parser_update_expression_post(parser, token, current);
3635
10.1k
    }
3636
1.73M
}
3637
3638
3639
static njs_int_t
3640
njs_parser_exponentiation_expression_match(njs_parser_t *parser,
3641
    njs_lexer_token_t *token, njs_queue_link_t *current)
3642
1.82k
{
3643
1.82k
    njs_parser_node_t  *node;
3644
3645
1.82k
    if (parser->target != NULL) {
3646
912
        parser->target->right = parser->node;
3647
912
        parser->target->right->dest = parser->target;
3648
912
        parser->node = parser->target;
3649
3650
912
        return njs_parser_stack_pop(parser);
3651
912
    }
3652
3653
912
    if (token->type != NJS_TOKEN_EXPONENTIATION) {
3654
0
        return njs_parser_stack_pop(parser);
3655
0
    }
3656
3657
912
    node = njs_parser_node_new(parser, token->type);
3658
912
    if (node == NULL) {
3659
0
        return NJS_ERROR;
3660
0
    }
3661
3662
912
    node->token_line = token->line;
3663
912
    node->u.operation = NJS_VMCODE_EXPONENTIATION;
3664
912
    node->left = parser->node;
3665
912
    node->left->dest = node;
3666
3667
912
    njs_lexer_consume_token(parser->lexer, 1);
3668
3669
912
    njs_parser_next(parser, njs_parser_exponentiation_expression);
3670
3671
912
    return njs_parser_after(parser, current, node, 1,
3672
912
                            njs_parser_exponentiation_expression_match);
3673
912
}
3674
3675
3676
/*
3677
 * 12.7 Multiplicative Operators.
3678
 */
3679
static njs_int_t
3680
njs_parser_multiplicative_expression(njs_parser_t *parser,
3681
    njs_lexer_token_t *token, njs_queue_link_t *current)
3682
1.71M
{
3683
1.71M
    njs_parser_next(parser, njs_parser_exponentiation_expression);
3684
3685
1.71M
    return njs_parser_after(parser, current, NULL, 1,
3686
1.71M
                            njs_parser_multiplicative_expression_match);
3687
1.71M
}
3688
3689
3690
static njs_int_t
3691
njs_parser_multiplicative_expression_match(njs_parser_t *parser,
3692
    njs_lexer_token_t *token, njs_queue_link_t *current)
3693
1.63M
{
3694
1.63M
    njs_vmcode_t       operation;
3695
1.63M
    njs_parser_node_t  *node;
3696
3697
1.63M
    if (parser->target != NULL) {
3698
18.7k
        parser->target->right = parser->node;
3699
18.7k
        parser->target->right->dest = parser->target;
3700
18.7k
        parser->node = parser->target;
3701
18.7k
    }
3702
3703
1.63M
    switch (token->type) {
3704
2.34k
    case NJS_TOKEN_MULTIPLICATION:
3705
2.34k
        operation = NJS_VMCODE_MULTIPLICATION;
3706
2.34k
        break;
3707
3708
13.3k
    case NJS_TOKEN_DIVISION:
3709
13.3k
        operation = NJS_VMCODE_DIVISION;
3710
13.3k
        break;
3711
3712
3.94k
    case NJS_TOKEN_REMAINDER:
3713
3.94k
        operation = NJS_VMCODE_REMAINDER;
3714
3.94k
        break;
3715
3716
1.61M
    default:
3717
1.61M
        return njs_parser_stack_pop(parser);
3718
1.63M
    }
3719
3720
19.6k
    node = njs_parser_node_new(parser, token->type);
3721
19.6k
    if (node == NULL) {
3722
0
        return NJS_ERROR;
3723
0
    }
3724
3725
19.6k
    node->token_line = token->line;
3726
19.6k
    node->u.operation = operation;
3727
19.6k
    node->left = parser->node;
3728
19.6k
    node->left->dest = node;
3729
3730
19.6k
    njs_lexer_consume_token(parser->lexer, 1);
3731
3732
19.6k
    njs_parser_next(parser, njs_parser_exponentiation_expression);
3733
3734
19.6k
    return njs_parser_after(parser, current, node, 1,
3735
19.6k
                            njs_parser_multiplicative_expression_match);
3736
19.6k
}
3737
3738
3739
/*
3740
 * 12.8 Additive Operators.
3741
 */
3742
static njs_int_t
3743
njs_parser_additive_expression(njs_parser_t *parser, njs_lexer_token_t *token,
3744
    njs_queue_link_t *current)
3745
1.66M
{
3746
1.66M
    njs_parser_next(parser, njs_parser_multiplicative_expression);
3747
3748
1.66M
    return njs_parser_after(parser, current, NULL, 1,
3749
1.66M
                            njs_parser_additive_expression_match);
3750
1.66M
}
3751
3752
3753
static njs_int_t
3754
njs_parser_additive_expression_match(njs_parser_t *parser,
3755
    njs_lexer_token_t *token, njs_queue_link_t *current)
3756
1.61M
{
3757
1.61M
    njs_vmcode_t       operation;
3758
1.61M
    njs_parser_node_t  *node;
3759
3760
1.61M
    if (parser->target != NULL) {
3761
41.9k
        parser->target->right = parser->node;
3762
41.9k
        parser->target->right->dest = parser->target;
3763
41.9k
        parser->node = parser->target;
3764
41.9k
    }
3765
3766
1.61M
    switch (token->type) {
3767
11.4k
    case NJS_TOKEN_ADDITION:
3768
11.4k
        operation = NJS_VMCODE_ADDITION;
3769
11.4k
        break;
3770
3771
31.4k
    case NJS_TOKEN_SUBTRACTION:
3772
31.4k
        operation = NJS_VMCODE_SUBTRACTION;
3773
31.4k
        break;
3774
3775
1.56M
    default:
3776
1.56M
        return njs_parser_stack_pop(parser);
3777
1.61M
    }
3778
3779
42.9k
    node = njs_parser_node_new(parser, token->type);
3780
42.9k
    if (node == NULL) {
3781
0
        return NJS_ERROR;
3782
0
    }
3783
3784
42.9k
    node->token_line = token->line;
3785
42.9k
    node->u.operation = operation;
3786
42.9k
    node->left = parser->node;
3787
42.9k
    node->left->dest = node;
3788
3789
42.9k
    njs_lexer_consume_token(parser->lexer, 1);
3790
3791
42.9k
    njs_parser_next(parser, njs_parser_multiplicative_expression);
3792
3793
42.9k
    return njs_parser_after(parser, current, node, 1,
3794
42.9k
                            njs_parser_additive_expression_match);
3795
42.9k
}
3796
3797
3798
/*
3799
 * 12.9 Bitwise Shift Operators
3800
 */
3801
static njs_int_t
3802
njs_parser_shift_expression(njs_parser_t *parser, njs_lexer_token_t *token,
3803
    njs_queue_link_t *current)
3804
1.66M
{
3805
1.66M
    njs_parser_next(parser, njs_parser_additive_expression);
3806
3807
1.66M
    return njs_parser_after(parser, current, NULL, 1,
3808
1.66M
                            njs_parser_shift_expression_match);
3809
1.66M
}
3810
3811
3812
static njs_int_t
3813
njs_parser_shift_expression_match(njs_parser_t *parser,
3814
    njs_lexer_token_t *token, njs_queue_link_t *current)
3815
1.56M
{
3816
1.56M
    njs_vmcode_t       operation;
3817
1.56M
    njs_parser_node_t  *node;
3818
3819
1.56M
    if (parser->target != NULL) {
3820
1.53k
        parser->target->right = parser->node;
3821
1.53k
        parser->target->right->dest = parser->target;
3822
1.53k
        parser->node = parser->target;
3823
1.53k
    }
3824
3825
1.56M
    switch (token->type) {
3826
1.69k
    case NJS_TOKEN_RIGHT_SHIFT:
3827
1.69k
        operation = NJS_VMCODE_RIGHT_SHIFT;
3828
1.69k
        break;
3829
3830
112
    case NJS_TOKEN_LEFT_SHIFT:
3831
112
        operation = NJS_VMCODE_LEFT_SHIFT;
3832
112
        break;
3833
3834
7
    case NJS_TOKEN_UNSIGNED_RIGHT_SHIFT:
3835
7
        operation = NJS_VMCODE_UNSIGNED_RIGHT_SHIFT;
3836
7
        break;
3837
3838
1.56M
    default:
3839
1.56M
        return njs_parser_stack_pop(parser);
3840
1.56M
    }
3841
3842
1.81k
    node = njs_parser_node_new(parser, token->type);
3843
1.81k
    if (node == NULL) {
3844
0
        return NJS_ERROR;
3845
0
    }
3846
3847
1.81k
    node->token_line = token->line;
3848
1.81k
    node->u.operation = operation;
3849
1.81k
    node->left = parser->node;
3850
1.81k
    node->left->dest = node;
3851
3852
1.81k
    njs_lexer_consume_token(parser->lexer, 1);
3853
3854
1.81k
    njs_parser_next(parser, njs_parser_additive_expression);
3855
3856
1.81k
    return njs_parser_after(parser, current, node, 1,
3857
1.81k
                            njs_parser_shift_expression_match);
3858
1.81k
}
3859
3860
3861
/*
3862
 * 12.10 Relational Operators.
3863
 */
3864
static njs_int_t
3865
njs_parser_relational_expression(njs_parser_t *parser,
3866
    njs_lexer_token_t *token, njs_queue_link_t *current)
3867
1.65M
{
3868
1.65M
    njs_parser_next(parser, njs_parser_shift_expression);
3869
3870
1.65M
    return njs_parser_after(parser, current, NULL, 1,
3871
1.65M
                            njs_parser_relational_expression_match);
3872
1.65M
}
3873
3874
3875
static njs_int_t
3876
njs_parser_relational_expression_match(njs_parser_t *parser,
3877
    njs_lexer_token_t *token, njs_queue_link_t *current)
3878
1.56M
{
3879
1.56M
    njs_vmcode_t       operation;
3880
1.56M
    njs_parser_node_t  *node;
3881
3882
1.56M
    if (parser->target != NULL) {
3883
11.1k
        parser->target->right = parser->node;
3884
11.1k
        parser->target->right->dest = parser->target;
3885
11.1k
        parser->node = parser->target;
3886
11.1k
    }
3887
3888
1.56M
    switch (token->type) {
3889
3.13k
    case NJS_TOKEN_LESS:
3890
3.13k
        operation = NJS_VMCODE_LESS;
3891
3.13k
        break;
3892
3893
2.83k
    case NJS_TOKEN_GREATER:
3894
2.83k
        operation = NJS_VMCODE_GREATER;
3895
2.83k
        break;
3896
3897
42
    case NJS_TOKEN_LESS_OR_EQUAL:
3898
42
        operation = NJS_VMCODE_LESS_OR_EQUAL;
3899
42
        break;
3900
3901
14
    case NJS_TOKEN_GREATER_OR_EQUAL:
3902
14
        operation = NJS_VMCODE_GREATER_OR_EQUAL;
3903
14
        break;
3904
3905
2.20k
    case NJS_TOKEN_INSTANCEOF:
3906
2.20k
        operation = NJS_VMCODE_INSTANCE_OF;
3907
2.20k
        break;
3908
3909
5.29k
    case NJS_TOKEN_IN:
3910
5.29k
        if (njs_lexer_in_fail_get(parser->lexer)) {
3911
0
            njs_parser_syntax_error(parser, "Invalid left-hand side in for-loop");
3912
0
            return NJS_ERROR;
3913
0
        }
3914
5.29k
        operation = NJS_VMCODE_PROPERTY_IN;
3915
5.29k
        break;
3916
3917
1.55M
    default:
3918
1.55M
        return njs_parser_stack_pop(parser);
3919
1.56M
    }
3920
3921
13.5k
    node = njs_parser_node_new(parser, token->type);
3922
13.5k
    if (node == NULL) {
3923
0
        return NJS_ERROR;
3924
0
    }
3925
3926
13.5k
    node->token_line = token->line;
3927
13.5k
    node->u.operation = operation;
3928
13.5k
    node->left = parser->node;
3929
13.5k
    node->left->dest = node;
3930
3931
13.5k
    njs_lexer_consume_token(parser->lexer, 1);
3932
3933
13.5k
    njs_parser_next(parser, njs_parser_shift_expression);
3934
3935
13.5k
    return njs_parser_after(parser, current, node, 1,
3936
13.5k
                            njs_parser_relational_expression_match);
3937
13.5k
}
3938
3939
3940
/*
3941
 * 12.11 Equality Operators.
3942
 */
3943
static njs_int_t
3944
njs_parser_equality_expression(njs_parser_t *parser, njs_lexer_token_t *token,
3945
    njs_queue_link_t *current)
3946
1.65M
{
3947
1.65M
    njs_parser_next(parser, njs_parser_relational_expression);
3948
3949
1.65M
    return njs_parser_after(parser, current, NULL, 1,
3950
1.65M
                            njs_parser_equality_expression_match);
3951
1.65M
}
3952
3953
3954
static njs_int_t
3955
njs_parser_equality_expression_match(njs_parser_t *parser,
3956
    njs_lexer_token_t *token, njs_queue_link_t *current)
3957
1.55M
{
3958
1.55M
    njs_vmcode_t       operation;
3959
1.55M
    njs_parser_node_t  *node;
3960
3961
1.55M
    if (parser->target != NULL) {
3962
937
        parser->target->right = parser->node;
3963
937
        parser->target->right->dest = parser->target;
3964
937
        parser->node = parser->target;
3965
937
    }
3966
3967
1.55M
    switch (token->type) {
3968
767
    case NJS_TOKEN_EQUAL:
3969
767
        operation = NJS_VMCODE_EQUAL;
3970
767
        break;
3971
3972
11
    case NJS_TOKEN_NOT_EQUAL:
3973
11
        operation = NJS_VMCODE_NOT_EQUAL;
3974
11
        break;
3975
3976
22
    case NJS_TOKEN_STRICT_EQUAL:
3977
22
        operation = NJS_VMCODE_STRICT_EQUAL;
3978
22
        break;
3979
3980
137
    case NJS_TOKEN_STRICT_NOT_EQUAL:
3981
137
        operation = NJS_VMCODE_STRICT_NOT_EQUAL;
3982
137
        break;
3983
3984
1.55M
    default:
3985
1.55M
        return njs_parser_stack_pop(parser);
3986
1.55M
    }
3987
3988
937
    node = njs_parser_node_new(parser, token->type);
3989
937
    if (node == NULL) {
3990
0
        return NJS_ERROR;
3991
0
    }
3992
3993
937
    node->token_line = token->line;
3994
937
    node->u.operation = operation;
3995
937
    node->left = parser->node;
3996
937
    node->left->dest = node;
3997
3998
937
    njs_lexer_consume_token(parser->lexer, 1);
3999
4000
937
    njs_parser_next(parser, njs_parser_relational_expression);
4001
4002
937
    return njs_parser_after(parser, current, node, 1,
4003
937
                            njs_parser_equality_expression_match);
4004
937
}
4005
4006
4007
/*
4008
 * 12.12 Binary Bitwise Operators.
4009
 */
4010
static njs_int_t
4011
njs_parser_bitwise_AND_expression(njs_parser_t *parser,
4012
    njs_lexer_token_t *token, njs_queue_link_t *current)
4013
1.64M
{
4014
1.64M
    njs_parser_next(parser, njs_parser_equality_expression);
4015
4016
1.64M
    return njs_parser_after(parser, current, NULL, 1,
4017
1.64M
                            njs_parser_bitwise_AND_expression_and);
4018
1.64M
}
4019
4020
4021
static njs_int_t
4022
njs_parser_bitwise_AND_expression_and(njs_parser_t *parser,
4023
    njs_lexer_token_t *token, njs_queue_link_t *current)
4024
1.55M
{
4025
1.55M
    njs_parser_next(parser, njs_parser_equality_expression);
4026
4027
1.55M
    return njs_parser_expression_node(parser, token, current,
4028
1.55M
                                       NJS_TOKEN_BITWISE_AND,
4029
1.55M
                                       NJS_VMCODE_BITWISE_AND,
4030
1.55M
                                       njs_parser_bitwise_AND_expression_and);
4031
1.55M
}
4032
4033
4034
static njs_int_t
4035
njs_parser_bitwise_XOR_expression(njs_parser_t *parser,
4036
    njs_lexer_token_t *token, njs_queue_link_t *current)
4037
1.64M
{
4038
1.64M
    njs_parser_next(parser, njs_parser_bitwise_AND_expression);
4039
4040
1.64M
    return njs_parser_after(parser, current, NULL, 1,
4041
1.64M
                            njs_parser_bitwise_XOR_expression_xor);
4042
1.64M
}
4043
4044
4045
static njs_int_t
4046
njs_parser_bitwise_XOR_expression_xor(njs_parser_t *parser,
4047
    njs_lexer_token_t *token, njs_queue_link_t *current)
4048
1.55M
{
4049
1.55M
    njs_parser_next(parser, njs_parser_bitwise_AND_expression);
4050
4051
1.55M
    return njs_parser_expression_node(parser, token, current,
4052
1.55M
                                       NJS_TOKEN_BITWISE_XOR,
4053
1.55M
                                       NJS_VMCODE_BITWISE_XOR,
4054
1.55M
                                       njs_parser_bitwise_XOR_expression_xor);
4055
1.55M
}
4056
4057
4058
static njs_int_t
4059
njs_parser_bitwise_OR_expression(njs_parser_t *parser,
4060
    njs_lexer_token_t *token, njs_queue_link_t *current)
4061
1.64M
{
4062
1.64M
    njs_parser_next(parser, njs_parser_bitwise_XOR_expression);
4063
4064
1.64M
    return njs_parser_after(parser, current, NULL, 1,
4065
1.64M
                            njs_parser_bitwise_OR_expression_or);
4066
1.64M
}
4067
4068
4069
static njs_int_t
4070
njs_parser_bitwise_OR_expression_or(njs_parser_t *parser,
4071
    njs_lexer_token_t *token, njs_queue_link_t *current)
4072
1.54M
{
4073
1.54M
    njs_parser_next(parser, njs_parser_bitwise_XOR_expression);
4074
4075
1.54M
    return njs_parser_expression_node(parser, token, current,
4076
1.54M
                                       NJS_TOKEN_BITWISE_OR,
4077
1.54M
                                       NJS_VMCODE_BITWISE_OR,
4078
1.54M
                                       njs_parser_bitwise_OR_expression_or);
4079
1.54M
}
4080
4081
4082
/*
4083
 * 12.13 Binary Logical Operators.
4084
 */
4085
static njs_int_t
4086
njs_parser_logical_AND_expression(njs_parser_t *parser,
4087
    njs_lexer_token_t *token, njs_queue_link_t *current)
4088
1.64M
{
4089
1.64M
    njs_parser_next(parser, njs_parser_bitwise_OR_expression);
4090
4091
1.64M
    return njs_parser_after(parser, current, NULL, 1,
4092
1.64M
                            njs_parser_logical_AND_expression_and);
4093
1.64M
}
4094
4095
4096
static njs_int_t
4097
njs_parser_logical_AND_expression_and(njs_parser_t *parser,
4098
    njs_lexer_token_t *token, njs_queue_link_t *current)
4099
1.54M
{
4100
1.54M
    njs_parser_next(parser, njs_parser_bitwise_OR_expression);
4101
4102
1.54M
    return njs_parser_expression_node(parser, token, current,
4103
1.54M
                                       NJS_TOKEN_LOGICAL_AND,
4104
1.54M
                                       NJS_VMCODE_TEST_IF_FALSE,
4105
1.54M
                                       njs_parser_logical_AND_expression_and);
4106
1.54M
}
4107
4108
4109
static njs_int_t
4110
njs_parser_logical_OR_expression(njs_parser_t *parser,
4111
    njs_lexer_token_t *token, njs_queue_link_t *current)
4112
1.64M
{
4113
1.64M
    njs_parser_next(parser, njs_parser_logical_AND_expression);
4114
4115
1.64M
    return njs_parser_after(parser, current, NULL, 1,
4116
1.64M
                            njs_parser_logical_OR_expression_or);
4117
1.64M
}
4118
4119
4120
static njs_int_t
4121
njs_parser_logical_OR_expression_or(njs_parser_t *parser,
4122
    njs_lexer_token_t *token, njs_queue_link_t *current)
4123
1.54M
{
4124
1.54M
    njs_parser_next(parser, njs_parser_logical_AND_expression);
4125
4126
1.54M
    return njs_parser_expression_node(parser, token, current,
4127
1.54M
                                       NJS_TOKEN_LOGICAL_OR,
4128
1.54M
                                       NJS_VMCODE_TEST_IF_TRUE,
4129
1.54M
                                       njs_parser_logical_OR_expression_or);
4130
1.54M
}
4131
4132
4133
static njs_int_t
4134
njs_parser_coalesce_expression(njs_parser_t *parser, njs_lexer_token_t *token,
4135
    njs_queue_link_t *current)
4136
1.54M
{
4137
1.54M
    njs_token_type_t   type;
4138
1.54M
    njs_parser_node_t  *node;
4139
4140
1.54M
    node = parser->node;
4141
4142
1.54M
    if (parser->target != NULL) {
4143
522
        parser->target->right = node;
4144
522
        parser->target->right->dest = parser->target;
4145
522
        parser->node = parser->target;
4146
522
    }
4147
4148
1.54M
    if (token->type != NJS_TOKEN_COALESCE) {
4149
1.54M
        return njs_parser_stack_pop(parser);
4150
1.54M
    }
4151
4152
522
    type = node->token_type;
4153
4154
522
    if (parser->lexer->prev_type != NJS_TOKEN_CLOSE_PARENTHESIS
4155
522
        && (type == NJS_TOKEN_LOGICAL_OR || type == NJS_TOKEN_LOGICAL_AND))
4156
0
    {
4157
0
        return njs_parser_failed(parser);
4158
0
    }
4159
4160
522
    node = njs_parser_node_new(parser, NJS_TOKEN_COALESCE);
4161
522
    if (node == NULL) {
4162
0
        return NJS_ERROR;
4163
0
    }
4164
4165
522
    node->token_line = token->line;
4166
522
    node->u.operation = NJS_VMCODE_COALESCE;
4167
522
    node->left = parser->node;
4168
522
    node->left->dest = node;
4169
4170
522
    njs_lexer_consume_token(parser->lexer, 1);
4171
522
    njs_parser_next(parser, njs_parser_bitwise_OR_expression);
4172
4173
522
    return njs_parser_after(parser, current, node, 1,
4174
522
                            njs_parser_coalesce_expression);
4175
522
}
4176
4177
4178
static njs_int_t
4179
njs_parser_short_circuit_expression(njs_parser_t *parser,
4180
    njs_lexer_token_t *token, njs_queue_link_t *current)
4181
1.64M
{
4182
1.64M
    njs_parser_next(parser, njs_parser_logical_OR_expression);
4183
4184
1.64M
    return njs_parser_after(parser, current, NULL, 1,
4185
1.64M
                            njs_parser_coalesce_expression);
4186
1.64M
}
4187
4188
4189
/*
4190
 * 12.14 Conditional Operator ( ? : ).
4191
 */
4192
static njs_int_t
4193
njs_parser_conditional_expression(njs_parser_t *parser,
4194
    njs_lexer_token_t *token, njs_queue_link_t *current)
4195
1.64M
{
4196
1.64M
    njs_parser_next(parser, njs_parser_short_circuit_expression);
4197
4198
1.64M
    return njs_parser_after(parser, current, NULL, 1,
4199
1.64M
                            njs_parser_conditional_question_mark);
4200
1.64M
}
4201
4202
4203
static njs_int_t
4204
njs_parser_conditional_question_mark(njs_parser_t *parser,
4205
    njs_lexer_token_t *token, njs_queue_link_t *current)
4206
1.54M
{
4207
1.54M
    njs_parser_node_t  *node, *cond;
4208
4209
1.54M
    if (token->type != NJS_TOKEN_CONDITIONAL) {
4210
1.54M
        return njs_parser_stack_pop(parser);
4211
1.54M
    }
4212
4213
836
    cond = njs_parser_node_new(parser, NJS_TOKEN_CONDITIONAL);
4214
836
    if (cond == NULL) {
4215
0
        return NJS_ERROR;
4216
0
    }
4217
4218
836
    cond->token_line = token->line;
4219
836
    cond->left = parser->node;
4220
4221
836
    node = njs_parser_node_new(parser, NJS_TOKEN_BRANCHING);
4222
836
    if (node == NULL) {
4223
0
        return NJS_ERROR;
4224
0
    }
4225
4226
836
    node->token_line = token->line;
4227
836
    cond->right = node;
4228
4229
836
    njs_lexer_consume_token(parser->lexer, 1);
4230
4231
836
    if (njs_lexer_in_stack_push(parser->lexer) != NJS_OK) {
4232
0
        return NJS_ERROR;
4233
0
    }
4234
4235
836
    njs_parser_next(parser, njs_parser_assignment_expression);
4236
4237
836
    return njs_parser_after(parser, current, cond, 1,
4238
836
                            njs_parser_conditional_colon);
4239
836
}
4240
4241
4242
static njs_int_t
4243
njs_parser_conditional_colon(njs_parser_t *parser, njs_lexer_token_t *token,
4244
    njs_queue_link_t *current)
4245
4
{
4246
4
    njs_parser_node_t  *node;
4247
4248
4
    if (token->type != NJS_TOKEN_COLON) {
4249
0
        return njs_parser_failed(parser);
4250
0
    }
4251
4252
4
    njs_lexer_in_stack_pop(parser->lexer);
4253
4254
4
    njs_lexer_consume_token(parser->lexer, 1);
4255
4256
4
    node = parser->target->right;
4257
4258
4
    node->left = parser->node;
4259
4
    node->left->dest = parser->target;
4260
4261
4
    njs_parser_next(parser, njs_parser_assignment_expression);
4262
4263
4
    return njs_parser_after(parser, current, parser->target, 1,
4264
4
                            njs_parser_conditional_colon_after);
4265
4
}
4266
4267
4268
static njs_int_t
4269
njs_parser_conditional_colon_after(njs_parser_t *parser,
4270
    njs_lexer_token_t *token, njs_queue_link_t *current)
4271
4
{
4272
4
    njs_parser_node_t  *node;
4273
4274
4
    node = parser->target->right;
4275
4276
4
    node->right = parser->node;
4277
4
    node->right->dest = parser->target;
4278
4279
4
    parser->node = parser->target;
4280
4281
4
    return njs_parser_stack_pop(parser);
4282
4
}
4283
4284
4285
/*
4286
 * 12.15 Assignment Operators.
4287
 */
4288
static njs_int_t
4289
njs_parser_assignment_expression(njs_parser_t *parser,
4290
    njs_lexer_token_t *token, njs_queue_link_t *current)
4291
1.67M
{
4292
1.67M
    njs_int_t  ret;
4293
4294
1.67M
    if (!parser->use_lhs) {
4295
1.66M
        ret = njs_parser_match_arrow_expression(parser, token);
4296
1.66M
        if (ret == NJS_OK) {
4297
35.2k
            njs_parser_next(parser, njs_parser_arrow_function);
4298
4299
35.2k
            return NJS_OK;
4300
4301
1.63M
        } else if (ret == NJS_ERROR) {
4302
0
            return NJS_ERROR;
4303
0
        }
4304
1.66M
    }
4305
4306
1.64M
    njs_parser_next(parser, njs_parser_conditional_expression);
4307
4308
1.64M
    return njs_parser_after(parser, current, NULL, 1,
4309
1.67M
                            njs_parser_assignment_expression_after);
4310
1.67M
}
4311
4312
4313
/*
4314
 * TODO: this function is a crutch.
4315
 * See NJS_TOKEN_OPEN_PARENTHESIS in njs_parser_primary_expression_test.
4316
 * and look CoverParenthesizedExpressionAndArrowParameterList in spec.
4317
 */
4318
static njs_int_t
4319
njs_parser_match_arrow_expression(njs_parser_t *parser,
4320
    njs_lexer_token_t *token)
4321
1.67M
{
4322
1.67M
    njs_bool_t  rest_parameters;
4323
4324
1.67M
    if (token->type == NJS_TOKEN_ASYNC) {
4325
369
        token = njs_lexer_peek_token(parser->lexer, token, 1);
4326
369
        if (token == NULL) {
4327
0
            return NJS_ERROR;
4328
0
        }
4329
369
    }
4330
4331
1.67M
    if (token->type != NJS_TOKEN_OPEN_PARENTHESIS
4332
1.67M
        && !njs_lexer_token_is_binding_identifier(token))
4333
1.14M
    {
4334
1.14M
        return NJS_DECLINED;
4335
1.14M
    }
4336
4337
530k
    if (njs_lexer_token_is_binding_identifier(token)) {
4338
477k
        goto arrow;
4339
477k
    }
4340
4341
53.0k
    token = njs_lexer_peek_token(parser->lexer, token, 0);
4342
53.0k
    if (token == NULL) {
4343
0
        return NJS_ERROR;
4344
0
    }
4345
4346
53.0k
    rest_parameters = 0;
4347
4348
55.2k
    while (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) {
4349
4350
54.9k
        if (rest_parameters) {
4351
0
            return NJS_DECLINED;
4352
0
        }
4353
4354
54.9k
        if (token->type == NJS_TOKEN_ELLIPSIS) {
4355
0
            rest_parameters = 1;
4356
4357
0
            token = njs_lexer_peek_token(parser->lexer, token, 0);
4358
0
            if (token == NULL) {
4359
0
                return NJS_ERROR;
4360
0
            }
4361
0
        }
4362
4363
54.9k
        if (!njs_lexer_token_is_binding_identifier(token)) {
4364
52.7k
            return NJS_DECLINED;
4365
52.7k
        }
4366
4367
2.22k
        token = njs_lexer_peek_token(parser->lexer, token, 0);
4368
2.22k
        if (token == NULL) {
4369
0
            return NJS_ERROR;
4370
0
        }
4371
4372
2.22k
        if (token->type == NJS_TOKEN_COMMA) {
4373
502
            token = njs_lexer_peek_token(parser->lexer, token, 0);
4374
502
            if (token == NULL) {
4375
0
               return NJS_ERROR;
4376
0
            }
4377
502
        }
4378
2.22k
    }
4379
4380
477k
arrow:
4381
4382
477k
    token = njs_lexer_peek_token(parser->lexer, token, 1);
4383
477k
    if (token == NULL) {
4384
0
        return NJS_ERROR;
4385
0
    }
4386
4387
477k
    if (token->type == NJS_TOKEN_LINE_END) {
4388
205k
        return NJS_DECLINED;
4389
205k
    }
4390
4391
272k
    if (token->type != NJS_TOKEN_ARROW) {
4392
237k
        return NJS_DECLINED;
4393
237k
    }
4394
4395
35.2k
    return NJS_OK;
4396
272k
}
4397
4398
4399
static njs_int_t
4400
njs_parser_assignment_expression_after(njs_parser_t *parser,
4401
    njs_lexer_token_t *token, njs_queue_link_t *current)
4402
1.54M
{
4403
1.54M
    return njs_parser_assignment_operator(parser, token, current);
4404
1.54M
}
4405
4406
4407
static njs_int_t
4408
njs_parser_assignment_operator(njs_parser_t *parser, njs_lexer_token_t *token,
4409
    njs_queue_link_t *current)
4410
1.54M
{
4411
1.54M
    njs_vmcode_t       operation;
4412
1.54M
    njs_token_type_t   type;
4413
1.54M
    njs_parser_node_t  *node;
4414
4415
1.54M
    switch (token->type) {
4416
50.1k
    case NJS_TOKEN_ASSIGNMENT:
4417
50.1k
        njs_thread_log_debug("JS: =");
4418
50.1k
        operation = NJS_VMCODE_MOVE;
4419
50.1k
        break;
4420
4421
2.01k
    case NJS_TOKEN_MULTIPLICATION_ASSIGNMENT:
4422
2.01k
        njs_thread_log_debug("JS: *=");
4423
2.01k
        operation = NJS_VMCODE_MULTIPLICATION;
4424
2.01k
        break;
4425
4426
1.39k
    case NJS_TOKEN_DIVISION_ASSIGNMENT:
4427
1.39k
        njs_thread_log_debug("JS: /=");
4428
1.39k
        operation = NJS_VMCODE_DIVISION;
4429
1.39k
        break;
4430
4431
80
    case NJS_TOKEN_REMAINDER_ASSIGNMENT:
4432
80
        njs_thread_log_debug("JS: %=");
4433
80
        operation = NJS_VMCODE_REMAINDER;
4434
80
        break;
4435
4436
11.5k
    case NJS_TOKEN_ADDITION_ASSIGNMENT:
4437
11.5k
        njs_thread_log_debug("JS: +=");
4438
11.5k
        operation = NJS_VMCODE_ADDITION;
4439
11.5k
        break;
4440
4441
317
    case NJS_TOKEN_SUBTRACTION_ASSIGNMENT:
4442
317
        njs_thread_log_debug("JS: -=");
4443
317
        operation = NJS_VMCODE_SUBTRACTION;
4444
317
        break;
4445
4446
0
    case NJS_TOKEN_LEFT_SHIFT_ASSIGNMENT:
4447
0
        njs_thread_log_debug("JS: <<=");
4448
0
        operation = NJS_VMCODE_LEFT_SHIFT;
4449
0
        break;
4450
4451
514
    case NJS_TOKEN_RIGHT_SHIFT_ASSIGNMENT:
4452
514
        njs_thread_log_debug("JS: >>=");
4453
514
        operation = NJS_VMCODE_RIGHT_SHIFT;
4454
514
        break;
4455
4456
0
    case NJS_TOKEN_UNSIGNED_RIGHT_SHIFT_ASSIGNMENT:
4457
0
        njs_thread_log_debug("JS: >>>=");
4458
0
        operation = NJS_VMCODE_UNSIGNED_RIGHT_SHIFT;
4459
0
        break;
4460
4461
535
    case NJS_TOKEN_BITWISE_AND_ASSIGNMENT:
4462
535
        njs_thread_log_debug("JS: &=");
4463
535
        operation = NJS_VMCODE_BITWISE_AND;
4464
535
        break;
4465
4466
0
    case NJS_TOKEN_BITWISE_XOR_ASSIGNMENT:
4467
0
        njs_thread_log_debug("JS: ^=");
4468
0
        operation = NJS_VMCODE_BITWISE_XOR;
4469
0
        break;
4470
4471
16.5k
    case NJS_TOKEN_BITWISE_OR_ASSIGNMENT:
4472
16.5k
        njs_thread_log_debug("JS: |=");
4473
16.5k
        operation = NJS_VMCODE_BITWISE_OR;
4474
16.5k
        break;
4475
4476
0
    case NJS_TOKEN_EXPONENTIATION_ASSIGNMENT:
4477
0
        njs_thread_log_debug("JS: **=");
4478
0
        operation = NJS_VMCODE_EXPONENTIATION;
4479
0
        break;
4480
4481
1.45M
    default:
4482
1.45M
        return njs_parser_stack_pop(parser);
4483
1.54M
    }
4484
4485
83.1k
    if (!njs_parser_is_lvalue(parser->node)) {
4486
0
        type = parser->node->token_type;
4487
4488
0
        if (njs_parser_restricted_identifier(type)) {
4489
0
            njs_parser_syntax_error(parser, "Identifier \"%s\" "
4490
0
                                    "is forbidden as left-hand in assignment",
4491
0
                                    (type == NJS_TOKEN_EVAL) ? "eval"
4492
0
                                                             : "arguments");
4493
4494
0
        } else {
4495
0
            njs_parser_ref_error(parser,
4496
0
                                 "Invalid left-hand side in assignment");
4497
0
        }
4498
4499
0
        return NJS_DONE;
4500
0
    }
4501
4502
83.1k
    node = njs_parser_node_new(parser, token->type);
4503
83.1k
    if (node == NULL) {
4504
0
        return NJS_ERROR;
4505
0
    }
4506
4507
83.1k
    node->token_line = token->line;
4508
83.1k
    node->u.operation = operation;
4509
83.1k
    node->left = parser->node;
4510
4511
83.1k
    njs_lexer_consume_token(parser->lexer, 1);
4512
83.1k
    njs_parser_next(parser, njs_parser_assignment_expression);
4513
4514
83.1k
    return njs_parser_after(parser, current, node, 1,
4515
83.1k
                            njs_parser_assignment_operator_after);
4516
83.1k
}
4517
4518
4519
static njs_int_t
4520
njs_parser_assignment_operator_after(njs_parser_t *parser,
4521
    njs_lexer_token_t *token, njs_queue_link_t *current)
4522
82.0k
{
4523
82.0k
    parser->target->right = parser->node;
4524
82.0k
    parser->node = parser->target;
4525
4526
82.0k
    return njs_parser_stack_pop(parser);
4527
82.0k
}
4528
4529
4530
/*
4531
 * 12.16 Comma Operator ( , ).
4532
 */
4533
static njs_int_t
4534
njs_parser_expression(njs_parser_t *parser, njs_lexer_token_t *token,
4535
    njs_queue_link_t *current)
4536
485k
{
4537
485k
    njs_parser_next(parser, njs_parser_assignment_expression);
4538
4539
485k
    return njs_parser_after(parser, current, NULL, 1,
4540
485k
                            njs_parser_expression_comma);
4541
485k
}
4542
4543
4544
static njs_int_t
4545
njs_parser_expression_comma(njs_parser_t *parser, njs_lexer_token_t *token,
4546
    njs_queue_link_t *current)
4547
407k
{
4548
407k
    njs_parser_next(parser, njs_parser_assignment_expression);
4549
4550
407k
    return njs_parser_expression_node(parser, token, current, NJS_TOKEN_COMMA,
4551
407k
                                       0,
4552
407k
                                       njs_parser_expression_comma);
4553
407k
}
4554
4555
4556
/*
4557
 * 13 Statements and Declarations.
4558
 */
4559
static njs_int_t
4560
njs_parser_statement(njs_parser_t *parser, njs_lexer_token_t *token,
4561
    njs_queue_link_t *current)
4562
496k
{
4563
496k
    njs_int_t                 ret;
4564
496k
    njs_queue_link_t          *lnk;
4565
496k
    njs_parser_stack_entry_t  *entry;
4566
4567
496k
    if (token->type == NJS_TOKEN_END) {
4568
14.2k
        lnk = njs_queue_next(njs_queue_first(&parser->stack));
4569
4570
14.2k
        if (lnk == njs_queue_head(&parser->stack)) {
4571
0
            return njs_parser_reject(parser);
4572
0
        }
4573
4574
14.2k
        entry = njs_queue_link_data(lnk, njs_parser_stack_entry_t, link);
4575
4576
14.2k
        if (entry->state == njs_parser_check_error_state) {
4577
14.2k
            return NJS_DONE;
4578
14.2k
        }
4579
4580
6
        return njs_parser_reject(parser);
4581
14.2k
    }
4582
4583
482k
    switch (token->type) {
4584
21.1k
    case NJS_TOKEN_SEMICOLON:
4585
21.1k
        njs_lexer_consume_token(parser->lexer, 1);
4586
21.1k
        return njs_parser_stack_pop(parser);
4587
4588
0
    case NJS_TOKEN_EXPORT:
4589
0
        parser->line = token->line;
4590
4591
0
        njs_lexer_consume_token(parser->lexer, 1);
4592
0
        njs_parser_next(parser, njs_parser_export);
4593
4594
0
        return njs_parser_after(parser, current, parser->node, 1,
4595
0
                                njs_parser_statement_after);
4596
4597
259
    case NJS_TOKEN_IMPORT:
4598
259
        parser->line = token->line;
4599
4600
259
        njs_lexer_consume_token(parser->lexer, 1);
4601
259
        njs_parser_next(parser, njs_parser_import);
4602
4603
259
        return njs_parser_after(parser, current, parser->node, 1,
4604
0
                                njs_parser_statement_after);
4605
460k
    default:
4606
460k
        break;
4607
482k
    }
4608
4609
460k
    ret = njs_parser_statement_wo_node(parser, token, current);
4610
460k
    if (ret != NJS_OK) {
4611
0
        return ret;
4612
0
    }
4613
4614
460k
    return njs_parser_after(parser, current, parser->node, 1,
4615
460k
                            njs_parser_statement_after);
4616
460k
}
4617
4618
4619
static njs_int_t
4620
njs_parser_statement_wo_node(njs_parser_t *parser, njs_lexer_token_t *token,
4621
    njs_queue_link_t *current)
4622
511k
{
4623
511k
    switch (token->type) {
4624
51.8k
    case NJS_TOKEN_OPEN_BRACE:
4625
51.8k
        njs_parser_next(parser, njs_parser_block_statement);
4626
51.8k
        break;
4627
4628
3.21k
    case NJS_TOKEN_VAR:
4629
3.21k
        njs_lexer_consume_token(parser->lexer, 1);
4630
3.21k
        return njs_parser_variable_statement(parser, token, current);
4631
4632
703
    case NJS_TOKEN_SEMICOLON:
4633
703
        njs_lexer_consume_token(parser->lexer, 1);
4634
703
        return njs_parser_stack_pop(parser);
4635
4636
1.59k
    case NJS_TOKEN_IF:
4637
1.59k
        njs_parser_next(parser, njs_parser_if_statement);
4638
1.59k
        break;
4639
4640
    /* BreakableStatement */
4641
2.70k
    case NJS_TOKEN_DO:
4642
2.70k
        njs_parser_next(parser, njs_parser_iteration_statement_do);
4643
2.70k
        break;
4644
4645
3.47k
    case NJS_TOKEN_WHILE:
4646
3.47k
        njs_parser_next(parser, njs_parser_iteration_statement_while);
4647
3.47k
        break;
4648
4649
29.6k
    case NJS_TOKEN_FOR:
4650
29.6k
        njs_parser_next(parser, njs_parser_iteration_statement_for);
4651
29.6k
        break;
4652
4653
109
    case NJS_TOKEN_SWITCH:
4654
109
        njs_parser_next(parser, njs_parser_switch_statement);
4655
109
        break;
4656
4657
2.19k
    case NJS_TOKEN_CONTINUE:
4658
2.19k
        njs_parser_next(parser, njs_parser_continue_statement);
4659
2.19k
        break;
4660
4661
6.25k
    case NJS_TOKEN_BREAK:
4662
6.25k
        njs_parser_next(parser, njs_parser_break_statement);
4663
6.25k
        break;
4664
4665
7.67k
    case NJS_TOKEN_RETURN:
4666
7.67k
        njs_parser_next(parser, njs_parser_return_statement);
4667
7.67k
        break;
4668
4669
0
    case NJS_TOKEN_WITH:
4670
0
        njs_parser_next(parser, njs_parser_with_statement);
4671
0
        break;
4672
4673
110
    case NJS_TOKEN_THROW:
4674
110
        njs_parser_next(parser, njs_parser_throw_statement);
4675
110
        break;
4676
4677
13.1k
    case NJS_TOKEN_TRY:
4678
13.1k
        njs_parser_next(parser, njs_parser_try_statement);
4679
13.1k
        break;
4680
4681
514
    case NJS_TOKEN_DEBUGGER:
4682
514
        njs_parser_next(parser, njs_parser_debugger_statement);
4683
514
        break;
4684
4685
0
    case NJS_TOKEN_END:
4686
0
        return njs_parser_failed(parser);
4687
4688
388k
    default:
4689
388k
        if (njs_lexer_token_is_identifier_reference(token)) {
4690
305k
            token = njs_lexer_peek_token(parser->lexer, token, 0);
4691
305k
            if (token == NULL) {
4692
0
                return NJS_ERROR;
4693
0
            }
4694
4695
305k
            if (token->type == NJS_TOKEN_COLON) {
4696
19.3k
                njs_parser_next(parser, njs_parser_labelled_statement);
4697
19.3k
                return NJS_OK;
4698
19.3k
            }
4699
305k
        }
4700
4701
369k
        njs_parser_next(parser, njs_parser_expression_statement);
4702
369k
        return NJS_OK;
4703
511k
    }
4704
4705
119k
    parser->line = token->line;
4706
4707
119k
    njs_lexer_consume_token(parser->lexer, 1);
4708
4709
119k
    return NJS_OK;
4710
511k
}
4711
4712
4713
static njs_int_t
4714
njs_parser_statement_after(njs_parser_t *parser, njs_lexer_token_t *token,
4715
    njs_queue_link_t *current)
4716
373k
{
4717
373k
    njs_parser_node_t  *stmt, *last, *new_node, **child;
4718
373k
    njs_parser_node_t  *node, *top;
4719
4720
373k
    child = &parser->target;
4721
373k
    last = *child;
4722
4723
373k
    new_node = parser->node;
4724
4725
373k
    if (new_node != NULL) {
4726
373k
        if (new_node->hoist) {
4727
0
            child = &njs_parser_chain_top(parser);
4728
4729
0
            while (*child != NULL) {
4730
0
                node = *child;
4731
4732
0
                if (node->hoist) {
4733
0
                    break;
4734
0
                }
4735
4736
0
                child = &node->left;
4737
0
            }
4738
4739
0
            last = *child;
4740
0
        }
4741
4742
373k
        stmt = njs_parser_node_new(parser, NJS_TOKEN_STATEMENT);
4743
373k
        if (njs_slow_path(stmt == NULL)) {
4744
0
            return NJS_ERROR;
4745
0
        }
4746
4747
373k
        stmt->hoist = new_node->hoist;
4748
373k
        stmt->left = last;
4749
373k
        stmt->right = new_node;
4750
4751
373k
        *child = stmt;
4752
4753
373k
        top = (child != &parser->target) ? njs_parser_chain_top(parser)
4754
373k
                                         : stmt;
4755
4756
373k
        parser->node = top;
4757
4758
373k
       njs_parser_chain_top_set(parser, top);
4759
373k
    }
4760
4761
373k
    return njs_parser_stack_pop(parser);
4762
373k
}
4763
4764
4765
static njs_int_t
4766
njs_parser_declaration(njs_parser_t *parser, njs_lexer_token_t *token,
4767
    njs_queue_link_t *current)
4768
510k
{
4769
510k
    njs_int_t  ret;
4770
4771
510k
    ret = njs_parser_hoistable_declaration(parser, token, current);
4772
510k
    if (ret == NJS_OK) {
4773
6.08k
        return NJS_OK;
4774
6.08k
    }
4775
4776
504k
    switch (token->type) {
4777
0
    case NJS_TOKEN_CLASS:
4778
0
        njs_parser_next(parser, njs_parser_class_declaration);
4779
0
        return NJS_OK;
4780
4781
5.80k
    case NJS_TOKEN_LET:
4782
8.40k
    case NJS_TOKEN_CONST:
4783
8.40k
        token = njs_lexer_peek_token(parser->lexer, token, 0);
4784
8.40k
        if (token == NULL) {
4785
0
            return NJS_ERROR;
4786
0
        }
4787
4788
8.40k
        switch (token->type) {
4789
591
        case NJS_TOKEN_OPEN_BRACE:
4790
591
        case NJS_TOKEN_OPEN_BRACKET:
4791
591
            njs_parser_next(parser, njs_parser_lexical_declaration);
4792
591
            break;
4793
4794
7.81k
        default:
4795
7.81k
            if (njs_lexer_token_is_reserved(token)) {
4796
0
                njs_lexer_consume_token(parser->lexer, 1);
4797
0
                njs_parser_next(parser, njs_parser_failed_state);
4798
0
                return NJS_OK;
4799
0
            }
4800
4801
7.81k
            if (njs_lexer_token_is_binding_identifier(token)) {
4802
7.81k
                njs_parser_next(parser, njs_parser_lexical_declaration);
4803
7.81k
                break;
4804
7.81k
            }
4805
4806
0
            return NJS_DECLINED;
4807
8.40k
        }
4808
4809
8.40k
        break;
4810
4811
496k
    default:
4812
496k
        return NJS_DECLINED;
4813
504k
    }
4814
4815
8.40k
    return njs_parser_after(parser, current, parser->node, 1,
4816
504k
                            njs_parser_statement_after);
4817
504k
}
4818
4819
4820
static njs_int_t
4821
njs_parser_hoistable_declaration(njs_parser_t *parser,
4822
    njs_lexer_token_t *token, njs_queue_link_t *current)
4823
510k
{
4824
510k
    njs_int_t  ret;
4825
4826
510k
    ret = njs_parser_function_or_generator(parser, token, current);
4827
510k
    if (ret == NJS_OK) {
4828
6.08k
        return NJS_OK;
4829
6.08k
    }
4830
4831
504k
    ret = njs_parser_async_function_or_generator(parser, token, current);
4832
504k
    if (ret == NJS_OK) {
4833
0
        return NJS_OK;
4834
0
    }
4835
4836
504k
    return NJS_DECLINED;
4837
504k
}
4838
4839
4840
/*
4841
 * 13.2 Block.
4842
 */
4843
static njs_int_t
4844
njs_parser_block_statement(njs_parser_t *parser, njs_lexer_token_t *token,
4845
    njs_queue_link_t *current)
4846
65.0k
{
4847
65.0k
    void       *target;
4848
65.0k
    njs_int_t  ret;
4849
4850
65.0k
    ret = njs_parser_scope_begin(parser, NJS_SCOPE_BLOCK, 0);
4851
65.0k
    if (ret != NJS_OK) {
4852
0
        return NJS_ERROR;
4853
0
    }
4854
4855
65.0k
    target = (void *) (uintptr_t) parser->line;
4856
65.0k
    parser->node = NULL;
4857
4858
65.0k
    if (token->type == NJS_TOKEN_CLOSE_BRACE) {
4859
354
        parser->target = target;
4860
4861
354
        njs_parser_next(parser, njs_parser_block_statement_close_brace);
4862
354
        return NJS_OK;
4863
354
    }
4864
4865
64.6k
    njs_parser_next(parser, njs_parser_statement_list);
4866
4867
64.6k
    return njs_parser_after(parser, current, target, 0,
4868
65.0k
                            njs_parser_block_statement_close_brace);
4869
65.0k
}
4870
4871
4872
static njs_int_t
4873
njs_parser_block_statement_open_brace(njs_parser_t *parser,
4874
    njs_lexer_token_t *token, njs_queue_link_t *current)
4875
13.1k
{
4876
13.1k
    if (token->type != NJS_TOKEN_OPEN_BRACE) {
4877
0
        return njs_parser_failed(parser);
4878
0
    }
4879
4880
13.1k
    parser->line = token->line;
4881
4882
13.1k
    njs_lexer_consume_token(parser->lexer, 1);
4883
4884
13.1k
    token = njs_lexer_token(parser->lexer, 0);
4885
13.1k
    if (token == NULL) {
4886
0
        return NJS_ERROR;
4887
0
    }
4888
4889
13.1k
    return njs_parser_block_statement(parser, token, current);
4890
13.1k
}
4891
4892
4893
static njs_int_t
4894
njs_parser_block_statement_close_brace(njs_parser_t *parser,
4895
    njs_lexer_token_t *token, njs_queue_link_t *current)
4896
43.0k
{
4897
43.0k
    njs_parser_node_t  *node;
4898
4899
43.0k
    if (parser->ret != NJS_OK) {
4900
606
        return njs_parser_failed(parser);
4901
606
    }
4902
4903
42.4k
    if (token->type != NJS_TOKEN_CLOSE_BRACE) {
4904
0
        return njs_parser_failed(parser);
4905
0
    }
4906
4907
42.4k
    node = njs_parser_node_new(parser, NJS_TOKEN_BLOCK);
4908
42.4k
    if (node == NULL) {
4909
0
        return NJS_ERROR;
4910
0
    }
4911
4912
42.4k
    node->token_line = (uint32_t) (uintptr_t) parser->target;
4913
42.4k
    node->left = parser->node;
4914
42.4k
    node->right = NULL;
4915
4916
42.4k
    parser->target = NULL;
4917
42.4k
    parser->node = node;
4918
4919
42.4k
    njs_parser_scope_end(parser);
4920
4921
42.4k
    njs_lexer_consume_token(parser->lexer, 1);
4922
42.4k
    return njs_parser_stack_pop(parser);
4923
42.4k
}
4924
4925
4926
static njs_int_t
4927
njs_parser_statement_list(njs_parser_t *parser, njs_lexer_token_t *token,
4928
    njs_queue_link_t *current)
4929
179k
{
4930
179k
    njs_parser_next(parser, njs_parser_statement_list_item);
4931
4932
179k
    return njs_parser_after(parser, current, NULL, 1,
4933
179k
                            njs_parser_statement_list_next);
4934
179k
}
4935
4936
4937
static njs_int_t
4938
njs_parser_statement_list_next(njs_parser_t *parser, njs_lexer_token_t *token,
4939
    njs_queue_link_t *current)
4940
396k
{
4941
396k
    if (parser->ret != NJS_OK) {
4942
1.94k
        if (token->type != NJS_TOKEN_CLOSE_BRACE) {
4943
1.94k
            parser->node = parser->target;
4944
4945
1.94k
            (void) njs_parser_stack_pop(parser);
4946
4947
1.94k
            return parser->ret;
4948
1.94k
        }
4949
4950
0
        return njs_parser_failed(parser);
4951
1.94k
    }
4952
4953
395k
    if (token->type == NJS_TOKEN_CLOSE_BRACE) {
4954
63.6k
        return njs_parser_stack_pop(parser);
4955
63.6k
    }
4956
4957
331k
    njs_parser_next(parser, njs_parser_statement_list_item);
4958
4959
331k
    return njs_parser_after(parser, current, parser->node, 0,
4960
395k
                            njs_parser_statement_list_next);
4961
395k
}
4962
4963
4964
static njs_int_t
4965
njs_parser_statement_list_item(njs_parser_t *parser, njs_lexer_token_t *token,
4966
    njs_queue_link_t *current)
4967
510k
{
4968
510k
    njs_int_t  ret;
4969
4970
510k
    ret = njs_parser_declaration(parser, token, current);
4971
510k
    if (ret == NJS_OK) {
4972
14.4k
        return NJS_OK;
4973
14.4k
    }
4974
4975
496k
    njs_parser_next(parser, njs_parser_statement);
4976
4977
496k
    return NJS_OK;
4978
510k
}
4979
4980
4981
/*
4982
 * 13.3.1 Let and Const Declarations
4983
 */
4984
static njs_int_t
4985
njs_parser_lexical_declaration(njs_parser_t *parser, njs_lexer_token_t *token,
4986
    njs_queue_link_t *current)
4987
8.40k
{
4988
8.40k
    parser->var_type = (token->type == NJS_TOKEN_LET) ? NJS_VARIABLE_LET
4989
8.40k
                                                      : NJS_VARIABLE_CONST;
4990
4991
8.40k
    njs_lexer_consume_token(parser->lexer, 1);
4992
4993
8.40k
    njs_parser_next(parser, njs_parser_variable_declaration_list);
4994
4995
8.40k
    return njs_parser_after(parser, current, NULL, 1, njs_parser_semicolon);
4996
8.40k
}
4997
4998
4999
/*
5000
 * 13.3.2 Variable Statement
5001
 */
5002
static njs_int_t
5003
njs_parser_variable_statement(njs_parser_t *parser, njs_lexer_token_t *token,
5004
    njs_queue_link_t *current)
5005
3.21k
{
5006
3.21k
    parser->var_type = NJS_VARIABLE_VAR;
5007
5008
3.21k
    njs_parser_next(parser, njs_parser_variable_declaration_list);
5009
5010
3.21k
    return njs_parser_after(parser, current, NULL, 1, njs_parser_semicolon);
5011
3.21k
}
5012
5013
5014
static njs_int_t
5015
njs_parser_variable_declaration_list(njs_parser_t *parser,
5016
    njs_lexer_token_t *token, njs_queue_link_t *current)
5017
11.6k
{
5018
11.6k
    njs_parser_next(parser, njs_parser_variable_declaration);
5019
5020
11.6k
    return njs_parser_after(parser, current, NULL, 1,
5021
11.6k
                            njs_parser_variable_declaration_list_next);
5022
11.6k
}
5023
5024
5025
static njs_int_t
5026
njs_parser_variable_declaration_list_next(njs_parser_t *parser,
5027
    njs_lexer_token_t *token, njs_queue_link_t *current)
5028
13.1k
{
5029
13.1k
    njs_parser_node_t  *node;
5030
5031
13.1k
    if (parser->target != NULL) {
5032
2.14k
        parser->node->left = parser->target;
5033
2.14k
    }
5034
5035
13.1k
    if (token->type != NJS_TOKEN_COMMA) {
5036
11.0k
        return njs_parser_stack_pop(parser);
5037
11.0k
    }
5038
5039
2.14k
    njs_lexer_consume_token(parser->lexer, 1);
5040
5041
2.14k
    node = parser->node;
5042
5043
2.14k
    parser->node = NULL;
5044
5045
2.14k
    njs_parser_next(parser, njs_parser_variable_declaration);
5046
5047
2.14k
    return njs_parser_after(parser, current, node, 1,
5048
13.1k
                            njs_parser_variable_declaration_list_next);
5049
13.1k
}
5050
5051
5052
static njs_int_t
5053
njs_parser_variable_declaration(njs_parser_t *parser,
5054
    njs_lexer_token_t *token, njs_queue_link_t *current)
5055
13.7k
{
5056
13.7k
    njs_int_t          ret;
5057
13.7k
    njs_variable_t     *var;
5058
13.7k
    njs_token_type_t   type;
5059
13.7k
    njs_parser_node_t  *name;
5060
5061
13.7k
    ret = njs_parser_binding_pattern(parser, token, current);
5062
13.7k
    if (ret == NJS_OK) {
5063
591
        return njs_parser_after(parser, current, NULL, 1,
5064
591
                                njs_parser_initializer);
5065
591
    }
5066
5067
13.1k
    if (!njs_lexer_token_is_binding_identifier(token)) {
5068
0
        return njs_parser_failed(parser);
5069
0
    }
5070
5071
13.1k
    if (njs_parser_restricted_identifier(token->type)) {
5072
0
        njs_parser_syntax_error(parser, "Identifier \"%V\" is forbidden in"
5073
0
                                " var declaration", &token->text);
5074
0
        return NJS_DONE;
5075
0
    }
5076
5077
13.1k
    name = njs_parser_variable_node(parser, token->unique_id, parser->var_type,
5078
13.1k
                                    &var);
5079
13.1k
    if (name == NULL) {
5080
0
        return NJS_ERROR;
5081
0
    }
5082
5083
13.1k
    if (var->self) {
5084
236
        var->type = parser->var_type;
5085
236
        var->self = 0;
5086
236
    }
5087
5088
13.1k
    name->token_line = token->line;
5089
5090
13.1k
    parser->node = name;
5091
5092
13.1k
    njs_lexer_consume_token(parser->lexer, 1);
5093
5094
13.1k
    token = njs_lexer_token(parser->lexer, 0);
5095
13.1k
    if (token == NULL) {
5096
0
        return NJS_ERROR;
5097
0
    }
5098
5099
13.1k
    switch (parser->var_type) {
5100
5.80k
    case NJS_VARIABLE_LET:
5101
5.80k
        type = NJS_TOKEN_LET;
5102
5.80k
        break;
5103
5104
3.39k
    case NJS_VARIABLE_CONST:
5105
3.39k
        type = NJS_TOKEN_CONST;
5106
3.39k
        break;
5107
5108
3.97k
    default:
5109
3.97k
        type = NJS_TOKEN_VAR;
5110
3.97k
        break;
5111
13.1k
    }
5112
5113
13.1k
    ret = njs_parser_initializer_assign(parser, type);
5114
13.1k
    if (ret != NJS_OK) {
5115
0
        return ret;
5116
0
    }
5117
5118
13.1k
    parser->node->token_line = token->line;
5119
5120
13.1k
    if (token->type == NJS_TOKEN_ASSIGNMENT) {
5121
5.42k
        njs_parser_next(parser, njs_parser_initializer);
5122
5123
5.42k
        return NJS_OK;
5124
5.42k
    }
5125
5126
7.74k
    parser->target = parser->node;
5127
7.74k
    parser->node = NULL;
5128
5129
7.74k
    njs_parser_next(parser, njs_parser_initializer_after);
5130
5131
7.74k
    return NJS_OK;
5132
13.1k
}
5133
5134
5135
/*
5136
 * 13.3.3 Destructuring Binding Patterns.
5137
 */
5138
static njs_int_t
5139
njs_parser_binding_pattern(njs_parser_t *parser, njs_lexer_token_t *token,
5140
    njs_queue_link_t *current)
5141
13.7k
{
5142
13.7k
    if (token->type == NJS_TOKEN_OPEN_BRACE) {
5143
591
        njs_parser_next(parser, njs_parser_object_binding_pattern);
5144
5145
13.1k
    } else if (token->type == NJS_TOKEN_OPEN_BRACKET) {
5146
0
        njs_parser_next(parser, njs_parser_array_binding_pattern);
5147
5148
13.1k
    } else {
5149
13.1k
        return NJS_DECLINED;
5150
13.1k
    }
5151
5152
591
    njs_lexer_consume_token(parser->lexer, 1);
5153
5154
591
    return NJS_OK;
5155
13.7k
}
5156
5157
static njs_int_t
5158
njs_parser_object_binding_pattern(njs_parser_t *parser,
5159
    njs_lexer_token_t *token, njs_queue_link_t *current)
5160
591
{
5161
591
    return njs_parser_not_supported(parser, token);
5162
591
}
5163
5164
5165
static njs_int_t
5166
njs_parser_array_binding_pattern(njs_parser_t *parser,
5167
    njs_lexer_token_t *token, njs_queue_link_t *current)
5168
0
{
5169
0
    return njs_parser_not_supported(parser, token);
5170
0
}
5171
5172
5173
/*
5174
 * 13.5 Expression Statement.
5175
 */
5176
static njs_int_t
5177
njs_parser_expression_statement(njs_parser_t *parser, njs_lexer_token_t *token,
5178
    njs_queue_link_t *current)
5179
369k
{
5180
369k
    njs_token_type_t   type;
5181
369k
    njs_lexer_token_t  *next;
5182
5183
369k
    switch (token->type) {
5184
925
    case NJS_TOKEN_FUNCTION:
5185
925
        njs_parser_syntax_error(parser, "Functions can only be declared "
5186
925
                                        "at top level or inside a block");
5187
925
        return NJS_DONE;
5188
5189
0
    case NJS_TOKEN_CLASS:
5190
0
        njs_parser_syntax_error(parser, "Class can only be declared "
5191
0
                                        "at top level or inside a block");
5192
0
        return NJS_DONE;
5193
5194
0
    case NJS_TOKEN_OPEN_BRACE:
5195
0
        return njs_parser_reject(parser);
5196
5197
0
    case NJS_TOKEN_ASYNC:
5198
0
        next = njs_lexer_peek_token(parser->lexer, token, 1);
5199
0
        if (next == NULL) {
5200
0
            return NJS_ERROR;
5201
0
        }
5202
5203
0
        if (next->type == NJS_TOKEN_FUNCTION) {
5204
0
            return njs_parser_not_supported(parser, token);
5205
0
        }
5206
5207
0
        break;
5208
5209
0
    case NJS_TOKEN_CONST:
5210
0
    case NJS_TOKEN_LET:
5211
0
        type = token->type;
5212
5213
0
        token = njs_lexer_peek_token(parser->lexer, token, 0);
5214
0
        if (token == NULL) {
5215
0
            return NJS_ERROR;
5216
0
        }
5217
5218
0
        if (token->type == NJS_TOKEN_NAME) {
5219
0
            njs_parser_syntax_error(parser, "%s declaration cannot appear "
5220
0
                                    "in a single-statement context",
5221
0
                                    (type == NJS_TOKEN_CONST ? "const"
5222
0
                                                             : "let" ));
5223
0
            return NJS_DONE;
5224
0
        }
5225
5226
0
        if (token->type == NJS_TOKEN_OPEN_BRACKET) {
5227
0
            return njs_parser_failed(parser);
5228
0
        }
5229
5230
0
        break;
5231
5232
368k
    default:
5233
368k
        break;
5234
369k
    }
5235
5236
368k
    parser->node = NULL;
5237
5238
368k
    njs_parser_next(parser, njs_parser_expression);
5239
5240
368k
    return njs_parser_after(parser, current, NULL, 1,
5241
369k
                            njs_parser_expression_statement_after);
5242
369k
}
5243
5244
5245
static njs_int_t
5246
njs_parser_expression_statement_after(njs_parser_t *parser,
5247
    njs_lexer_token_t *token, njs_queue_link_t *current)
5248
316k
{
5249
316k
    if (njs_parser_expect_semicolon(parser, token) != NJS_OK) {
5250
2.39k
        return njs_parser_failed(parser);
5251
2.39k
    }
5252
5253
314k
    return njs_parser_stack_pop(parser);
5254
316k
}
5255
5256
5257
/*
5258
 * 13.6 if Statement.
5259
 */
5260
static njs_int_t
5261
njs_parser_if_statement(njs_parser_t *parser, njs_lexer_token_t *token,
5262
    njs_queue_link_t *current)
5263
1.59k
{
5264
1.59k
    njs_int_t          ret;
5265
1.59k
    njs_parser_node_t  *node;
5266
5267
1.59k
    if (token->type != NJS_TOKEN_OPEN_PARENTHESIS) {
5268
0
        return njs_parser_failed(parser);
5269
0
    }
5270
5271
1.59k
    njs_lexer_consume_token(parser->lexer, 1);
5272
5273
1.59k
    node = njs_parser_node_new(parser, NJS_TOKEN_IF);
5274
1.59k
    if (node == NULL) {
5275
0
        return NJS_ERROR;
5276
0
    }
5277
5278
1.59k
    node->token_line = parser->line;
5279
5280
1.59k
    parser->node = NULL;
5281
5282
1.59k
    njs_parser_next(parser, njs_parser_expression);
5283
5284
1.59k
    ret = njs_parser_after(parser, current, node, 1,
5285
1.59k
                           njs_parser_if_close_parenthesis);
5286
1.59k
    if (ret != NJS_OK) {
5287
0
        return ret;
5288
0
    }
5289
5290
1.59k
    ret = njs_parser_after(parser, current, NULL, 1,
5291
1.59k
                           njs_parser_statement_wo_node);
5292
1.59k
    if (ret != NJS_OK) {
5293
0
        return ret;
5294
0
    }
5295
5296
1.59k
    return njs_parser_after(parser, current, node, 1,
5297
1.59k
                            njs_parser_else_statement);
5298
1.59k
}
5299
5300
5301
static njs_int_t
5302
njs_parser_if_close_parenthesis(njs_parser_t *parser, njs_lexer_token_t *token,
5303
    njs_queue_link_t *current)
5304
1.59k
{
5305
1.59k
    if (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) {
5306
523
        return njs_parser_failed(parser);
5307
523
    }
5308
5309
1.07k
    njs_lexer_consume_token(parser->lexer, 1);
5310
5311
1.07k
    parser->target->left = parser->node;
5312
1.07k
    parser->node = NULL;
5313
5314
1.07k
    return njs_parser_stack_pop(parser);
5315
1.59k
}
5316
5317
5318
static njs_int_t
5319
njs_parser_else_statement(njs_parser_t *parser, njs_lexer_token_t *token,
5320
    njs_queue_link_t *current)
5321
1.07k
{
5322
1.07k
    njs_parser_node_t  *node;
5323
5324
1.07k
    parser->target->right = parser->node;
5325
1.07k
    parser->node = NULL;
5326
5327
1.07k
    if (token->type == NJS_TOKEN_ELSE) {
5328
260
        node = njs_parser_node_new(parser, NJS_TOKEN_BRANCHING);
5329
260
        if (node == NULL) {
5330
0
            return NJS_ERROR;
5331
0
        }
5332
5333
260
        node->token_line = token->line;
5334
260
        node->left = parser->target->right;
5335
5336
260
        parser->target->right = node;
5337
5338
260
        njs_lexer_consume_token(parser->lexer, 1);
5339
260
        njs_parser_next(parser, njs_parser_statement_wo_node);
5340
5341
260
        return njs_parser_after(parser, current, parser->target, 1,
5342
260
                                njs_parser_else_statement_after);
5343
260
    }
5344
5345
811
    parser->node = parser->target;
5346
5347
811
    return njs_parser_stack_pop(parser);
5348
1.07k
}
5349
5350
5351
static njs_int_t
5352
njs_parser_else_statement_after(njs_parser_t *parser, njs_lexer_token_t *token,
5353
    njs_queue_link_t *current)
5354
260
{
5355
260
    parser->target->right->right = parser->node;
5356
5357
260
    parser->node = parser->target;
5358
5359
260
    return njs_parser_stack_pop(parser);
5360
260
}
5361
5362
5363
static njs_int_t
5364
njs_parser_iteration_statement_do(njs_parser_t *parser,
5365
    njs_lexer_token_t *token, njs_queue_link_t *current)
5366
2.70k
{
5367
2.70k
    njs_parser_node_t  *node;
5368
5369
2.70k
    node = njs_parser_node_new(parser, NJS_TOKEN_DO);
5370
2.70k
    if (node == NULL) {
5371
0
        return NJS_ERROR;
5372
0
    }
5373
5374
2.70k
    node->token_line = parser->line;
5375
5376
2.70k
    parser->node = NULL;
5377
5378
2.70k
    njs_parser_next(parser, njs_parser_statement_wo_node);
5379
5380
2.70k
    return njs_parser_after(parser, current, node, 1,
5381
2.70k
                            njs_parser_iteration_statement_do_while);
5382
2.70k
}
5383
5384
5385
static njs_int_t
5386
njs_parser_iteration_statement_do_while(njs_parser_t *parser,
5387
    njs_lexer_token_t *token, njs_queue_link_t *current)
5388
2.70k
{
5389
2.70k
    if (token->type != NJS_TOKEN_WHILE) {
5390
3
        return njs_parser_failed(parser);
5391
3
    }
5392
5393
2.70k
    parser->target->left = parser->node;
5394
5395
2.70k
    njs_lexer_consume_token(parser->lexer, 1);
5396
5397
2.70k
    njs_parser_next(parser, njs_parser_expression_parenthesis);
5398
5399
2.70k
    return njs_parser_after(parser, current, parser->target, 1,
5400
2.70k
                            njs_parser_do_while_semicolon);
5401
2.70k
}
5402
5403
5404
static njs_int_t
5405
njs_parser_do_while_semicolon(njs_parser_t *parser, njs_lexer_token_t *token,
5406
    njs_queue_link_t *current)
5407
2.70k
{
5408
2.70k
    if (parser->strict_semicolon) {
5409
0
        return njs_parser_failed(parser);
5410
0
    }
5411
5412
2.70k
    parser->target->right = parser->node;
5413
2.70k
    parser->node = parser->target;
5414
5415
2.70k
    return njs_parser_stack_pop(parser);
5416
2.70k
}
5417
5418
5419
static njs_int_t
5420
njs_parser_iteration_statement_while(njs_parser_t *parser,
5421
    njs_lexer_token_t *token, njs_queue_link_t *current)
5422
3.47k
{
5423
3.47k
    njs_parser_node_t  *node;
5424
5425
3.47k
    node = njs_parser_node_new(parser, NJS_TOKEN_WHILE);
5426
3.47k
    if (node == NULL) {
5427
0
        return NJS_ERROR;
5428
0
    }
5429
5430
3.47k
    node->token_line = token->line;
5431
5432
3.47k
    njs_parser_next(parser, njs_parser_expression_parenthesis);
5433
5434
3.47k
    return njs_parser_after(parser, current, node, 1,
5435
3.47k
                            njs_parser_while_statement);
5436
3.47k
}
5437
5438
5439
static njs_int_t
5440
njs_parser_while_statement(njs_parser_t *parser, njs_lexer_token_t *token,
5441
    njs_queue_link_t *current)
5442
3.47k
{
5443
3.47k
    parser->target->right = parser->node;
5444
3.47k
    parser->node = NULL;
5445
5446
3.47k
    njs_parser_next(parser, njs_parser_statement_wo_node);
5447
5448
3.47k
    return njs_parser_after(parser, current, parser->target, 1,
5449
3.47k
                            njs_parser_while_after);
5450
3.47k
}
5451
5452
5453
static njs_int_t
5454
njs_parser_while_after(njs_parser_t *parser, njs_lexer_token_t *token,
5455
    njs_queue_link_t *current)
5456
3.47k
{
5457
3.47k
    parser->target->left = parser->node;
5458
3.47k
    parser->node = parser->target;
5459
5460
3.47k
    return njs_parser_stack_pop(parser);
5461
3.47k
}
5462
5463
5464
static njs_int_t
5465
njs_parser_iteration_statement_for(njs_parser_t *parser,
5466
    njs_lexer_token_t *token, njs_queue_link_t *current)
5467
29.6k
{
5468
29.6k
    njs_int_t  ret;
5469
5470
29.6k
    if (token->type == NJS_TOKEN_OPEN_PARENTHESIS) {
5471
28.9k
        njs_lexer_consume_token(parser->lexer, 1);
5472
5473
28.9k
        ret = njs_parser_scope_begin(parser, NJS_SCOPE_BLOCK, 0);
5474
28.9k
        if (njs_slow_path(ret != NJS_OK)) {
5475
0
            return ret;
5476
0
        }
5477
5478
28.9k
        njs_parser_next(parser, njs_parser_iteration_statement_for_map);
5479
5480
28.9k
        return njs_parser_after(parser, current,
5481
28.9k
                                (void *) (uintptr_t) parser->line, 1,
5482
28.9k
                                njs_parser_iteration_statement_for_end);
5483
28.9k
    }
5484
5485
765
    if (token->type == NJS_TOKEN_AWAIT) {
5486
517
        return njs_parser_not_supported(parser, token);
5487
517
    }
5488
5489
248
    return njs_parser_failed(parser);
5490
765
}
5491
5492
5493
static njs_int_t
5494
njs_parser_for_expression_map_reparse(njs_parser_t *parser,
5495
    njs_lexer_token_t *token, njs_queue_link_t *current)
5496
10.8k
{
5497
10.8k
    if (parser->ret != NJS_OK && parser->node != NULL) {
5498
1
        return njs_parser_failed(parser);
5499
1
    }
5500
5501
10.8k
    if (parser->node == NULL) {
5502
341
        njs_lexer_in_fail_set(parser->lexer, 1);
5503
5504
341
        njs_parser_next(parser, njs_parser_expression);
5505
5506
341
        return NJS_OK;
5507
341
    }
5508
5509
10.4k
    return njs_parser_stack_pop(parser);
5510
10.8k
}
5511
5512
5513
static njs_int_t
5514
njs_parser_for_expression_map_continue(njs_parser_t *parser,
5515
    njs_lexer_token_t *token, njs_queue_link_t *current)
5516
10.4k
{
5517
10.4k
    njs_int_t          operation;
5518
10.4k
    njs_str_t          *text;
5519
10.4k
    njs_parser_node_t  *node;
5520
5521
10.4k
    if (token->type != NJS_TOKEN_IN) {
5522
10.1k
        njs_lexer_in_fail_set(parser->lexer, 1);
5523
5524
        /* Continue parsing of expr1 in "for (expr1;[expr2];[expr3])". */
5525
5526
10.1k
        njs_parser_next(parser, njs_parser_expression_continue_op);
5527
5528
        /*
5529
         * Here we pass not a node, but a token, this is important.
5530
         * This is necessary for correct error output.
5531
         */
5532
5533
10.1k
        text = njs_mp_alloc(parser->vm->mem_pool, sizeof(njs_str_t));
5534
10.1k
        if (text == NULL) {
5535
0
            return NJS_ERROR;
5536
0
        }
5537
5538
10.1k
        *text = token->text;
5539
5540
10.1k
        return njs_parser_after(parser, current, text, 1,
5541
10.1k
                                njs_parser_for_var_in_of_expression);
5542
5543
10.1k
    } else {
5544
5545
        /* for-in */
5546
5547
364
        if (parser->node->token_type != NJS_TOKEN_NAME &&
5548
364
            parser->node->token_type != NJS_TOKEN_PROPERTY)
5549
0
        {
5550
0
            text = (njs_str_t *) parser->target;
5551
5552
0
            njs_parser_ref_error(parser, "Invalid left-hand side \"%V\" "
5553
0
                                 "in for-in statement", text);
5554
5555
0
            njs_mp_free(parser->vm->mem_pool, text);
5556
5557
0
            return NJS_DONE;
5558
0
        }
5559
5560
364
        operation = NJS_VMCODE_PROPERTY_IN;
5561
5562
364
        node = njs_parser_node_new(parser, token->type);
5563
364
        if (node == NULL) {
5564
0
            return NJS_ERROR;
5565
0
        }
5566
5567
364
        node->token_line = token->line;
5568
364
        node->u.operation = operation;
5569
364
        node->left = parser->node;
5570
364
        node->left->dest = node;
5571
5572
364
        njs_lexer_consume_token(parser->lexer, 1);
5573
5574
364
        njs_parser_next(parser, njs_parser_expression);
5575
5576
364
        return njs_parser_after(parser, current, node, 0,
5577
364
                                njs_parser_for_in_statement_statement);
5578
364
    }
5579
10.4k
}
5580
5581
5582
static njs_int_t
5583
njs_parser_after_expr(njs_parser_t *parser,
5584
    njs_lexer_token_t *token, njs_queue_link_t *current)
5585
0
{
5586
0
    parser->target->right = parser->node;
5587
0
    parser->node = parser->target;
5588
5589
0
    return njs_parser_stack_pop(parser);
5590
0
}
5591
5592
5593
static njs_int_t
5594
njs_parser_comma_expression_comma(njs_parser_t *parser,
5595
    njs_lexer_token_t *token, njs_queue_link_t *current)
5596
10.1k
{
5597
10.1k
    njs_parser_node_t  *node;
5598
5599
10.1k
    if (parser->target != NULL) {
5600
0
        parser->target->right = parser->node;
5601
0
        parser->target->right->dest = parser->target;
5602
0
        parser->node = parser->target;
5603
0
    }
5604
5605
10.1k
    if (token->type != NJS_TOKEN_COMMA) {
5606
10.1k
        return njs_parser_stack_pop(parser);
5607
10.1k
    }
5608
5609
0
    node = njs_parser_node_new(parser, NJS_TOKEN_COMMA);
5610
0
    if (node == NULL) {
5611
0
        return NJS_ERROR;
5612
0
    }
5613
5614
0
    node->token_line = token->line;
5615
0
    node->u.operation = 0;
5616
0
    node->left = parser->node;
5617
0
    node->left->dest = node;
5618
5619
0
    njs_lexer_consume_token(parser->lexer, 1);
5620
5621
0
    njs_parser_next(parser, njs_parser_expression);
5622
5623
0
    return njs_parser_after(parser, current, node, 1, njs_parser_after_expr);
5624
0
}
5625
5626
5627
static njs_int_t
5628
njs_parser_expression_continue_op(njs_parser_t *parser,
5629
    njs_lexer_token_t *token, njs_queue_link_t *current)
5630
10.1k
{
5631
10.1k
    if (token->type == NJS_TOKEN_CONDITIONAL) {
5632
0
        njs_parser_next(parser, njs_parser_conditional_question_mark);
5633
0
        return njs_parser_after(parser, current, NULL, 0,
5634
0
                                njs_parser_expression_continue_assign_comma);
5635
10.1k
    } else {
5636
10.1k
        parser->target = NULL;
5637
5638
10.1k
        parser->use_lhs = 1;
5639
5640
10.1k
        njs_parser_next(parser, njs_parser_expression);
5641
5642
10.1k
        return njs_parser_after(parser, current, NULL, 1,
5643
10.1k
                                njs_parser_comma_expression_comma);
5644
10.1k
    }
5645
10.1k
}
5646
5647
5648
static njs_int_t
5649
njs_parser_expression_continue_assign_comma(njs_parser_t *parser,
5650
    njs_lexer_token_t *token, njs_queue_link_t *current)
5651
0
{
5652
0
    if (parser->ret != NJS_OK) {
5653
0
        return njs_parser_failed(parser);
5654
0
    }
5655
5656
0
    njs_parser_next(parser, njs_parser_assignment_expression_after);
5657
5658
0
    return njs_parser_after(parser, current, NULL, 1,
5659
0
                            njs_parser_expression_comma);
5660
0
}
5661
5662
5663
static njs_int_t
5664
njs_parser_iteration_statement_for_map(njs_parser_t *parser,
5665
    njs_lexer_token_t *token, njs_queue_link_t *current)
5666
28.9k
{
5667
28.9k
    njs_int_t         ret;
5668
28.9k
    njs_str_t         *text;
5669
28.9k
    njs_token_type_t  token_type;
5670
5671
    /*
5672
     * "var" <VariableDeclarationList> ";" <Expression>? ";" <Expression>? ")"
5673
     *     <Statement>
5674
     * "var" <ForBinding> "in" <Expression> ")" <Statement>
5675
     * "var" <ForBinding> "of" <AssignmentExpression> ")" <Statement>
5676
5677
     * <ForDeclaration> "in" <Expression> ")" <Statement>
5678
     * <ForDeclaration> "of" <AssignmentExpression> ")" <Statement>
5679
5680
     * <Expression>? ";" <Expression>? ";" <Expression>? ")" <Statement>
5681
     * <LexicalDeclaration> <Expression>? ";" <Expression>? ")" <Statement>
5682
5683
     * <LeftHandSideExpression> "in" <Expression> ")" <Statement>
5684
     * <LeftHandSideExpression> "of" <AssignmentExpression> ")" <Statement>
5685
     */
5686
5687
28.9k
    parser->node = NULL;
5688
5689
28.9k
    switch (token->type) {
5690
10.4k
    case NJS_TOKEN_SEMICOLON:
5691
10.4k
        token = njs_lexer_peek_token(parser->lexer, token, 0);
5692
10.4k
        if (token == NULL) {
5693
0
            return NJS_ERROR;
5694
0
        }
5695
5696
10.4k
        if (token->type != NJS_TOKEN_SEMICOLON) {
5697
6.14k
            njs_lexer_consume_token(parser->lexer, 1);
5698
5699
6.14k
            parser->target = NULL;
5700
5701
6.14k
            njs_parser_next(parser, njs_parser_expression);
5702
5703
6.14k
            return njs_parser_after(parser, current, NULL, 1,
5704
6.14k
                                    njs_parser_for_expression);
5705
6.14k
        }
5706
5707
4.29k
        parser->node = NULL;
5708
4.29k
        parser->target = NULL;
5709
5710
4.29k
        njs_lexer_consume_token(parser->lexer, 1);
5711
4.29k
        njs_parser_next(parser, njs_parser_for_expression);
5712
5713
4.29k
        return NJS_OK;
5714
5715
5.45k
    case NJS_TOKEN_VAR:
5716
5.45k
    case NJS_TOKEN_LET:
5717
5.45k
    case NJS_TOKEN_CONST:
5718
5.45k
        token_type = token->type;
5719
5720
5.45k
        token = njs_lexer_peek_token(parser->lexer, token, 0);
5721
5.45k
        if (token == NULL) {
5722
0
            return NJS_ERROR;
5723
0
        }
5724
5725
5.45k
        njs_lexer_consume_token(parser->lexer, 1);
5726
5727
5.45k
        ret = njs_parser_for_var_binding_or_var_list(parser, token,
5728
5.45k
                                                     current, token_type);
5729
5.45k
        if (ret != NJS_OK) {
5730
5.45k
            if (ret == NJS_DONE) {
5731
5.45k
                return NJS_OK;
5732
5.45k
            }
5733
5734
0
            return ret;
5735
5.45k
        }
5736
5737
1
        goto expression_after;
5738
5739
1.84k
    case NJS_TOKEN_AWAIT:
5740
1.84k
        njs_parser_next(parser, njs_parser_expression);
5741
5742
1.84k
        goto expression_after;
5743
5744
11.1k
    default:
5745
11.1k
        ret = njs_parser_match_arrow_expression(parser, token);
5746
11.1k
        if (ret == NJS_OK) {
5747
0
            parser->target = NULL;
5748
0
            njs_parser_next(parser, njs_parser_expression);
5749
0
            goto expression_after;
5750
11.1k
        } else if (ret == NJS_ERROR) {
5751
0
            return NJS_ERROR;
5752
0
        }
5753
5754
11.1k
        parser->target = NULL;
5755
11.1k
        njs_parser_next(parser, njs_parser_left_hand_side_expression);
5756
5757
        /*
5758
         * Here we pass not a node, but a token, this is important.
5759
         * This is necessary for correct error output.
5760
         */
5761
5762
11.1k
        text = njs_mp_alloc(parser->vm->mem_pool, sizeof(njs_str_t));
5763
11.1k
        if (text == NULL) {
5764
0
            return NJS_ERROR;
5765
0
        }
5766
5767
11.1k
        *text = token->text;
5768
5769
11.1k
        ret = njs_parser_after(parser, current, text, 0,
5770
11.1k
                               njs_parser_for_expression_map_reparse);
5771
11.1k
        if (ret != NJS_OK) {
5772
0
            return NJS_ERROR;
5773
0
        }
5774
5775
11.1k
        return njs_parser_after(parser, current, text, 1,
5776
28.9k
                                njs_parser_for_expression_map_continue);
5777
28.9k
    }
5778
5779
1.85k
expression_after:
5780
5781
    /*
5782
     * Here we pass not a node, but a token, this is important.
5783
     * This is necessary for correct error output.
5784
     */
5785
5786
1.85k
    text = njs_mp_alloc(parser->vm->mem_pool, sizeof(njs_str_t));
5787
1.85k
    if (text == NULL) {
5788
0
        return NJS_ERROR;
5789
0
    }
5790
5791
1.85k
    *text = token->text;
5792
5793
1.85k
    return njs_parser_after(parser, current, text, 1,
5794
1.85k
                            njs_parser_for_var_in_of_expression);
5795
1.85k
}
5796
5797
5798
static njs_int_t
5799
njs_parser_for_var_binding_or_var_list(njs_parser_t *parser,
5800
    njs_lexer_token_t *token, njs_queue_link_t *current,
5801
    njs_token_type_t token_type)
5802
5.45k
{
5803
5.45k
    njs_int_t            ret;
5804
5.45k
    njs_lexer_token_t    *next;
5805
5.45k
    njs_parser_node_t    *node, *var, *node_type, *statement;
5806
5.45k
    njs_variable_type_t  type;
5807
5808
5.45k
    switch (token_type) {
5809
0
    case NJS_TOKEN_LET:
5810
0
        type = NJS_VARIABLE_LET;
5811
0
        break;
5812
5813
4
    case NJS_TOKEN_CONST:
5814
4
        type = NJS_VARIABLE_CONST;
5815
4
        break;
5816
5817
5.45k
    default:
5818
5.45k
        type = NJS_VARIABLE_VAR;
5819
5.45k
        break;
5820
5.45k
    }
5821
5822
5.45k
    switch (token->type) {
5823
    /* BindingPattern */
5824
0
    case NJS_TOKEN_OPEN_BRACE:
5825
0
        njs_parser_next(parser, njs_parser_object_binding_pattern);
5826
0
        return NJS_DONE;
5827
5828
0
    case NJS_TOKEN_OPEN_BRACKET:
5829
0
        njs_parser_next(parser, njs_parser_array_binding_pattern);
5830
0
        return NJS_DONE;
5831
5832
5.45k
    default:
5833
5.45k
        if (njs_lexer_token_is_binding_identifier(token)) {
5834
5.45k
            if (njs_parser_restricted_identifier(token->type)) {
5835
0
                njs_parser_syntax_error(parser, "Identifier \"%V\" is forbidden"
5836
0
                                        " in var declaration", &token->text);
5837
0
                return NJS_DONE;
5838
0
            }
5839
5840
5.45k
            next = njs_lexer_peek_token(parser->lexer, token, 0);
5841
5.45k
            if (next == NULL) {
5842
0
                return NJS_ERROR;
5843
0
            }
5844
5845
5.45k
            if (next->type != NJS_TOKEN_IN) {
5846
1
                parser->var_type = type;
5847
5848
1
                njs_lexer_in_fail_set(parser->lexer, 1);
5849
5850
1
                njs_parser_next(parser, njs_parser_variable_declaration_list);
5851
1
                return NJS_OK;
5852
1
            }
5853
5854
5.45k
            statement = njs_parser_node_new(parser, NJS_TOKEN_STATEMENT);
5855
5.45k
            if (njs_slow_path(statement == NULL)) {
5856
0
                return NJS_ERROR;
5857
0
            }
5858
5859
5.45k
            node_type = njs_parser_node_new(parser, token_type);
5860
5.45k
            if (njs_slow_path(node_type == NULL)) {
5861
0
                return NJS_ERROR;
5862
0
            }
5863
5864
5.45k
            var = njs_parser_variable_node(parser, token->unique_id,
5865
5.45k
                                           type, NULL);
5866
5.45k
            if (var == NULL) {
5867
0
                return NJS_ERROR;
5868
0
            }
5869
5870
5.45k
            node_type->token_line = token->line;
5871
5.45k
            var->token_line = token->line;
5872
5873
5.45k
            statement->right = node_type;
5874
5.45k
            node_type->left = var;
5875
5.45k
            parser->node = NULL;
5876
5877
5.45k
            node = njs_parser_node_new(parser, NJS_TOKEN_IN);
5878
5.45k
            if (node == NULL) {
5879
0
                return NJS_ERROR;
5880
0
            }
5881
5882
5.45k
            node->token_line = next->line;
5883
5.45k
            node->left = statement;
5884
5885
5.45k
            njs_parser_next(parser, njs_parser_expression);
5886
5887
5.45k
            ret = njs_parser_after(parser, current, node, 1,
5888
5.45k
                                   njs_parser_for_var_in_statement);
5889
5.45k
            if (ret != NJS_OK) {
5890
0
                return NJS_ERROR;
5891
0
            }
5892
5893
5.45k
            njs_lexer_consume_token(parser->lexer, 2);
5894
5895
5.45k
            return NJS_DONE;
5896
5897
5.45k
        } else {
5898
0
            return njs_parser_failed(parser);
5899
0
        }
5900
5.45k
    }
5901
5.45k
}
5902
5903
5904
static njs_int_t
5905
njs_parser_for_var_in_statement(njs_parser_t *parser, njs_lexer_token_t *token,
5906
    njs_queue_link_t *current)
5907
5.45k
{
5908
5.45k
    if (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) {
5909
0
        return njs_parser_failed(parser);
5910
0
    }
5911
5912
5.45k
    njs_lexer_consume_token(parser->lexer, 1);
5913
5914
5.45k
    parser->target->right = parser->node;
5915
5.45k
    parser->node = NULL;
5916
5917
5.45k
    njs_parser_next(parser, njs_parser_statement_wo_node);
5918
5919
5.45k
    return njs_parser_after(parser, current, parser->target, 1,
5920
5.45k
                            njs_parser_for_var_in_statement_after);
5921
5.45k
}
5922
5923
5924
static njs_int_t
5925
njs_parser_for_var_in_statement_after(njs_parser_t *parser,
5926
    njs_lexer_token_t *token, njs_queue_link_t *current)
5927
628
{
5928
628
    njs_parser_node_t  *foreach;
5929
5930
628
    foreach = njs_parser_node_new(parser, NJS_TOKEN_FOR_IN);
5931
628
    if (foreach == NULL) {
5932
0
        return NJS_ERROR;
5933
0
    }
5934
5935
628
    foreach->left = parser->target;
5936
628
    foreach->right = parser->node;
5937
5938
628
    parser->node = foreach;
5939
5940
628
    return njs_parser_stack_pop(parser);
5941
628
}
5942
5943
5944
static njs_int_t
5945
njs_parser_for_var_in_of_expression(njs_parser_t *parser,
5946
    njs_lexer_token_t *token, njs_queue_link_t *current)
5947
10.5k
{
5948
10.5k
    njs_str_t          *text;
5949
10.5k
    njs_parser_node_t  *node;
5950
5951
    /*
5952
     * ";" <Expression>? ";" <Expression>? ")" <Statement>
5953
     * "in" <Expression> ")" <Statement>
5954
     * "of" <AssignmentExpression> ")" <Statement>
5955
     */
5956
5957
10.5k
    if (token->type != NJS_TOKEN_SEMICOLON &&
5958
10.5k
        token->type != NJS_TOKEN_CLOSE_PARENTHESIS &&
5959
10.5k
        parser->node != NULL && parser->node->token_type == NJS_TOKEN_IN)
5960
0
    {
5961
0
        node = parser->node->left;
5962
5963
0
        if (node->token_type != NJS_TOKEN_NAME &&
5964
0
            node->token_type != NJS_TOKEN_PROPERTY)
5965
0
        {
5966
5967
0
            text = (njs_str_t *) parser->target;
5968
5969
0
            njs_parser_ref_error(parser, "Invalid left-hand side \"%V\" "
5970
0
                                 "in for-in statement", text);
5971
5972
0
            njs_mp_free(parser->vm->mem_pool, text);
5973
5974
0
            return NJS_DONE;
5975
0
        }
5976
5977
0
        njs_parser_next(parser, njs_parser_for_in_statement);
5978
0
        return NJS_OK;
5979
0
    }
5980
5981
10.5k
    if (parser->target != NULL) {
5982
10.5k
        text = (njs_str_t *) parser->target;
5983
5984
10.5k
        njs_mp_free(parser->vm->mem_pool, text);
5985
10.5k
    }
5986
5987
10.5k
    switch (token->type) {
5988
8.27k
    case NJS_TOKEN_SEMICOLON:
5989
8.27k
        njs_lexer_in_fail_set(parser->lexer, 0);
5990
5991
8.27k
        token = njs_lexer_peek_token(parser->lexer, token, 0);
5992
8.27k
        if (token == NULL) {
5993
0
            return NJS_ERROR;
5994
0
        }
5995
5996
8.27k
        node = parser->node;
5997
8.27k
        parser->node = NULL;
5998
5999
8.27k
        if (token->type != NJS_TOKEN_SEMICOLON) {
6000
1.95k
            njs_lexer_consume_token(parser->lexer, 1);
6001
6002
1.95k
            njs_parser_next(parser, njs_parser_expression);
6003
6004
1.95k
            return njs_parser_after(parser, current, node, 1,
6005
1.95k
                                    njs_parser_for_expression);
6006
1.95k
        }
6007
6008
6.31k
        parser->target = node;
6009
6010
6.31k
        njs_lexer_consume_token(parser->lexer, 1);
6011
6.31k
        njs_parser_next(parser, njs_parser_for_expression);
6012
6013
6.31k
        return NJS_OK;
6014
6015
0
    case NJS_TOKEN_OF:
6016
0
        return njs_parser_not_supported(parser, token);
6017
6018
2.25k
    default:
6019
2.25k
        return njs_parser_failed(parser);
6020
10.5k
    }
6021
10.5k
}
6022
6023
6024
static njs_int_t
6025
njs_parser_for_in_statement(njs_parser_t *parser, njs_lexer_token_t *token,
6026
    njs_queue_link_t *current)
6027
0
{
6028
0
    njs_parser_node_t  *node, *forin;
6029
6030
0
    if (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) {
6031
0
        return njs_parser_failed(parser);
6032
0
    }
6033
6034
0
    njs_lexer_consume_token(parser->lexer, 1);
6035
6036
0
    node = parser->node;
6037
6038
0
    if (node->right != NULL && node->right->token_type == NJS_TOKEN_VAR) {
6039
0
        return NJS_ERROR;
6040
0
    }
6041
6042
0
    forin = njs_parser_node_new(parser, NJS_TOKEN_FOR_IN);
6043
0
    if (forin == NULL) {
6044
0
        return NJS_ERROR;
6045
0
    }
6046
6047
0
    forin->left = parser->node;
6048
6049
0
    parser->node = NULL;
6050
6051
0
    njs_parser_next(parser, njs_parser_statement_wo_node);
6052
6053
0
    return njs_parser_after(parser, current, forin, 1,
6054
0
                            njs_parser_for_in_statement_after);
6055
0
}
6056
6057
6058
static njs_int_t
6059
njs_parser_for_in_statement_statement(njs_parser_t *parser,
6060
    njs_lexer_token_t *token, njs_queue_link_t *current)
6061
364
{
6062
364
    njs_parser_node_t  *forin;
6063
6064
364
    if (parser->ret != NJS_OK || token->type != NJS_TOKEN_CLOSE_PARENTHESIS) {
6065
0
        return njs_parser_failed(parser);
6066
0
    }
6067
6068
364
    njs_lexer_consume_token(parser->lexer, 1);
6069
6070
364
    parser->target->right = parser->node;
6071
6072
364
    forin = njs_parser_node_new(parser, NJS_TOKEN_FOR_IN);
6073
364
    if (forin == NULL) {
6074
0
        return NJS_ERROR;
6075
0
    }
6076
6077
364
    forin->left = parser->target;
6078
6079
364
    parser->node = NULL;
6080
6081
364
    njs_parser_next(parser, njs_parser_statement_wo_node);
6082
6083
364
    return njs_parser_after(parser, current, forin, 1,
6084
364
                            njs_parser_for_in_statement_after);
6085
364
}
6086
6087
6088
static njs_int_t
6089
njs_parser_for_in_statement_after(njs_parser_t *parser,
6090
    njs_lexer_token_t *token, njs_queue_link_t *current)
6091
358
{
6092
358
    parser->target->right = parser->node;
6093
358
    parser->node = parser->target;
6094
6095
358
    return njs_parser_stack_pop(parser);
6096
358
}
6097
6098
6099
static njs_int_t
6100
njs_parser_for_expression(njs_parser_t *parser, njs_lexer_token_t *token,
6101
    njs_queue_link_t *current)
6102
18.7k
{
6103
18.7k
    njs_parser_node_t  *body, *cond, *for_node;
6104
6105
18.7k
    if (token->type != NJS_TOKEN_SEMICOLON) {
6106
530
        return njs_parser_failed(parser);
6107
530
    }
6108
6109
18.1k
    njs_lexer_consume_token(parser->lexer, 1);
6110
6111
18.1k
    for_node = njs_parser_node_new(parser, NJS_TOKEN_FOR);
6112
18.1k
    if (for_node == NULL) {
6113
0
        return NJS_ERROR;
6114
0
    }
6115
6116
18.1k
    cond = njs_parser_node_new(parser, 0);
6117
18.1k
    if (cond == NULL) {
6118
0
        return NJS_ERROR;
6119
0
    }
6120
6121
18.1k
    body = njs_parser_node_new(parser, 0);
6122
18.1k
    if (body == NULL) {
6123
0
        return NJS_ERROR;
6124
0
    }
6125
6126
18.1k
    for_node->left = parser->target;
6127
18.1k
    for_node->right = cond;
6128
6129
18.1k
    cond->left = parser->node;
6130
18.1k
    cond->right = body;
6131
6132
18.1k
    parser->node = NULL;
6133
6134
18.1k
    token = njs_lexer_token(parser->lexer, 0);
6135
18.1k
    if (token == NULL) {
6136
0
        return NJS_ERROR;
6137
0
    }
6138
6139
18.1k
    if (token->type == NJS_TOKEN_CLOSE_PARENTHESIS) {
6140
6.05k
        parser->target = for_node;
6141
6142
6.05k
        njs_parser_next(parser, njs_parser_for_expression_end);
6143
6144
6.05k
        return NJS_OK;
6145
6.05k
    }
6146
6147
12.1k
    njs_parser_next(parser, njs_parser_expression);
6148
6149
12.1k
    return njs_parser_after(parser, current, for_node, 1,
6150
18.1k
                            njs_parser_for_expression_end);
6151
18.1k
}
6152
6153
6154
static njs_int_t
6155
njs_parser_for_expression_end(njs_parser_t *parser, njs_lexer_token_t *token,
6156
    njs_queue_link_t *current)
6157
18.1k
{
6158
18.1k
    njs_parser_node_t  *body;
6159
6160
18.1k
    if (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) {
6161
0
        return njs_parser_failed(parser);
6162
0
    }
6163
6164
18.1k
    njs_lexer_consume_token(parser->lexer, 1);
6165
6166
18.1k
    body = parser->target->right->right;
6167
6168
18.1k
    body->right = parser->node;
6169
6170
18.1k
    parser->node = NULL;
6171
6172
18.1k
    njs_parser_next(parser, njs_parser_statement_wo_node);
6173
6174
18.1k
    return njs_parser_after(parser, current, parser->target, 1,
6175
18.1k
                            njs_parser_for_end);
6176
18.1k
}
6177
6178
6179
static njs_int_t
6180
njs_parser_for_end(njs_parser_t *parser, njs_lexer_token_t *token,
6181
    njs_queue_link_t *current)
6182
16.3k
{
6183
16.3k
    njs_parser_node_t  *body;
6184
6185
16.3k
    body = parser->target->right->right;
6186
6187
16.3k
    body->left = parser->node;
6188
16.3k
    parser->node = parser->target;
6189
6190
16.3k
    return njs_parser_stack_pop(parser);
6191
16.3k
}
6192
6193
6194
/*
6195
 * 13.8 continue Statement.
6196
 */
6197
static njs_int_t
6198
njs_parser_continue_statement(njs_parser_t *parser, njs_lexer_token_t *token,
6199
    njs_queue_link_t *current)
6200
2.19k
{
6201
2.19k
    return njs_parser_break_continue(parser, token, NJS_TOKEN_CONTINUE);
6202
2.19k
}
6203
6204
6205
/*
6206
 * 13.9 break Statement.
6207
 */
6208
static njs_int_t
6209
njs_parser_break_statement(njs_parser_t *parser, njs_lexer_token_t *token,
6210
    njs_queue_link_t *current)
6211
6.25k
{
6212
6.25k
    return njs_parser_break_continue(parser, token, NJS_TOKEN_BREAK);
6213
6.25k
}
6214
6215
6216
static njs_int_t
6217
njs_parser_break_continue(njs_parser_t *parser, njs_lexer_token_t *token,
6218
    njs_token_type_t type)
6219
8.44k
{
6220
8.44k
    njs_int_t  ret;
6221
6222
8.44k
    parser->node = njs_parser_node_new(parser, type);
6223
8.44k
    if (parser->node == NULL) {
6224
0
        return NJS_ERROR;
6225
0
    }
6226
6227
8.44k
    parser->node->token_line = parser->line;
6228
6229
8.44k
    switch (token->type) {
6230
374
    case NJS_TOKEN_SEMICOLON:
6231
374
        break;
6232
6233
0
    case NJS_TOKEN_LINE_END:
6234
0
        return njs_parser_failed(parser);
6235
6236
8.07k
    default:
6237
8.07k
        if (njs_lexer_token_is_label_identifier(token)) {
6238
849
            if (parser->lexer->prev_type == NJS_TOKEN_LINE_END) {
6239
849
                return njs_parser_stack_pop(parser);
6240
849
            }
6241
6242
0
            if (njs_label_find(parser->vm, parser->scope,
6243
0
                               token->unique_id) == NULL)
6244
0
            {
6245
0
                njs_parser_syntax_error(parser, "Undefined label \"%V\"",
6246
0
                                        &token->text);
6247
0
                return NJS_DONE;
6248
0
            }
6249
6250
0
            ret = njs_name_copy(parser->vm, &parser->node->name, &token->text);
6251
0
            if (ret != NJS_OK) {
6252
0
                return NJS_ERROR;
6253
0
            }
6254
6255
0
            break;
6256
0
        }
6257
6258
7.22k
        if (parser->strict_semicolon
6259
7.22k
            || (token->type != NJS_TOKEN_END
6260
7.22k
                && token->type != NJS_TOKEN_CLOSE_BRACE
6261
7.22k
                && parser->lexer->prev_type != NJS_TOKEN_LINE_END))
6262
518
        {
6263
518
            return njs_parser_failed(parser);
6264
518
        }
6265
6266
6.70k
        return njs_parser_stack_pop(parser);
6267
8.44k
    }
6268
6269
374
    njs_lexer_consume_token(parser->lexer, 1);
6270
6271
374
    return njs_parser_stack_pop(parser);
6272
8.44k
}
6273
6274
6275
/*
6276
 * 13.10 return Statement.
6277
 */
6278
static njs_int_t
6279
njs_parser_return_statement(njs_parser_t *parser, njs_lexer_token_t *token,
6280
    njs_queue_link_t *current)
6281
7.67k
{
6282
7.67k
    njs_parser_node_t   *node;
6283
7.67k
    njs_parser_scope_t  *scope;
6284
6285
7.67k
    for (scope = parser->scope;
6286
31.9k
         scope != NULL;
6287
24.3k
         scope = scope->parent)
6288
31.9k
    {
6289
31.9k
        if (scope->type == NJS_SCOPE_FUNCTION) {
6290
7.67k
            break;
6291
7.67k
        }
6292
6293
24.3k
        if (scope->parent == NULL) {
6294
0
            njs_parser_syntax_error(parser, "Illegal return statement");
6295
0
            return NJS_ERROR;
6296
0
        }
6297
24.3k
    }
6298
6299
7.67k
    node = njs_parser_node_new(parser, NJS_TOKEN_RETURN);
6300
7.67k
    if (njs_slow_path(node == NULL)) {
6301
0
        return NJS_ERROR;
6302
0
    }
6303
6304
7.67k
    node->token_line = parser->line;
6305
6306
7.67k
    switch (token->type) {
6307
541
    case NJS_TOKEN_SEMICOLON:
6308
541
        njs_lexer_consume_token(parser->lexer, 1);
6309
541
        break;
6310
6311
0
    case NJS_TOKEN_LINE_END:
6312
0
        return njs_parser_failed(parser);
6313
6314
7.13k
    default:
6315
7.13k
        if (!parser->strict_semicolon
6316
7.13k
            && parser->lexer->prev_type == NJS_TOKEN_LINE_END)
6317
3
        {
6318
3
            break;
6319
3
        }
6320
6321
7.13k
        parser->node = NULL;
6322
6323
7.13k
        if (token->type != NJS_TOKEN_CLOSE_BRACE) {
6324
7.12k
            njs_parser_next(parser, njs_parser_expression);
6325
6326
7.12k
            return njs_parser_after(parser, current, node, 0,
6327
7.12k
                                    njs_parser_return_statement_after);
6328
7.12k
        }
6329
7.67k
    }
6330
6331
552
    parser->node = node;
6332
6333
552
    return njs_parser_stack_pop(parser);
6334
7.67k
}
6335
6336
6337
static njs_int_t
6338
njs_parser_return_statement_after(njs_parser_t *parser,
6339
    njs_lexer_token_t *token, njs_queue_link_t *current)
6340
7.12k
{
6341
7.12k
    if (parser->ret != NJS_OK) {
6342
1.81k
        njs_parser_syntax_error(parser, "Unexpected token \"%V\"",
6343
1.81k
                                &token->text);
6344
1.81k
        return NJS_DONE;
6345
1.81k
    }
6346
6347
5.31k
    if (njs_parser_expect_semicolon(parser, token) != NJS_OK) {
6348
636
        return njs_parser_failed(parser);
6349
636
    }
6350
6351
4.68k
    parser->target->right = parser->node;
6352
4.68k
    parser->node = parser->target;
6353
6354
4.68k
    return njs_parser_stack_pop(parser);
6355
5.31k
}
6356
6357
6358
/*
6359
 * 13.11 with Statement
6360
 */
6361
static njs_int_t
6362
njs_parser_with_statement(njs_parser_t *parser, njs_lexer_token_t *token,
6363
    njs_queue_link_t *current)
6364
0
{
6365
0
    return njs_parser_not_supported(parser, token);
6366
0
}
6367
6368
6369
/*
6370
 * 13.12 switch Statement
6371
 */
6372
static njs_int_t
6373
njs_parser_switch_statement(njs_parser_t *parser, njs_lexer_token_t *token,
6374
    njs_queue_link_t *current)
6375
109
{
6376
109
    njs_int_t          ret;
6377
109
    njs_parser_node_t  *swtch;
6378
6379
109
    swtch = njs_parser_node_new(parser, NJS_TOKEN_SWITCH);
6380
109
    if (swtch == NULL) {
6381
0
        return NJS_ERROR;
6382
0
    }
6383
6384
109
    swtch->token_line = parser->line;
6385
6386
109
    njs_parser_next(parser, njs_parser_expression_parenthesis);
6387
6388
109
    ret = njs_parser_after(parser, current, swtch, 1,
6389
109
                           njs_parser_switch_block);
6390
109
    if (ret != NJS_OK) {
6391
0
        return ret;
6392
0
    }
6393
6394
109
    return njs_parser_after(parser, current, swtch, 1,
6395
109
                            njs_parser_switch_statement_after);
6396
109
}
6397
6398
6399
static njs_int_t
6400
njs_parser_switch_statement_after(njs_parser_t *parser,
6401
    njs_lexer_token_t *token, njs_queue_link_t *current)
6402
100
{
6403
100
    parser->node = parser->target;
6404
6405
100
    return njs_parser_stack_pop(parser);
6406
100
}
6407
6408
6409
static njs_int_t
6410
njs_parser_switch_block(njs_parser_t *parser, njs_lexer_token_t *token,
6411
    njs_queue_link_t *current)
6412
109
{
6413
109
    njs_int_t  ret;
6414
6415
109
    if (token->type != NJS_TOKEN_OPEN_BRACE) {
6416
0
        return njs_parser_failed(parser);
6417
0
    }
6418
6419
109
    njs_lexer_consume_token(parser->lexer, 1);
6420
6421
109
    parser->target->left = parser->node;
6422
6423
109
    ret = njs_parser_scope_begin(parser, NJS_SCOPE_BLOCK, 0);
6424
109
    if (ret != NJS_OK) {
6425
0
        return NJS_ERROR;
6426
0
    }
6427
6428
109
    njs_parser_next(parser, njs_parser_switch_case);
6429
6430
109
    return njs_parser_after(parser, current, NULL, 1,
6431
109
                            njs_parser_switch_block_after);
6432
109
}
6433
6434
static njs_int_t
6435
njs_parser_switch_block_after(njs_parser_t *parser, njs_lexer_token_t *token,
6436
    njs_queue_link_t *current)
6437
100
{
6438
100
    njs_parser_scope_end(parser);
6439
6440
100
    return njs_parser_stack_pop(parser);
6441
100
}
6442
6443
6444
static njs_int_t
6445
njs_parser_switch_case(njs_parser_t *parser, njs_lexer_token_t *token,
6446
    njs_queue_link_t *current)
6447
301
{
6448
301
    return njs_parser_switch_case_def(parser, token, current, 1);
6449
301
}
6450
6451
6452
static njs_int_t
6453
njs_parser_switch_case_wo_def(njs_parser_t *parser, njs_lexer_token_t *token,
6454
    njs_queue_link_t *current)
6455
0
{
6456
0
    return njs_parser_switch_case_def(parser, token, current, 0);
6457
0
}
6458
6459
6460
static njs_int_t
6461
njs_parser_switch_case_def(njs_parser_t *parser, njs_lexer_token_t *token,
6462
    njs_queue_link_t *current, njs_bool_t with_default)
6463
301
{
6464
301
    njs_parser_node_t  *node, *branch;
6465
6466
301
    node = njs_parser_node_new(parser, 0);
6467
301
    if (node == NULL) {
6468
0
        return NJS_ERROR;
6469
0
    }
6470
6471
301
    parser->node = NULL;
6472
6473
301
    switch (token->type) {
6474
201
    case NJS_TOKEN_CASE:
6475
201
        branch = njs_parser_node_new(parser, 0);
6476
201
        if (branch == NULL) {
6477
0
            return NJS_ERROR;
6478
0
        }
6479
6480
201
        branch->token_line = token->line;
6481
201
        branch->right = node;
6482
6483
201
        njs_parser_next(parser, njs_parser_expression);
6484
6485
201
        njs_lexer_consume_token(parser->lexer, 1);
6486
6487
201
        if (parser->target->token_type == NJS_TOKEN_SWITCH) {
6488
109
            parser->target->right = branch;
6489
6490
109
        } else {
6491
92
            parser->target->left = branch;
6492
92
        }
6493
6494
201
        if (with_default) {
6495
201
            return njs_parser_after(parser, current, branch, 1,
6496
201
                                    njs_parser_switch_case_after);
6497
6498
201
        } else {
6499
0
            return njs_parser_after(parser, current, branch, 1,
6500
0
                                    njs_parser_switch_case_after_wo_def);
6501
0
        }
6502
6503
0
    case NJS_TOKEN_DEFAULT:
6504
0
        if (!with_default) {
6505
0
            njs_parser_syntax_error(parser, "More than one default clause "
6506
0
                                            "in switch statement");
6507
0
            return NJS_DONE;
6508
0
        }
6509
6510
0
        if (parser->target->token_type == NJS_TOKEN_SWITCH) {
6511
0
            parser->target->right = node;
6512
6513
0
        } else {
6514
0
            parser->target->left = node;
6515
0
        }
6516
6517
0
        node->token_line = token->line;
6518
0
        node->token_type = NJS_TOKEN_DEFAULT;
6519
6520
0
        parser->target = node;
6521
6522
0
        njs_lexer_consume_token(parser->lexer, 1);
6523
0
        njs_parser_next(parser, njs_parser_switch_case_after_wo_def);
6524
6525
0
        break;
6526
6527
100
    case NJS_TOKEN_CLOSE_BRACE:
6528
100
        njs_lexer_consume_token(parser->lexer, 1);
6529
100
        return njs_parser_stack_pop(parser);
6530
6531
0
    default:
6532
0
        return njs_parser_failed(parser);
6533
301
    }
6534
6535
0
    return NJS_OK;
6536
301
}
6537
6538
6539
static njs_int_t
6540
njs_parser_switch_case_after(njs_parser_t *parser, njs_lexer_token_t *token,
6541
    njs_queue_link_t *current)
6542
201
{
6543
201
    if (token->type != NJS_TOKEN_COLON) {
6544
0
        return njs_parser_failed(parser);
6545
0
    }
6546
6547
201
    njs_lexer_consume_token(parser->lexer, 1);
6548
6549
201
    parser->target->right->left = parser->node;
6550
201
    parser->node = NULL;
6551
6552
201
    token = njs_lexer_token(parser->lexer, 0);
6553
201
    if (token == NULL) {
6554
0
        return NJS_ERROR;
6555
0
    }
6556
6557
201
    switch (token->type) {
6558
92
    case NJS_TOKEN_CASE:
6559
92
    case NJS_TOKEN_DEFAULT:
6560
92
    case NJS_TOKEN_CLOSE_BRACE:
6561
92
        njs_parser_next(parser, njs_parser_switch_case_block);
6562
92
        return NJS_OK;
6563
6564
109
    default:
6565
109
        njs_parser_next(parser, njs_parser_statement_list);
6566
109
        break;
6567
201
    }
6568
6569
109
    return njs_parser_after(parser, current, parser->target, 1,
6570
201
                            njs_parser_switch_case_block);
6571
201
}
6572
6573
6574
static njs_int_t
6575
njs_parser_switch_case_block(njs_parser_t *parser, njs_lexer_token_t *token,
6576
    njs_queue_link_t *current)
6577
201
{
6578
201
    parser->target->right->right = parser->node;
6579
6580
201
    if (parser->ret != NJS_OK && parser->target->scope != parser->scope) {
6581
9
        return njs_parser_failed(parser);
6582
9
    }
6583
6584
192
    njs_parser_next(parser, njs_parser_switch_case);
6585
6586
192
    return NJS_OK;
6587
201
}
6588
6589
6590
static njs_int_t
6591
njs_parser_switch_case_after_wo_def(njs_parser_t *parser,
6592
    njs_lexer_token_t *token, njs_queue_link_t *current)
6593
0
{
6594
0
    if (token->type != NJS_TOKEN_COLON) {
6595
0
        return njs_parser_failed(parser);
6596
0
    }
6597
6598
0
    njs_lexer_consume_token(parser->lexer, 1);
6599
6600
0
    if (parser->target->right != NULL) {
6601
0
        parser->target->right->left = parser->node;
6602
0
    }
6603
6604
0
    parser->node = NULL;
6605
6606
0
    token = njs_lexer_token(parser->lexer, 0);
6607
0
    if (token == NULL) {
6608
0
        return NJS_ERROR;
6609
0
    }
6610
6611
0
    switch (token->type) {
6612
0
    case NJS_TOKEN_CASE:
6613
0
    case NJS_TOKEN_DEFAULT:
6614
0
    case NJS_TOKEN_CLOSE_BRACE:
6615
0
        njs_parser_next(parser, njs_parser_switch_case_block_wo_def);
6616
0
        return NJS_OK;
6617
6618
0
    default:
6619
0
        njs_parser_next(parser, njs_parser_statement_list);
6620
0
        break;
6621
0
    }
6622
6623
0
    return njs_parser_after(parser, current, parser->target, 1,
6624
0
                            njs_parser_switch_case_block_wo_def);
6625
0
}
6626
6627
6628
static njs_int_t
6629
njs_parser_switch_case_block_wo_def(njs_parser_t *parser,
6630
    njs_lexer_token_t *token, njs_queue_link_t *current)
6631
0
{
6632
0
    if (parser->target->right != NULL) {
6633
0
        parser->target->right->right = parser->node;
6634
6635
0
    } else {
6636
0
        parser->target->right = parser->node;
6637
0
    }
6638
6639
0
    if (parser->ret != NJS_OK && parser->target->scope != parser->scope) {
6640
0
        return njs_parser_failed(parser);
6641
0
    }
6642
6643
0
    njs_parser_next(parser, njs_parser_switch_case_wo_def);
6644
6645
0
    return NJS_OK;
6646
0
}
6647
6648
6649
/*
6650
 * 13.13 Labelled Statements
6651
 */
6652
static njs_int_t
6653
njs_parser_labelled_statement(njs_parser_t *parser, njs_lexer_token_t *token,
6654
    njs_queue_link_t *current)
6655
19.3k
{
6656
19.3k
    uintptr_t          unique_id;
6657
19.3k
    njs_variable_t     *label;
6658
6659
19.3k
    unique_id = token->unique_id;
6660
6661
19.3k
    label = njs_label_find(parser->vm, parser->scope, unique_id);
6662
19.3k
    if (label != NULL) {
6663
0
        njs_parser_syntax_error(parser, "Label \"%V\" "
6664
0
                                "has already been declared", &token->text);
6665
0
        return NJS_DONE;
6666
0
    }
6667
6668
19.3k
    label = njs_label_add(parser->vm, parser->scope, unique_id);
6669
19.3k
    if (label == NULL) {
6670
0
        return NJS_ERROR;
6671
0
    }
6672
6673
19.3k
    njs_lexer_consume_token(parser->lexer, 2);
6674
6675
19.3k
    token = njs_lexer_token(parser->lexer, 0);
6676
19.3k
    if (token == NULL) {
6677
0
        return NJS_ERROR;
6678
0
    }
6679
6680
19.3k
    parser->node = NULL;
6681
6682
19.3k
    if (token->type == NJS_TOKEN_FUNCTION) {
6683
0
        njs_syntax_error(parser->vm, "In strict mode code, functions can only "
6684
0
                                "be declared at top level or inside a block.");
6685
0
        return NJS_DONE;
6686
6687
19.3k
    } else {
6688
19.3k
        njs_parser_next(parser, njs_parser_statement_wo_node);
6689
19.3k
    }
6690
6691
19.3k
    return njs_parser_after(parser, current, (void *) unique_id, 1,
6692
19.3k
                            njs_parser_labelled_statement_after);
6693
19.3k
}
6694
6695
6696
static njs_int_t
6697
njs_parser_labelled_statement_after(njs_parser_t *parser,
6698
    njs_lexer_token_t *token, njs_queue_link_t *current)
6699
11.9k
{
6700
11.9k
    njs_int_t                ret;
6701
11.9k
    uintptr_t                unique_id;
6702
11.9k
    njs_parser_node_t        *node;
6703
11.9k
    const njs_lexer_entry_t  *entry;
6704
6705
11.9k
    node = parser->node;
6706
11.9k
    if (node == NULL) {
6707
690
        node = njs_parser_node_new(parser, NJS_TOKEN_BLOCK);
6708
690
        if (node == NULL) {
6709
0
            return NJS_ERROR;
6710
0
        }
6711
6712
690
        node->token_line = token->line;
6713
6714
690
        parser->node = node;
6715
690
    }
6716
6717
11.9k
    unique_id = (uintptr_t) parser->target;
6718
11.9k
    entry = (const njs_lexer_entry_t *) unique_id;
6719
6720
11.9k
    ret = njs_name_copy(parser->vm, &parser->node->name, &entry->name);
6721
11.9k
    if (ret != NJS_OK) {
6722
0
        return NJS_ERROR;
6723
0
    }
6724
6725
11.9k
    ret = njs_label_remove(parser->vm, parser->scope, unique_id);
6726
11.9k
    if (ret != NJS_OK) {
6727
0
        return NJS_ERROR;
6728
0
    }
6729
6730
11.9k
    return njs_parser_stack_pop(parser);
6731
11.9k
}
6732
6733
6734
/*
6735
 * 13.14 throw Statement
6736
 */
6737
static njs_int_t
6738
njs_parser_throw_statement(njs_parser_t *parser, njs_lexer_token_t *token,
6739
    njs_queue_link_t *current)
6740
110
{
6741
110
    njs_parser_node_t  *node;
6742
6743
110
    node = njs_parser_node_new(parser, NJS_TOKEN_THROW);
6744
110
    if (node == NULL) {
6745
0
        return NJS_ERROR;
6746
0
    }
6747
6748
110
    node->token_line = parser->line;
6749
6750
110
    if (parser->lexer->prev_type == NJS_TOKEN_LINE_END) {
6751
0
        njs_parser_syntax_error(parser, "Illegal newline after throw");
6752
0
        return NJS_DONE;
6753
0
    }
6754
6755
110
    parser->node = NULL;
6756
6757
110
    njs_parser_next(parser, njs_parser_expression);
6758
6759
110
    return njs_parser_after(parser, current, node, 1,
6760
110
                            njs_parser_throw_statement_after);
6761
110
}
6762
6763
6764
static njs_int_t
6765
njs_parser_throw_statement_after(njs_parser_t *parser,
6766
    njs_lexer_token_t *token, njs_queue_link_t *current)
6767
110
{
6768
110
    if (parser->ret != NJS_OK) {
6769
0
        parser->node = parser->target;
6770
0
        return njs_parser_reject(parser);
6771
0
    }
6772
6773
110
    if (njs_parser_expect_semicolon(parser, token) != NJS_OK) {
6774
0
        return njs_parser_failed(parser);
6775
0
    }
6776
6777
110
    parser->target->right = parser->node;
6778
110
    parser->node = parser->target;
6779
6780
110
    return njs_parser_stack_pop(parser);
6781
110
}
6782
6783
6784
/*
6785
 * 13.15 try Statement.
6786
 */
6787
static njs_int_t
6788
njs_parser_try_statement(njs_parser_t *parser, njs_lexer_token_t *token,
6789
    njs_queue_link_t *current)
6790
13.1k
{
6791
13.1k
    njs_parser_node_t  *try;
6792
6793
13.1k
    try = njs_parser_node_new(parser, NJS_TOKEN_TRY);
6794
13.1k
    if (try == NULL) {
6795
0
        return NJS_ERROR;
6796
0
    }
6797
6798
13.1k
    try->token_line = parser->line;
6799
6800
13.1k
    parser->node = NULL;
6801
6802
13.1k
    njs_parser_next(parser, njs_parser_block_statement_open_brace);
6803
6804
13.1k
    return njs_parser_after(parser, current, try, 1,
6805
13.1k
                            njs_parser_catch_or_finally);
6806
13.1k
}
6807
6808
6809
static njs_int_t
6810
njs_parser_catch_or_finally(njs_parser_t *parser, njs_lexer_token_t *token,
6811
    njs_queue_link_t *current)
6812
10.7k
{
6813
10.7k
    njs_int_t          ret;
6814
10.7k
    njs_parser_node_t  *catch, *node, *try;
6815
6816
10.7k
    try = parser->target;
6817
6818
10.7k
    try->left = parser->node;
6819
6820
10.7k
    if (token->type == NJS_TOKEN_FINALLY) {
6821
0
        node = njs_parser_node_new(parser, NJS_TOKEN_FINALLY);
6822
0
        if (node == NULL) {
6823
0
            return NJS_ERROR;
6824
0
        }
6825
6826
0
        node->token_line = token->line;
6827
6828
0
        if (try->right != NULL) {
6829
0
            node->left = try->right;
6830
0
        }
6831
6832
0
        try->right = node;
6833
0
        parser->node = NULL;
6834
6835
0
        njs_lexer_consume_token(parser->lexer, 1);
6836
0
        njs_parser_next(parser, njs_parser_block_statement_open_brace);
6837
6838
0
        return njs_parser_after(parser, current, try, 0,
6839
0
                                njs_parser_catch_finally);
6840
6841
10.7k
    } else if (token->type != NJS_TOKEN_CATCH) {
6842
1.76k
        njs_parser_syntax_error(parser, "Missing catch or finally after try");
6843
1.76k
        return NJS_DONE;
6844
1.76k
    }
6845
6846
8.99k
    catch = njs_parser_node_new(parser, NJS_TOKEN_CATCH);
6847
8.99k
    if (catch == NULL) {
6848
0
        return NJS_ERROR;
6849
0
    }
6850
6851
8.99k
    catch->token_line = token->line;
6852
6853
8.99k
    njs_lexer_consume_token(parser->lexer, 1);
6854
6855
8.99k
    token = njs_lexer_token(parser->lexer, 0);
6856
8.99k
    if (token == NULL) {
6857
0
        return NJS_ERROR;
6858
0
    }
6859
6860
8.99k
    ret = njs_parser_scope_begin(parser, NJS_SCOPE_BLOCK, 0);
6861
8.99k
    if (ret != NJS_OK) {
6862
0
        return NJS_ERROR;
6863
0
    }
6864
6865
8.99k
    if (token->type != NJS_TOKEN_OPEN_PARENTHESIS) {
6866
0
        parser->node = NULL;
6867
6868
0
        njs_parser_next(parser, njs_parser_block_statement_open_brace);
6869
6870
0
        try->right = catch;
6871
6872
        /* TODO: it is necessary to change the generator. */
6873
6874
0
        return njs_parser_not_supported(parser, token);
6875
6876
        /*
6877
         *  return njs_parser_after(parser, current, parser->target, 0,
6878
         *                          njs_parser_catch_after);
6879
         */
6880
0
    }
6881
6882
8.99k
    njs_lexer_consume_token(parser->lexer, 1);
6883
6884
8.99k
    token = njs_lexer_token(parser->lexer, 0);
6885
8.99k
    if (token == NULL) {
6886
0
        return NJS_ERROR;
6887
0
    }
6888
6889
8.99k
    try->right = catch;
6890
6891
8.99k
    if (njs_lexer_token_is_binding_identifier(token)) {
6892
8.33k
        node = njs_parser_variable_node(parser, token->unique_id,
6893
8.33k
                                        NJS_VARIABLE_CATCH, NULL);
6894
8.33k
        if (node == NULL) {
6895
0
            return NJS_ERROR;
6896
0
        }
6897
6898
8.33k
        node->token_line = token->line;
6899
6900
8.33k
        catch->left = node;
6901
6902
8.33k
        njs_lexer_consume_token(parser->lexer, 1);
6903
8.33k
        njs_parser_next(parser, njs_parser_catch_parenthesis);
6904
8.33k
        return NJS_OK;
6905
8.33k
    }
6906
6907
662
    if (token->type != NJS_TOKEN_OPEN_BRACE) {
6908
283
        return njs_parser_failed(parser);
6909
283
    }
6910
6911
    /*
6912
     * njs_parser_next(parser, njs_parser_block_statement_open_brace);
6913
     *
6914
     * return njs_parser_after(parser, current, try, 1,
6915
     *                       njs_parser_catch_parenthesis);
6916
     */
6917
6918
379
    return njs_parser_not_supported(parser, token);
6919
662
}
6920
6921
6922
static njs_int_t
6923
njs_parser_catch_after(njs_parser_t *parser, njs_lexer_token_t *token,
6924
    njs_queue_link_t *current)
6925
998
{
6926
998
    njs_parser_node_t  *node;
6927
6928
998
    parser->target->right->right = parser->node;
6929
6930
998
    if (token->type == NJS_TOKEN_FINALLY) {
6931
0
        node = njs_parser_node_new(parser, NJS_TOKEN_FINALLY);
6932
0
        if (node == NULL) {
6933
0
            return NJS_ERROR;
6934
0
        }
6935
6936
0
        node->token_line = token->line;
6937
6938
0
        if (parser->target->right != NULL) {
6939
0
            node->left = parser->target->right;
6940
0
        }
6941
6942
0
        parser->target->right = node;
6943
0
        parser->node = NULL;
6944
6945
0
        njs_lexer_consume_token(parser->lexer, 1);
6946
0
        njs_parser_next(parser, njs_parser_block_statement_open_brace);
6947
6948
0
        return njs_parser_after(parser, current, parser->target, 1,
6949
0
                                njs_parser_catch_finally);
6950
0
    }
6951
6952
998
    parser->node = parser->target;
6953
6954
998
    return njs_parser_stack_pop(parser);
6955
998
}
6956
6957
6958
static njs_int_t
6959
njs_parser_catch_parenthesis(njs_parser_t *parser, njs_lexer_token_t *token,
6960
    njs_queue_link_t *current)
6961
8.33k
{
6962
8.33k
    if (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) {
6963
0
        return njs_parser_failed(parser);
6964
0
    }
6965
6966
8.33k
    njs_lexer_consume_token(parser->lexer, 1);
6967
6968
8.33k
    parser->target->right->right = parser->node;
6969
8.33k
    parser->node = NULL;
6970
6971
8.33k
    njs_parser_next(parser, njs_parser_catch_statement_open_brace);
6972
6973
8.33k
    return njs_parser_after(parser, current, parser->target, 1,
6974
8.33k
                            njs_parser_catch_after);
6975
8.33k
}
6976
6977
6978
static njs_int_t
6979
njs_parser_catch_statement_open_brace(njs_parser_t *parser,
6980
    njs_lexer_token_t *token, njs_queue_link_t *current)
6981
8.33k
{
6982
8.33k
    void  *target;
6983
6984
8.33k
    if (token->type != NJS_TOKEN_OPEN_BRACE) {
6985
0
        return njs_parser_failed(parser);
6986
0
    }
6987
6988
8.33k
    parser->line = token->line;
6989
6990
8.33k
    njs_lexer_consume_token(parser->lexer, 1);
6991
6992
8.33k
    token = njs_lexer_token(parser->lexer, 0);
6993
8.33k
    if (token == NULL) {
6994
0
        return NJS_ERROR;
6995
0
    }
6996
6997
8.33k
    target = (void *) (uintptr_t) parser->line;
6998
8.33k
    parser->node = NULL;
6999
7000
8.33k
    if (token->type == NJS_TOKEN_CLOSE_BRACE) {
7001
788
        parser->target = target;
7002
7003
788
        njs_parser_next(parser, njs_parser_block_statement_close_brace);
7004
788
        return NJS_OK;
7005
788
    }
7006
7007
7.54k
    njs_parser_next(parser, njs_parser_statement_list);
7008
7009
7.54k
    return njs_parser_after(parser, current, target, 0,
7010
8.33k
                            njs_parser_block_statement_close_brace);
7011
8.33k
}
7012
7013
7014
static njs_int_t
7015
njs_parser_catch_finally(njs_parser_t *parser, njs_lexer_token_t *token,
7016
    njs_queue_link_t *current)
7017
0
{
7018
0
    if (parser->ret != NJS_OK) {
7019
0
        return njs_parser_failed(parser);
7020
0
    }
7021
7022
0
    parser->target->right->right = parser->node;
7023
0
    parser->node = parser->target;
7024
7025
0
    return njs_parser_stack_pop(parser);
7026
0
}
7027
7028
7029
static njs_int_t
7030
njs_parser_debugger_statement(njs_parser_t *parser, njs_lexer_token_t *token,
7031
    njs_queue_link_t *current)
7032
514
{
7033
514
    parser->node = njs_parser_node_new(parser, NJS_TOKEN_DEBUGGER);
7034
514
    if (parser->node == NULL) {
7035
0
        return NJS_ERROR;
7036
0
    }
7037
7038
514
    parser->node->token_line = parser->line;
7039
7040
514
    if (token->type != NJS_TOKEN_SEMICOLON
7041
514
        && token->type != NJS_TOKEN_END)
7042
0
    {
7043
0
        return njs_parser_failed(parser);
7044
0
    }
7045
7046
514
    njs_lexer_consume_token(parser->lexer, 1);
7047
7048
514
    return njs_parser_stack_pop(parser);
7049
514
}
7050
7051
7052
/*
7053
 * 14.1 Function Definitions.
7054
 */
7055
static njs_int_t
7056
njs_parser_function_declaration(njs_parser_t *parser, njs_lexer_token_t *token,
7057
    njs_queue_link_t *current)
7058
6.08k
{
7059
6.08k
    njs_int_t          ret;
7060
6.08k
    uintptr_t          unique_id;
7061
6.08k
    njs_bool_t         async;
7062
6.08k
    njs_variable_t     *var;
7063
6.08k
    njs_parser_node_t  *node;
7064
7065
6.08k
    if (!njs_lexer_token_is_binding_identifier(token)) {
7066
262
        return njs_parser_failed(parser);
7067
262
    }
7068
7069
5.82k
    if (njs_parser_restricted_identifier(token->type)) {
7070
0
        njs_parser_syntax_error(parser, "Identifier \"%V\" is forbidden"
7071
0
                                " in function declaration", &token->text);
7072
0
        return NJS_DONE;
7073
0
    }
7074
7075
5.82k
    node = parser->node;
7076
5.82k
    unique_id = token->unique_id;
7077
7078
5.82k
    njs_lexer_consume_token(parser->lexer, 1);
7079
7080
5.82k
    token = njs_lexer_token(parser->lexer, 0);
7081
5.82k
    if (token == NULL) {
7082
0
        return NJS_ERROR;
7083
0
    }
7084
7085
5.82k
    if (token->type != NJS_TOKEN_OPEN_PARENTHESIS) {
7086
280
        return njs_parser_failed(parser);
7087
280
    }
7088
7089
5.54k
    njs_lexer_consume_token(parser->lexer, 1);
7090
7091
5.54k
    var = njs_variable_function_add(parser, parser->scope, unique_id,
7092
5.54k
                                    NJS_VARIABLE_FUNCTION);
7093
5.54k
    if (var == NULL) {
7094
1.77k
        return NJS_ERROR;
7095
1.77k
    }
7096
7097
3.77k
    node->u.value.data.u.lambda = njs_variable_lambda(var);
7098
7099
3.77k
    node->left = (njs_parser_node_t *) unique_id;
7100
7101
3.77k
    parser->node = node;
7102
7103
3.77k
    ret = njs_parser_scope_begin(parser, NJS_SCOPE_FUNCTION, 1);
7104
3.77k
    if (ret != NJS_OK) {
7105
0
        return NJS_ERROR;
7106
0
    }
7107
7108
3.77k
    async = (node->token_type == NJS_TOKEN_ASYNC_FUNCTION_DECLARATION);
7109
3.77k
    parser->scope->async = async;
7110
7111
3.77k
    njs_parser_next(parser, njs_parser_function_parse);
7112
7113
3.77k
    return njs_parser_after(parser, current, node, 1,
7114
3.77k
                            njs_parser_function_declaration_after);
7115
3.77k
}
7116
7117
7118
static njs_int_t
7119
njs_parser_function_declaration_after(njs_parser_t *parser,
7120
    njs_lexer_token_t *token, njs_queue_link_t *current)
7121
2.80k
{
7122
2.80k
    njs_int_t  ret;
7123
2.80k
    uintptr_t  unique_id;
7124
7125
2.80k
    unique_id = (uintptr_t) parser->node->left;
7126
7127
2.80k
    parser->node->left = NULL;
7128
7129
2.80k
    njs_value_null_set(&parser->node->u.value);
7130
7131
2.80k
    ret = njs_parser_variable_reference(parser, parser->scope, parser->node,
7132
2.80k
                                        unique_id, NJS_DECLARATION);
7133
2.80k
    if (ret != NJS_OK) {
7134
0
        return NJS_ERROR;
7135
0
    }
7136
7137
2.80k
    return njs_parser_stack_pop(parser);
7138
2.80k
}
7139
7140
7141
static njs_int_t
7142
njs_parser_function_parse(njs_parser_t *parser, njs_lexer_token_t *token,
7143
    njs_queue_link_t *current)
7144
56.9k
{
7145
56.9k
    parser->target = parser->node;
7146
56.9k
    parser->node = NULL;
7147
7148
56.9k
    njs_parser_next(parser, njs_parser_formal_parameters);
7149
7150
56.9k
    return njs_parser_after(parser, current, parser->target, 1,
7151
56.9k
                            njs_parser_function_lambda_args_after);
7152
56.9k
}
7153
7154
7155
static const njs_lexer_entry_t njs_parser_empty_entry =
7156
{
7157
    .name = njs_str("")
7158
};
7159
7160
7161
static njs_int_t
7162
njs_parser_function_expression(njs_parser_t *parser, njs_lexer_token_t *token,
7163
    njs_queue_link_t *current)
7164
53.2k
{
7165
53.2k
    njs_int_t              ret;
7166
53.2k
    uintptr_t              unique_id;
7167
53.2k
    njs_bool_t             async;
7168
53.2k
    njs_variable_t         *var;
7169
53.2k
    njs_function_lambda_t  *lambda;
7170
7171
53.2k
    ret = njs_parser_scope_begin(parser, NJS_SCOPE_FUNCTION, 1);
7172
53.2k
    if (ret != NJS_OK) {
7173
0
        return NJS_ERROR;
7174
0
    }
7175
7176
53.2k
    async = (parser->node->token_type == NJS_TOKEN_ASYNC_FUNCTION_EXPRESSION);
7177
53.2k
    parser->scope->async = async;
7178
7179
53.2k
    var = NULL;
7180
7181
53.2k
    if (njs_lexer_token_is_binding_identifier(token)) {
7182
827
        unique_id = token->unique_id;
7183
7184
827
        njs_lexer_consume_token(parser->lexer, 1);
7185
7186
827
        token = njs_lexer_token(parser->lexer, 0);
7187
827
        if (token == NULL) {
7188
0
            return NJS_ERROR;
7189
0
        }
7190
7191
52.3k
    } else {
7192
52.3k
        unique_id = (uintptr_t) &njs_parser_empty_entry;
7193
52.3k
    }
7194
7195
53.2k
    if (token->type != NJS_TOKEN_OPEN_PARENTHESIS) {
7196
0
        return njs_parser_failed(parser);
7197
0
    }
7198
7199
53.2k
    njs_lexer_consume_token(parser->lexer, 1);
7200
7201
53.2k
    parser->node->left = njs_parser_node_new(parser, NJS_TOKEN_NAME);
7202
53.2k
    if (parser->node->left == NULL) {
7203
0
        return NJS_ERROR;
7204
0
    }
7205
7206
53.2k
    var = njs_variable_scope_add(parser, parser->scope, parser->scope,
7207
53.2k
                                 unique_id, NJS_VARIABLE_FUNCTION, 1);
7208
53.2k
    if (var == NULL) {
7209
0
        return NJS_ERROR;
7210
0
    }
7211
7212
53.2k
    var->self = 1;
7213
7214
53.2k
    ret = njs_parser_variable_reference(parser, parser->scope,
7215
53.2k
                                        parser->node->left, unique_id,
7216
53.2k
                                        NJS_DECLARATION);
7217
53.2k
    if (ret != NJS_OK) {
7218
0
        return NJS_ERROR;
7219
0
    }
7220
7221
53.2k
    lambda = njs_function_lambda_alloc(parser->vm, !async);
7222
53.2k
    if (lambda == NULL) {
7223
0
        return NJS_ERROR;
7224
0
    }
7225
7226
53.2k
    parser->node->u.value.data.u.lambda = lambda;
7227
7228
53.2k
    njs_parser_next(parser, njs_parser_function_parse);
7229
7230
53.2k
    return njs_parser_after(parser, current, var, 1,
7231
53.2k
                            njs_parser_function_expression_after);
7232
53.2k
}
7233
7234
7235
static njs_int_t
7236
njs_parser_function_expression_after(njs_parser_t *parser,
7237
    njs_lexer_token_t *token, njs_queue_link_t *current)
7238
16.4k
{
7239
16.4k
    njs_variable_t  *var;
7240
7241
16.4k
    var = (njs_variable_t *) parser->target;
7242
7243
16.4k
    if (var->self) {
7244
16.1k
        var->init = 1;
7245
16.1k
        var->type = NJS_VARIABLE_CONST;
7246
16.1k
    }
7247
7248
16.4k
    var->index = njs_scope_index(var->scope->type, var->scope->items,
7249
16.4k
                                 NJS_LEVEL_LOCAL, var->type);
7250
16.4k
    var->scope->items++;
7251
7252
16.4k
    if (var->self) {
7253
16.1k
        parser->node->u.value.data.u.lambda->self = var->index;
7254
16.1k
    }
7255
7256
16.4k
    return njs_parser_stack_pop(parser);
7257
16.4k
}
7258
7259
7260
static njs_int_t
7261
njs_parser_unique_formal_parameters(njs_parser_t *parser,
7262
    njs_lexer_token_t *token, njs_queue_link_t *current)
7263
3.80k
{
7264
3.80k
    parser->node = NULL;
7265
7266
3.80k
    njs_parser_next(parser, njs_parser_formal_parameters);
7267
7268
3.80k
    return NJS_OK;
7269
3.80k
}
7270
7271
7272
static njs_int_t
7273
njs_parser_formal_parameters(njs_parser_t *parser, njs_lexer_token_t *token,
7274
    njs_queue_link_t *current)
7275
61.2k
{
7276
61.2k
    njs_variable_t         *arg;
7277
61.2k
    njs_rbtree_node_t      *rb_node;
7278
61.2k
    njs_variable_node_t    var_node;
7279
61.2k
    njs_function_lambda_t  *lambda;
7280
7281
61.2k
    lambda = parser->target->u.value.data.u.lambda;
7282
7283
61.2k
    switch (token->type) {
7284
    /* BindingRestElement */
7285
967
    case NJS_TOKEN_ELLIPSIS:
7286
967
        if (lambda->rest_parameters != 0) {
7287
0
            return njs_parser_failed(parser);
7288
0
        }
7289
7290
967
        njs_lexer_consume_token(parser->lexer, 1);
7291
7292
967
        token = njs_lexer_token(parser->lexer, 0);
7293
967
        if (token == NULL) {
7294
0
            return NJS_ERROR;
7295
0
        }
7296
7297
967
        if (!njs_lexer_token_is_binding_identifier(token)) {
7298
519
            return njs_parser_failed(parser);
7299
519
        }
7300
7301
448
        lambda->rest_parameters = 1;
7302
7303
448
        return NJS_OK;
7304
7305
    /* BindingElement */
7306
779
    case NJS_TOKEN_OPEN_BRACE:
7307
779
        return njs_parser_not_supported(parser, token);
7308
7309
0
    case NJS_TOKEN_OPEN_BRACKET:
7310
0
        return njs_parser_not_supported(parser, token);
7311
7312
59.5k
    default:
7313
        /* SingleNameBinding */
7314
59.5k
        if (njs_lexer_token_is_binding_identifier(token)) {
7315
3.44k
            var_node.key = token->unique_id;
7316
7317
3.44k
            rb_node = njs_rbtree_find(&parser->scope->variables,
7318
3.44k
                                      &var_node.node);
7319
3.44k
            if (rb_node != NULL) {
7320
20
                arg = ((njs_variable_node_t *) rb_node)->variable;
7321
7322
20
                if (!arg->self) {
7323
0
                    njs_parser_syntax_error(parser,
7324
0
                                            "Duplicate parameter names");
7325
0
                    return NJS_DONE;
7326
0
                }
7327
7328
20
                arg->self = 0;
7329
7330
3.42k
            } else {
7331
3.42k
                arg = njs_variable_add(parser, parser->scope,
7332
3.42k
                                       token->unique_id, NJS_VARIABLE_VAR);
7333
3.42k
            }
7334
7335
3.44k
            if (arg == NULL) {
7336
0
                return NJS_ERROR;
7337
0
            }
7338
7339
3.44k
            arg->argument = 1;
7340
7341
3.44k
            lambda->nargs++;
7342
7343
            /* Crutch for temporary storage. */
7344
3.44k
            parser->node = (njs_parser_node_t *) arg;
7345
7346
3.44k
            njs_lexer_consume_token(parser->lexer, 1);
7347
7348
3.44k
            njs_parser_next(parser, njs_parser_formal_parameters_after);
7349
3.44k
            break;
7350
3.44k
        }
7351
7352
56.0k
        return njs_parser_stack_pop(parser);
7353
61.2k
    }
7354
7355
3.44k
    return NJS_OK;
7356
61.2k
}
7357
7358
7359
static njs_int_t
7360
njs_parser_formal_parameters_after(njs_parser_t *parser,
7361
    njs_lexer_token_t *token, njs_queue_link_t *current)
7362
3.44k
{
7363
3.44k
    njs_function_lambda_t  *lambda;
7364
7365
3.44k
    if (token->type != NJS_TOKEN_COMMA) {
7366
2.97k
        return njs_parser_stack_pop(parser);
7367
2.97k
    }
7368
7369
475
    lambda = parser->target->u.value.data.u.lambda;
7370
7371
475
    if (lambda->rest_parameters) {
7372
448
        njs_parser_syntax_error(parser, "Rest parameter must be "
7373
448
                                        "last formal parameter");
7374
448
        return NJS_DONE;
7375
448
    }
7376
7377
27
    njs_lexer_consume_token(parser->lexer, 1);
7378
7379
27
    njs_parser_next(parser, njs_parser_formal_parameters);
7380
7381
27
    return NJS_OK;
7382
475
}
7383
7384
7385
/*
7386
 * 14.2 Arrow Function Definitions
7387
 *
7388
 * TODO: implement according to specification.
7389
 */
7390
static njs_int_t
7391
njs_parser_arrow_function(njs_parser_t *parser, njs_lexer_token_t *token,
7392
    njs_queue_link_t *current)
7393
35.2k
{
7394
35.2k
    njs_int_t              ret;
7395
35.2k
    uintptr_t              unique_id;
7396
35.2k
    njs_bool_t             async;
7397
35.2k
    njs_variable_t         *arg, *var;
7398
35.2k
    njs_parser_node_t      *node, *name;
7399
35.2k
    njs_function_lambda_t  *lambda;
7400
7401
35.2k
    if (token->type == NJS_TOKEN_ASYNC) {
7402
369
        njs_lexer_consume_token(parser->lexer, 1);
7403
7404
369
        token = njs_lexer_token(parser->lexer, 0);
7405
369
        if (token == NULL) {
7406
0
            return NJS_ERROR;
7407
0
        }
7408
7409
369
        async = 1;
7410
369
        node = njs_parser_node_new(parser, NJS_TOKEN_ASYNC_FUNCTION_EXPRESSION);
7411
7412
34.8k
    } else {
7413
34.8k
        async = 0;
7414
34.8k
        node = njs_parser_node_new(parser, NJS_TOKEN_FUNCTION_EXPRESSION);
7415
34.8k
    }
7416
7417
35.2k
    if (node == NULL) {
7418
0
        return NJS_ERROR;
7419
0
    }
7420
7421
35.2k
    node->token_line = token->line;
7422
35.2k
    parser->node = node;
7423
7424
35.2k
    ret = njs_parser_scope_begin(parser, NJS_SCOPE_FUNCTION, 0);
7425
35.2k
    if (ret != NJS_OK) {
7426
0
        return NJS_ERROR;
7427
0
    }
7428
7429
35.2k
    parser->scope->async = async;
7430
7431
35.2k
    name = njs_parser_node_new(parser, NJS_TOKEN_NAME);
7432
35.2k
    if (name == NULL) {
7433
0
        return NJS_ERROR;
7434
0
    }
7435
7436
35.2k
    node->left = name;
7437
7438
35.2k
    unique_id = (uintptr_t) &njs_parser_empty_entry;
7439
7440
35.2k
    var = njs_variable_scope_add(parser, parser->scope, parser->scope,
7441
35.2k
                                 unique_id, NJS_VARIABLE_FUNCTION, 1);
7442
35.2k
    if (var == NULL) {
7443
0
        return NJS_ERROR;
7444
0
    }
7445
7446
35.2k
    ret = njs_parser_variable_reference(parser, parser->scope, node->left,
7447
35.2k
                                        unique_id, NJS_DECLARATION);
7448
35.2k
    if (ret != NJS_OK) {
7449
0
        return NJS_ERROR;
7450
0
    }
7451
7452
35.2k
    node->left->u.reference.variable = var;
7453
7454
35.2k
    lambda = njs_function_lambda_alloc(parser->vm, 0);
7455
35.2k
    if (lambda == NULL) {
7456
0
        return NJS_ERROR;
7457
0
    }
7458
7459
35.2k
    node->u.value.data.u.lambda = lambda;
7460
7461
35.2k
    parser->scope->arrow_function = 1;
7462
7463
35.2k
    if (token->type == NJS_TOKEN_OPEN_PARENTHESIS) {
7464
8
        njs_lexer_consume_token(parser->lexer, 1);
7465
7466
8
        parser->node = NULL;
7467
8
        parser->target = node;
7468
7469
8
        njs_parser_next(parser, njs_parser_formal_parameters);
7470
7471
8
        return njs_parser_after(parser, current, node, 1,
7472
8
                                njs_parser_arrow_function_args_after);
7473
7474
35.2k
    } else if (njs_lexer_token_is_binding_identifier(token)) {
7475
35.2k
        arg = njs_variable_add(parser, parser->scope, token->unique_id,
7476
35.2k
                               NJS_VARIABLE_VAR);
7477
35.2k
        if (arg == NULL) {
7478
0
            return NJS_ERROR;
7479
0
        }
7480
7481
35.2k
        arg->argument = 1;
7482
7483
35.2k
        var->index = njs_scope_index(parser->scope->type, parser->scope->items,
7484
35.2k
                                     NJS_LEVEL_LOCAL, NJS_VARIABLE_VAR);
7485
35.2k
        parser->scope->items++;
7486
7487
35.2k
        lambda->self = var->index;
7488
35.2k
        lambda->nargs++;
7489
7490
35.2k
        njs_lexer_consume_token(parser->lexer, 1);
7491
7492
35.2k
        parser->target = node;
7493
7494
35.2k
        njs_parser_next(parser, njs_parser_arrow_function_arrow);
7495
7496
35.2k
    } else {
7497
0
        return njs_parser_failed(parser);
7498
0
    }
7499
7500
35.2k
    return NJS_OK;
7501
35.2k
}
7502
7503
7504
static njs_int_t
7505
njs_parser_arrow_function_args_after(njs_parser_t *parser,
7506
    njs_lexer_token_t *token, njs_queue_link_t *current)
7507
8
{
7508
8
    njs_variable_t  *var, **vv;
7509
7510
8
    if (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) {
7511
0
        return njs_parser_failed(parser);
7512
0
    }
7513
7514
8
    njs_lexer_consume_token(parser->lexer, 1);
7515
7516
8
    vv = &parser->target->left->u.reference.variable;
7517
7518
8
    var = *vv;
7519
8
    *vv = NULL;
7520
7521
8
    var->index = njs_scope_index(var->scope->type, var->scope->items,
7522
8
                                 NJS_LEVEL_LOCAL, NJS_VARIABLE_VAR);
7523
8
    var->scope->items++;
7524
7525
8
    parser->target->u.value.data.u.lambda->self = var->index;
7526
7527
8
    njs_parser_next(parser, njs_parser_arrow_function_arrow);
7528
7529
8
    return NJS_OK;
7530
8
}
7531
7532
7533
static njs_int_t
7534
njs_parser_arrow_function_arrow(njs_parser_t *parser,
7535
    njs_lexer_token_t *token, njs_queue_link_t *current)
7536
35.2k
{
7537
35.2k
    if (token->type != NJS_TOKEN_ARROW) {
7538
0
        return njs_parser_failed(parser);
7539
0
    }
7540
7541
35.2k
    njs_lexer_consume_token(parser->lexer, 1);
7542
7543
35.2k
    token = njs_lexer_token(parser->lexer, 0);
7544
35.2k
    if (token == NULL) {
7545
0
        return NJS_ERROR;
7546
0
    }
7547
7548
35.2k
    if (token->type == NJS_TOKEN_OPEN_BRACE) {
7549
2
        njs_lexer_consume_token(parser->lexer, 1);
7550
7551
2
        token = njs_lexer_token(parser->lexer, 0);
7552
2
        if (token == NULL) {
7553
0
            return NJS_ERROR;
7554
0
        }
7555
7556
2
        if (token->type == NJS_TOKEN_CLOSE_BRACE) {
7557
0
            parser->node = NULL;
7558
7559
0
            njs_parser_next(parser, njs_parser_function_lambda_body_after);
7560
7561
0
            return NJS_OK;
7562
0
        }
7563
7564
2
        parser->node = NULL;
7565
7566
2
        njs_parser_next(parser, njs_parser_statement_list);
7567
7568
2
        return njs_parser_after(parser, current, parser->target, 1,
7569
2
                                njs_parser_function_lambda_body_after);
7570
2
    }
7571
7572
35.2k
    parser->node = NULL;
7573
7574
35.2k
    njs_parser_next(parser, njs_parser_assignment_expression);
7575
7576
35.2k
    return njs_parser_after(parser, current, parser->target, 1,
7577
35.2k
                            njs_parser_arrow_function_body_after);
7578
35.2k
}
7579
7580
7581
static njs_int_t
7582
njs_parser_arrow_function_body_after(njs_parser_t *parser,
7583
    njs_lexer_token_t *token, njs_queue_link_t *current)
7584
35.1k
{
7585
35.1k
    njs_parser_node_t  *body;
7586
7587
35.1k
    body = njs_parser_return_set(parser, parser->node);
7588
35.1k
    if (body == NULL) {
7589
0
        return NJS_ERROR;
7590
0
    }
7591
7592
35.1k
    parser->target->right = body;
7593
35.1k
    parser->node = parser->target;
7594
7595
35.1k
    njs_parser_scope_end(parser);
7596
7597
35.1k
    return njs_parser_stack_pop(parser);
7598
35.1k
}
7599
7600
7601
/*
7602
 * 14.3 Method Definitions.
7603
 */
7604
static njs_int_t
7605
njs_parser_method_definition(njs_parser_t *parser, njs_lexer_token_t *token,
7606
    njs_queue_link_t *current)
7607
3.60k
{
7608
3.60k
    njs_token_type_t   type;
7609
3.60k
    njs_lexer_token_t  *next;
7610
3.60k
    njs_parser_node_t  *expr;
7611
7612
3.60k
    type = NJS_TOKEN_FUNCTION;
7613
7614
3.60k
    if (token->type == NJS_TOKEN_ASYNC) {
7615
0
        njs_lexer_consume_token(parser->lexer, 1);
7616
7617
0
        token = njs_lexer_token(parser->lexer, 0);
7618
0
        if (token == NULL) {
7619
0
            return NJS_ERROR;
7620
0
        }
7621
7622
0
        type = NJS_TOKEN_ASYNC_FUNCTION;
7623
0
    }
7624
7625
3.60k
    switch (token->type) {
7626
    /* PropertyName */
7627
272
    case NJS_TOKEN_STRING:
7628
272
    case NJS_TOKEN_ESCAPE_STRING:
7629
1.90k
    case NJS_TOKEN_NUMBER:
7630
1.90k
        break;
7631
7632
1.70k
    default:
7633
1.70k
        if (njs_lexer_token_is_identifier_name(token)) {
7634
1.70k
            break;
7635
1.70k
        }
7636
7637
0
        return njs_parser_failed(parser);
7638
3.60k
    }
7639
7640
3.60k
    njs_lexer_consume_token(parser->lexer, 1);
7641
7642
3.60k
    next = njs_lexer_token(parser->lexer, 0);
7643
3.60k
    if (next == NULL) {
7644
0
        return NJS_ERROR;
7645
0
    }
7646
7647
3.60k
    if (next->type != NJS_TOKEN_OPEN_PARENTHESIS) {
7648
0
        return njs_parser_failed(parser);
7649
0
    }
7650
7651
3.60k
    expr = njs_parser_node_new(parser, type);
7652
3.60k
    if (expr == NULL) {
7653
0
        return NJS_ERROR;
7654
0
    }
7655
7656
3.60k
    expr->token_line = next->line;
7657
7658
3.60k
    parser->node = expr;
7659
7660
3.60k
    njs_lexer_consume_token(parser->lexer, 1);
7661
3.60k
    njs_parser_next(parser, njs_parser_function_lambda);
7662
7663
3.60k
    return NJS_OK;
7664
3.60k
}
7665
7666
7667
static njs_int_t
7668
njs_parser_get_set(njs_parser_t *parser, njs_lexer_token_t *token,
7669
    njs_queue_link_t *current)
7670
1.50k
{
7671
1.50k
    njs_token_type_t   accessor;
7672
1.50k
    njs_lexer_token_t  *name;
7673
1.50k
    njs_parser_node_t  *property, *expression, *temp;
7674
7675
1.50k
    temp = parser->target;
7676
1.50k
    accessor = (njs_token_type_t) (uintptr_t) temp->right;
7677
7678
1.50k
    name = token;
7679
7680
1.50k
    token = njs_lexer_peek_token(parser->lexer, token, 0);
7681
1.50k
    if (token == NULL) {
7682
0
        return NJS_ERROR;
7683
0
    }
7684
7685
1.50k
    switch (token->type) {
7686
    /* IdentifierReference */
7687
0
    case NJS_TOKEN_NAME:
7688
0
    case NJS_TOKEN_STRING:
7689
1.30k
    case NJS_TOKEN_ESCAPE_STRING:
7690
1.50k
    case NJS_TOKEN_NUMBER:
7691
1.50k
        break;
7692
7693
0
    case NJS_TOKEN_OPEN_BRACKET:
7694
0
        njs_lexer_consume_token(parser->lexer, 2);
7695
7696
0
        njs_parser_next(parser, njs_parser_assignment_expression);
7697
7698
0
        return njs_parser_after(parser, current, temp, 1,
7699
1.30k
                                njs_parser_get_set_after);
7700
7701
0
    default:
7702
0
        if (njs_lexer_token_is_identifier_name(token)) {
7703
0
            break;
7704
0
        }
7705
7706
0
        return njs_parser_property_definition_ident(parser, name, temp);
7707
1.50k
    }
7708
7709
1.50k
    property = njs_parser_property_name_node(parser, token);
7710
1.50k
    if (property == NULL) {
7711
269
        return NJS_ERROR;
7712
269
    }
7713
7714
1.23k
    njs_lexer_consume_token(parser->lexer, 2);
7715
7716
1.23k
    token = njs_lexer_token(parser->lexer, 0);
7717
1.23k
    if (token == NULL) {
7718
0
        return NJS_ERROR;
7719
0
    }
7720
7721
1.23k
    if (token->type != NJS_TOKEN_OPEN_PARENTHESIS) {
7722
1.03k
        return njs_parser_failed(parser);
7723
1.03k
    }
7724
7725
195
    expression = njs_parser_node_new(parser, NJS_TOKEN_FUNCTION);
7726
195
    if (expression == NULL) {
7727
0
        return NJS_ERROR;
7728
0
    }
7729
7730
195
    expression->token_line = token->line;
7731
7732
195
    temp->right = property;
7733
7734
195
    parser->node = expression;
7735
7736
195
    njs_lexer_consume_token(parser->lexer, 1);
7737
195
    njs_parser_next(parser, njs_parser_function_lambda);
7738
7739
195
    if (accessor == NJS_TOKEN_PROPERTY_GETTER) {
7740
195
        return njs_parser_after(parser, current, temp, 1, njs_parser_get_after);
7741
195
    }
7742
7743
0
    return njs_parser_after(parser, current, temp, 1, njs_parser_set_after);
7744
195
}
7745
7746
7747
static njs_int_t
7748
njs_parser_get_set_after(njs_parser_t *parser, njs_lexer_token_t *token,
7749
    njs_queue_link_t *current)
7750
0
{
7751
0
    njs_token_type_t   accessor;
7752
0
    njs_parser_node_t  *expression, *temp;
7753
7754
0
    if (token->type != NJS_TOKEN_CLOSE_BRACKET) {
7755
0
        return njs_parser_failed(parser);
7756
0
    }
7757
7758
0
    njs_lexer_consume_token(parser->lexer, 1);
7759
7760
0
    token = njs_lexer_token(parser->lexer, 0);
7761
0
    if (token == NULL) {
7762
0
        return NJS_ERROR;
7763
0
    }
7764
7765
0
    if (token->type != NJS_TOKEN_OPEN_PARENTHESIS) {
7766
0
        return njs_parser_failed(parser);
7767
0
    }
7768
7769
0
    expression = njs_parser_node_new(parser, NJS_TOKEN_FUNCTION);
7770
0
    if (expression == NULL) {
7771
0
        return NJS_ERROR;
7772
0
    }
7773
7774
0
    expression->token_line = token->line;
7775
7776
0
    temp = parser->target;
7777
7778
0
    accessor = (njs_token_type_t) (uintptr_t) temp->right;
7779
0
    temp->right = parser->node;
7780
7781
0
    parser->node = expression;
7782
7783
0
    njs_lexer_consume_token(parser->lexer, 1);
7784
0
    njs_parser_next(parser, njs_parser_function_lambda);
7785
7786
0
    if (accessor == NJS_TOKEN_PROPERTY_GETTER) {
7787
0
        return njs_parser_after(parser, current, temp, 1, njs_parser_get_after);
7788
0
    }
7789
7790
0
    return njs_parser_after(parser, current, temp, 1, njs_parser_set_after);
7791
0
}
7792
7793
7794
static njs_int_t
7795
njs_parser_get_after(njs_parser_t *parser, njs_lexer_token_t *token,
7796
    njs_queue_link_t *current)
7797
195
{
7798
195
    njs_int_t              ret;
7799
195
    njs_parser_node_t      *expression, *temp;
7800
195
    njs_function_lambda_t  *lambda;
7801
7802
195
    temp = parser->target;
7803
7804
195
    expression = parser->node;
7805
195
    lambda = expression->u.value.data.u.lambda;
7806
7807
195
    if (lambda->nargs != 0) {
7808
0
        njs_parser_syntax_error(parser,
7809
0
                                "Getter must not have any formal parameters");
7810
0
        return NJS_DONE;
7811
0
    }
7812
7813
195
    ret = njs_parser_property_accessor(parser, temp->left, temp->right,
7814
195
                                       expression, NJS_TOKEN_PROPERTY_GETTER);
7815
195
    if (ret != NJS_OK) {
7816
0
        return NJS_ERROR;
7817
0
    }
7818
7819
195
    parser->node = temp->left;
7820
195
    parser->target = NULL;
7821
7822
195
    return njs_parser_stack_pop(parser);
7823
195
}
7824
7825
7826
static njs_int_t
7827
njs_parser_set_after(njs_parser_t *parser, njs_lexer_token_t *token,
7828
    njs_queue_link_t *current)
7829
0
{
7830
0
    njs_int_t              ret;
7831
0
    njs_parser_node_t      *expression, *temp;
7832
0
    njs_function_lambda_t  *lambda;
7833
7834
0
    temp = parser->target;
7835
7836
0
    expression = parser->node;
7837
0
    lambda = expression->u.value.data.u.lambda;
7838
7839
0
    if (lambda->nargs != 1) {
7840
0
        njs_parser_syntax_error(parser,
7841
0
                               "Setter must have exactly one formal parameter");
7842
0
        return NJS_DONE;
7843
0
    }
7844
7845
0
    ret = njs_parser_property_accessor(parser, temp->left, temp->right,
7846
0
                                       expression, NJS_TOKEN_PROPERTY_SETTER);
7847
0
    if (ret != NJS_OK) {
7848
0
        return NJS_ERROR;
7849
0
    }
7850
7851
0
    parser->node = temp->left;
7852
0
    parser->target = NULL;
7853
7854
0
    return njs_parser_stack_pop(parser);
7855
0
}
7856
7857
7858
static njs_int_t
7859
njs_parser_function_lambda(njs_parser_t *parser,
7860
    njs_lexer_token_t *token, njs_queue_link_t *current)
7861
3.80k
{
7862
3.80k
    njs_int_t              ret;
7863
3.80k
    njs_parser_node_t      *expr;
7864
3.80k
    njs_function_lambda_t  *lambda;
7865
7866
3.80k
    lambda = njs_function_lambda_alloc(parser->vm, 0);
7867
3.80k
    if (lambda == NULL) {
7868
0
        return NJS_ERROR;
7869
0
    }
7870
7871
3.80k
    expr = parser->node;
7872
3.80k
    expr->u.value.data.u.lambda = lambda;
7873
7874
3.80k
    ret = njs_parser_scope_begin(parser, NJS_SCOPE_FUNCTION, 1);
7875
3.80k
    if (ret != NJS_OK) {
7876
0
        return NJS_ERROR;
7877
0
    }
7878
7879
3.80k
    parser->scope->async =
7880
3.80k
                        (parser->node->token_type == NJS_TOKEN_ASYNC_FUNCTION);
7881
7882
3.80k
    parser->node = NULL;
7883
3.80k
    parser->target = expr;
7884
7885
3.80k
    njs_parser_next(parser, njs_parser_unique_formal_parameters);
7886
7887
3.80k
    return njs_parser_after(parser, current, expr, 1,
7888
3.80k
                            njs_parser_function_lambda_args_after);
7889
3.80k
}
7890
7891
7892
static njs_int_t
7893
njs_parser_function_lambda_args_after(njs_parser_t *parser,
7894
    njs_lexer_token_t *token, njs_queue_link_t *current)
7895
59.0k
{
7896
59.0k
    if (token->type != NJS_TOKEN_CLOSE_PARENTHESIS) {
7897
2.62k
        return njs_parser_failed(parser);
7898
2.62k
    }
7899
7900
56.4k
    njs_lexer_consume_token(parser->lexer, 1);
7901
7902
56.4k
    token = njs_lexer_token(parser->lexer, 0);
7903
56.4k
    if (token == NULL) {
7904
0
        return NJS_ERROR;
7905
0
    }
7906
7907
56.4k
    if (token->type != NJS_TOKEN_OPEN_BRACE) {
7908
273
        return njs_parser_failed(parser);
7909
273
    }
7910
7911
56.1k
    njs_lexer_consume_token(parser->lexer, 1);
7912
7913
56.1k
    token = njs_lexer_token(parser->lexer, 0);
7914
56.1k
    if (token == NULL) {
7915
0
        return NJS_ERROR;
7916
0
    }
7917
7918
56.1k
    if (token->type == NJS_TOKEN_CLOSE_BRACE) {
7919
1
        parser->node = NULL;
7920
7921
1
        njs_parser_next(parser, njs_parser_function_lambda_body_after);
7922
7923
1
        return NJS_OK;
7924
1
    }
7925
7926
56.1k
    parser->node = NULL;
7927
7928
56.1k
    njs_parser_next(parser, njs_parser_statement_list);
7929
7930
56.1k
    return njs_parser_after(parser, current, parser->target, 1,
7931
56.1k
                            njs_parser_function_lambda_body_after);
7932
56.1k
}
7933
7934
7935
static njs_int_t
7936
njs_parser_function_lambda_body_after(njs_parser_t *parser,
7937
    njs_lexer_token_t *token, njs_queue_link_t *current)
7938
24.1k
{
7939
24.1k
    njs_parser_node_t *body, *last, *parent;
7940
7941
24.1k
    if (token->type != NJS_TOKEN_CLOSE_BRACE) {
7942
1.93k
        return njs_parser_failed(parser);
7943
1.93k
    }
7944
7945
22.2k
    parent = parser->target;
7946
7947
22.2k
    last = NULL;
7948
22.2k
    body = njs_parser_chain_top(parser);
7949
7950
22.2k
    if (body != NULL) {
7951
        /* Take the last function body statement. */
7952
22.2k
        last = body->right;
7953
7954
22.2k
        if (last == NULL) {
7955
            /*
7956
             * The last statement is terminated by semicolon.
7957
             * Take the last statement itself.
7958
             */
7959
0
            last = body->left;
7960
0
        }
7961
22.2k
    }
7962
7963
22.2k
    if (last == NULL || last->token_type != NJS_TOKEN_RETURN) {
7964
        /*
7965
         * There is no function body or the last function body
7966
         * body statement is not "return" statement.
7967
         */
7968
22.1k
        body = njs_parser_return_set(parser, NULL);
7969
22.1k
        if (body == NULL) {
7970
0
            return NJS_ERROR;
7971
0
        }
7972
7973
22.1k
        body->right->token_line = token->line;
7974
22.1k
    }
7975
7976
22.2k
    parent->right = body;
7977
22.2k
    parser->node = parent;
7978
7979
22.2k
    njs_parser_scope_end(parser);
7980
7981
22.2k
    njs_lexer_consume_token(parser->lexer, 1);
7982
7983
22.2k
    return njs_parser_stack_pop(parser);
7984
22.2k
}
7985
7986
7987
static njs_int_t
7988
njs_parser_export(njs_parser_t *parser, njs_lexer_token_t *token,
7989
    njs_queue_link_t *current)
7990
0
{
7991
0
    njs_parser_node_t  *node;
7992
0
    njs_lexer_token_t  *peek;
7993
7994
0
    static const njs_str_t  as_string = njs_str("as");
7995
7996
0
    if (!parser->module) {
7997
0
        njs_parser_syntax_error(parser, "Illegal export statement");
7998
0
        return NJS_DONE;
7999
0
    }
8000
8001
0
    if (token->type != NJS_TOKEN_DEFAULT) {
8002
8003
0
        if (token->type != NJS_TOKEN_OPEN_BRACE) {
8004
0
            njs_parser_syntax_error(parser,
8005
0
                                    "Non-default export is not supported");
8006
0
            return NJS_DONE;
8007
0
        }
8008
8009
        /*
8010
         * 'export {'
8011
         *    supported only: export {identifier as default};
8012
         */
8013
8014
0
        njs_lexer_consume_token(parser->lexer, 1);
8015
8016
0
        token = njs_lexer_token(parser->lexer, 0);
8017
0
        if (njs_slow_path(token == NULL)) {
8018
0
            return NJS_ERROR;
8019
0
        }
8020
8021
0
        if (token->type != NJS_TOKEN_NAME) {
8022
0
            njs_parser_syntax_error(parser, "Identifier expected");
8023
0
            return NJS_DONE;
8024
0
        }
8025
8026
0
        peek = njs_lexer_peek_token(parser->lexer, token, 0);
8027
0
        if (njs_slow_path(peek == NULL)) {
8028
0
            return NJS_ERROR;
8029
0
        }
8030
8031
0
        if (peek->type != NJS_TOKEN_NAME ||
8032
0
            !njs_strstr_eq(&peek->text, &as_string))
8033
0
        {
8034
0
            njs_parser_syntax_error(parser, "'as' expected");
8035
0
            return NJS_DONE;
8036
0
        }
8037
8038
0
        peek = njs_lexer_peek_token(parser->lexer, peek, 0);
8039
0
        if (njs_slow_path(peek == NULL)) {
8040
0
            return NJS_ERROR;
8041
0
        }
8042
8043
0
        if (peek->type != NJS_TOKEN_DEFAULT) {
8044
0
            njs_parser_syntax_error(parser,
8045
0
                                    "Non-default export is not supported");
8046
0
            return NJS_DONE;
8047
0
        }
8048
8049
0
        peek = njs_lexer_peek_token(parser->lexer, peek, 0);
8050
0
        if (njs_slow_path(peek == NULL)) {
8051
0
            return NJS_ERROR;
8052
0
        }
8053
8054
0
        if (peek->type != NJS_TOKEN_CLOSE_BRACE) {
8055
0
            njs_parser_syntax_error(parser, "Close brace is expected");
8056
0
            return NJS_DONE;
8057
0
        }
8058
8059
0
        node = njs_parser_node_new(parser, NJS_TOKEN_EXPORT);
8060
0
        if (node == NULL) {
8061
0
            return NJS_ERROR;
8062
0
        }
8063
8064
0
        node->token_line = parser->line;
8065
0
        node->right = njs_parser_reference(parser, token);
8066
0
        if (node->right == NULL) {
8067
0
            return NJS_ERROR;
8068
0
        }
8069
8070
0
        parser->node = node;
8071
8072
0
        njs_lexer_consume_token(parser->lexer, 4);
8073
8074
0
        return njs_parser_stack_pop(parser);
8075
0
    }
8076
8077
0
    njs_lexer_consume_token(parser->lexer, 1);
8078
8079
0
    node = njs_parser_node_new(parser, NJS_TOKEN_EXPORT);
8080
0
    if (node == NULL) {
8081
0
        return NJS_ERROR;
8082
0
    }
8083
8084
0
    node->token_line = parser->line;
8085
0
    parser->node = node;
8086
8087
0
    njs_parser_next(parser, njs_parser_assignment_expression);
8088
8089
0
    return njs_parser_after(parser, current, node, 1, njs_parser_export_after);
8090
0
}
8091
8092
8093
static njs_int_t
8094
njs_parser_export_after(njs_parser_t *parser, njs_lexer_token_t *token,
8095
    njs_queue_link_t *current)
8096
0
{
8097
0
    if (njs_parser_expect_semicolon(parser, token) != NJS_OK) {
8098
0
        return njs_parser_failed(parser);
8099
0
    }
8100
8101
0
    parser->target->right = parser->node;
8102
0
    parser->node = parser->target;
8103
8104
0
    return njs_parser_stack_pop(parser);
8105
0
}
8106
8107
8108
static njs_mod_t *
8109
njs_parser_module(njs_parser_t *parser, njs_str_t *name)
8110
0
{
8111
0
    njs_vm_t   *vm;
8112
0
    njs_mod_t  *module;
8113
8114
0
    vm = parser->vm;
8115
8116
0
    if (name->length == 0) {
8117
0
        njs_parser_syntax_error(parser, "Cannot find module \"%V\"", name);
8118
0
        return NULL;
8119
0
    }
8120
8121
0
    module = njs_module_find(vm, name, 1);
8122
0
    if (module != NULL) {
8123
0
        goto done;
8124
0
    }
8125
8126
0
    if (vm->module_loader == NULL) {
8127
0
        njs_parser_syntax_error(parser, "Cannot load module \"%V\"", name);
8128
0
        return NULL;
8129
0
    }
8130
8131
0
    module = vm->module_loader(vm, vm->module_loader_opaque, name);
8132
0
    if (module == NULL) {
8133
0
        njs_parser_syntax_error(parser, "Cannot find module \"%V\"", name);
8134
0
        return NULL;
8135
0
    }
8136
8137
0
done:
8138
8139
0
    if (module->index == 0) {
8140
0
        module->index = vm->shared->module_items++;
8141
0
    }
8142
8143
0
    return module;
8144
0
}
8145
8146
8147
static njs_int_t
8148
njs_parser_import(njs_parser_t *parser, njs_lexer_token_t *token,
8149
    njs_queue_link_t *current)
8150
259
{
8151
259
    njs_variable_t     *var;
8152
259
    njs_parser_node_t  *name, *import;
8153
8154
259
    if (parser->scope->parent != NULL) {
8155
259
        njs_parser_syntax_error(parser, "Illegal import statement");
8156
259
        return NJS_DONE;
8157
259
    }
8158
8159
0
    if (token->type == NJS_TOKEN_MULTIPLICATION
8160
0
        || token->type == NJS_TOKEN_OPEN_BRACE
8161
0
        || token->type == NJS_TOKEN_STRING)
8162
0
    {
8163
0
        njs_parser_syntax_error(parser, "Non-default import is not supported");
8164
0
        return NJS_DONE;
8165
0
    }
8166
8167
0
    if (token->type != NJS_TOKEN_NAME) {
8168
0
        return njs_parser_failed(parser);
8169
0
     }
8170
8171
0
    name = njs_parser_variable_node(parser, token->unique_id, NJS_VARIABLE_LET,
8172
0
                                    &var);
8173
0
    if (name == NULL) {
8174
0
        return NJS_ERROR;
8175
0
    }
8176
8177
0
    var->init = 1;
8178
8179
0
    name->token_line = token->line;
8180
8181
0
    njs_lexer_consume_token(parser->lexer, 1);
8182
8183
0
    token = njs_lexer_token(parser->lexer, 0);
8184
0
    if (token == NULL) {
8185
0
        return NJS_ERROR;
8186
0
    }
8187
8188
0
    if (token->type != NJS_TOKEN_FROM) {
8189
0
        return njs_parser_failed(parser);
8190
0
    }
8191
8192
0
    njs_lexer_consume_token(parser->lexer, 1);
8193
8194
0
    token = njs_lexer_token(parser->lexer, 0);
8195
0
    if (token == NULL) {
8196
0
        return NJS_ERROR;
8197
0
    }
8198
8199
0
    if (token->type != NJS_TOKEN_STRING) {
8200
0
        return njs_parser_failed(parser);
8201
0
    }
8202
8203
0
    import = njs_parser_node_new(parser, NJS_TOKEN_IMPORT);
8204
0
    if (import == NULL) {
8205
0
        return NJS_ERROR;
8206
0
    }
8207
8208
0
    import->hoist = 1;
8209
0
    import->token_line = parser->line;
8210
0
    import->left = name;
8211
8212
0
    import->u.module = njs_parser_module(parser, &token->text);
8213
0
    if (njs_slow_path(import->u.module == NULL)) {
8214
0
        return NJS_ERROR;
8215
0
    }
8216
8217
0
    njs_lexer_consume_token(parser->lexer, 1);
8218
8219
0
    token = njs_lexer_token(parser->lexer, 0);
8220
0
    if (token == NULL) {
8221
0
        return NJS_ERROR;
8222
0
    }
8223
8224
0
    if (njs_parser_expect_semicolon(parser, token) != NJS_OK) {
8225
0
        return njs_parser_failed(parser);
8226
0
    }
8227
8228
0
    parser->node = import;
8229
8230
0
    return njs_parser_stack_pop(parser);
8231
0
}
8232
8233
8234
static njs_int_t
8235
njs_parser_export_sink(njs_parser_t *parser)
8236
0
{
8237
0
    njs_uint_t         n;
8238
0
    njs_parser_node_t  *node, *prev;
8239
8240
0
    n = 0;
8241
8242
0
    for (node = njs_parser_chain_top(parser);
8243
0
         node != NULL;
8244
0
         node = node->left)
8245
0
    {
8246
0
        if (node->right != NULL
8247
0
            && node->right->token_type == NJS_TOKEN_EXPORT)
8248
0
        {
8249
0
            n++;
8250
0
        }
8251
0
    }
8252
8253
0
    if (n != 1) {
8254
0
        njs_parser_syntax_error(parser,
8255
0
             (n == 0) ? "export statement is required"
8256
0
                      : "Identifier \"default\" has already been declared");
8257
0
        return NJS_ERROR;
8258
0
    }
8259
8260
0
    node = njs_parser_chain_top(parser);
8261
8262
0
    if (node->right && node->right->token_type == NJS_TOKEN_EXPORT) {
8263
0
        return NJS_OK;
8264
0
    }
8265
8266
0
    prev = njs_parser_chain_top(parser);
8267
8268
0
    while (prev->left != NULL) {
8269
0
        node = prev->left;
8270
8271
0
        if (node->right != NULL
8272
0
            && node->right->token_type == NJS_TOKEN_EXPORT)
8273
0
        {
8274
0
            prev->left = node->left;
8275
0
            break;
8276
0
        }
8277
8278
0
        prev = prev->left;
8279
0
    }
8280
8281
0
    node->left = njs_parser_chain_top(parser);
8282
0
    njs_parser_chain_top_set(parser, node);
8283
8284
0
    return NJS_OK;
8285
0
}
8286
8287
8288
static njs_parser_node_t *
8289
njs_parser_return_set(njs_parser_t *parser, njs_parser_node_t *expr)
8290
57.3k
{
8291
57.3k
    njs_parser_node_t  *stmt, *node;
8292
8293
57.3k
    node = njs_parser_node_new(parser, NJS_TOKEN_RETURN);
8294
57.3k
    if (njs_slow_path(node == NULL)) {
8295
0
        return NULL;
8296
0
    }
8297
8298
57.3k
    if (expr != NULL) {
8299
35.1k
        node->token_line = expr->token_line;
8300
35.1k
    }
8301
8302
57.3k
    node->right = expr;
8303
8304
57.3k
    stmt = njs_parser_node_new(parser, NJS_TOKEN_STATEMENT);
8305
57.3k
    if (njs_slow_path(stmt == NULL)) {
8306
0
        return NULL;
8307
0
    }
8308
8309
57.3k
    stmt->left = njs_parser_chain_top(parser);
8310
57.3k
    stmt->right = node;
8311
8312
57.3k
    njs_parser_chain_top_set(parser, stmt);
8313
8314
57.3k
    return stmt;
8315
57.3k
}
8316
8317
8318
static njs_parser_node_t *
8319
njs_parser_variable_node(njs_parser_t *parser, uintptr_t unique_id,
8320
    njs_variable_type_t type, njs_variable_t  **retvar)
8321
26.9k
{
8322
26.9k
    njs_int_t          ret;
8323
26.9k
    njs_variable_t     *var;
8324
26.9k
    njs_parser_node_t  *node;
8325
8326
26.9k
    var = njs_variable_add(parser, parser->scope, unique_id, type);
8327
26.9k
    if (njs_slow_path(var == NULL)) {
8328
0
        return NULL;
8329
0
    }
8330
8331
26.9k
    if (retvar != NULL) {
8332
13.1k
        *retvar = var;
8333
13.1k
    }
8334
8335
26.9k
    node = njs_parser_node_new(parser, NJS_TOKEN_NAME);
8336
26.9k
    if (njs_slow_path(node == NULL)) {
8337
0
        return NULL;
8338
0
    }
8339
8340
26.9k
    ret = njs_parser_variable_reference(parser, parser->scope, node, unique_id,
8341
26.9k
                                        NJS_DECLARATION);
8342
26.9k
    if (njs_slow_path(ret != NJS_OK)) {
8343
0
        return NULL;
8344
0
    }
8345
8346
26.9k
    return node;
8347
26.9k
}
8348
8349
8350
static njs_parser_node_t *
8351
njs_parser_reference(njs_parser_t *parser, njs_lexer_token_t *token)
8352
514k
{
8353
514k
    njs_int_t                        ret;
8354
514k
    njs_index_t                      index;
8355
514k
    njs_variable_t                   *var;
8356
514k
    njs_parser_node_t                *node;
8357
514k
    njs_parser_scope_t               *scope;
8358
514k
    const njs_lexer_keyword_entry_t  *keyword;
8359
8360
514k
    static const njs_str_t  njs_undefined_str = njs_str("undefined");
8361
8362
514k
    node = njs_parser_node_new(parser, token->type);
8363
514k
    if (njs_slow_path(node == NULL)) {
8364
0
        return NULL;
8365
0
    }
8366
8367
514k
    switch (token->type) {
8368
8369
7
    case NJS_TOKEN_NULL:
8370
7
        njs_thread_log_debug("JS: null");
8371
7
        break;
8372
8373
1.07k
    case NJS_TOKEN_THIS:
8374
1.07k
        njs_thread_log_debug("JS: this");
8375
8376
1.07k
        scope = njs_function_scope(parser->scope);
8377
1.07k
        if (njs_slow_path(scope == NULL)) {
8378
0
            njs_parser_syntax_error(parser,
8379
0
                                    "function or global scope not found");
8380
0
            return NULL;
8381
0
        }
8382
8383
1.07k
        if (parser->vm->options.module) {
8384
0
            keyword = njs_lexer_keyword(njs_undefined_str.start,
8385
0
                                        njs_undefined_str.length);
8386
0
            if (njs_slow_path(keyword == NULL)) {
8387
0
                return NULL;
8388
0
            }
8389
8390
0
            token->unique_id = (uintptr_t) keyword->value;
8391
8392
1.07k
        } else if (!scope->arrow_function) {
8393
690
            index = njs_scope_index(scope->type, 0, NJS_LEVEL_LOCAL,
8394
690
                                    NJS_VARIABLE_VAR);
8395
8396
690
            var = njs_variable_scope_add(parser, scope, scope, token->unique_id,
8397
690
                                         NJS_VARIABLE_VAR, index);
8398
690
            if (njs_slow_path(var == NULL)) {
8399
0
                return NULL;
8400
0
            }
8401
690
        }
8402
8403
1.07k
        node->token_type = NJS_TOKEN_THIS;
8404
1.07k
        node->token_line = token->line;
8405
8406
1.07k
        ret = njs_parser_variable_reference(parser, parser->scope, node,
8407
1.07k
                                            token->unique_id, NJS_REFERENCE);
8408
1.07k
        if (njs_slow_path(ret != NJS_OK)) {
8409
0
            return NULL;
8410
0
        }
8411
8412
1.07k
        break;
8413
8414
1.07k
    case NJS_TOKEN_ARGUMENTS:
8415
441
        njs_thread_log_debug("JS: arguments");
8416
8417
441
        scope = njs_function_scope(parser->scope);
8418
8419
451
        while (scope->arrow_function) {
8420
10
            scope = njs_function_scope(scope->parent);
8421
10
        }
8422
8423
441
        if (scope->parent == NULL) {
8424
267
            njs_parser_syntax_error(parser, "\"%V\" object in global scope",
8425
267
                                    &token->text);
8426
267
            return NULL;
8427
267
        }
8428
8429
174
        node->token_line = token->line;
8430
8431
174
        ret = njs_parser_variable_reference(parser, parser->scope, node,
8432
174
                                            token->unique_id, NJS_REFERENCE);
8433
174
        if (njs_slow_path(ret != NJS_OK)) {
8434
0
            return NULL;
8435
0
        }
8436
8437
174
        var = njs_variable_add(parser, scope, token->unique_id,
8438
174
                               NJS_VARIABLE_VAR);
8439
174
        if (njs_slow_path(var == NULL)) {
8440
0
            return NULL;
8441
0
        }
8442
8443
174
        var->arguments_object = 1;
8444
8445
174
        break;
8446
8447
512k
    default:
8448
512k
        if (token->type == NJS_TOKEN_EVAL
8449
512k
            || njs_lexer_token_is_identifier_reference(token))
8450
512k
        {
8451
512k
            njs_thread_log_debug("JS: %V", name);
8452
8453
512k
            if (token->type != NJS_TOKEN_EVAL) {
8454
511k
                node->token_type = NJS_TOKEN_NAME;
8455
511k
            }
8456
8457
512k
            node->token_line = token->line;
8458
8459
512k
            ret = njs_parser_variable_reference(parser, parser->scope, node,
8460
512k
                                               token->unique_id, NJS_REFERENCE);
8461
512k
            if (njs_slow_path(ret != NJS_OK)) {
8462
0
                return NULL;
8463
0
            }
8464
8465
512k
            break;
8466
512k
        }
8467
8468
0
        (void) njs_parser_unexpected_token(parser->vm, parser, &token->text,
8469
0
                                           token->type);
8470
0
        return NULL;
8471
514k
    }
8472
8473
513k
    return node;
8474
514k
}
8475
8476
8477
static njs_parser_node_t *
8478
njs_parser_argument(njs_parser_t *parser, njs_parser_node_t *expr,
8479
    njs_index_t index)
8480
117k
{
8481
117k
    njs_parser_node_t  *node;
8482
8483
117k
    node = njs_parser_node_new(parser, NJS_TOKEN_ARGUMENT);
8484
117k
    if (njs_slow_path(node == NULL)) {
8485
0
        return NULL;
8486
0
    }
8487
8488
117k
    node->token_line = expr->token_line;
8489
117k
    node->index = index;
8490
8491
117k
    node->left = expr;
8492
117k
    expr->dest = node;
8493
8494
117k
    return node;
8495
117k
}
8496
8497
8498
static njs_int_t
8499
njs_parser_object_property(njs_parser_t *parser, njs_parser_node_t *parent,
8500
    njs_parser_node_t *property, njs_parser_node_t *value,
8501
    njs_bool_t proto_init)
8502
1.15M
{
8503
1.15M
    njs_token_type_t   type;
8504
1.15M
    njs_parser_node_t  *stmt, *assign, *object, *propref;
8505
8506
1.15M
    object = njs_parser_node_new(parser, NJS_TOKEN_OBJECT_VALUE);
8507
1.15M
    if (njs_slow_path(object == NULL)) {
8508
0
        return NJS_TOKEN_ERROR;
8509
0
    }
8510
8511
1.15M
    object->token_line = value->token_line;
8512
1.15M
    object->u.object = parent;
8513
8514
1.15M
    type = proto_init ? NJS_TOKEN_PROTO_INIT : NJS_TOKEN_PROPERTY_INIT;
8515
8516
1.15M
    propref = njs_parser_node_new(parser, type);
8517
1.15M
    if (njs_slow_path(propref == NULL)) {
8518
0
        return NJS_ERROR;
8519
0
    }
8520
8521
1.15M
    propref->token_line = value->token_line;
8522
1.15M
    propref->left = object;
8523
1.15M
    propref->right = property;
8524
8525
1.15M
    assign = njs_parser_node_new(parser, NJS_TOKEN_ASSIGNMENT);
8526
1.15M
    if (njs_slow_path(assign == NULL)) {
8527
0
        return NJS_ERROR;
8528
0
    }
8529
8530
1.15M
    assign->token_line = value->token_line;
8531
1.15M
    assign->u.operation = NJS_VMCODE_MOVE;
8532
1.15M
    assign->left = propref;
8533
1.15M
    assign->right = value;
8534
8535
1.15M
    stmt = njs_parser_node_new(parser, NJS_TOKEN_STATEMENT);
8536
1.15M
    if (njs_slow_path(stmt == NULL)) {
8537
0
        return NJS_ERROR;
8538
0
    }
8539
8540
1.15M
    stmt->right = assign;
8541
1.15M
    stmt->left = parent->left;
8542
1.15M
    parent->left = stmt;
8543
8544
1.15M
    return NJS_OK;
8545
1.15M
}
8546
8547
8548
static njs_int_t
8549
njs_parser_property_accessor(njs_parser_t *parser, njs_parser_node_t *parent,
8550
    njs_parser_node_t *property, njs_parser_node_t *value,
8551
    njs_token_type_t accessor)
8552
195
{
8553
195
    njs_parser_node_t  *node, *stmt, *object, *propref;
8554
8555
195
    object = njs_parser_node_new(parser, NJS_TOKEN_OBJECT_VALUE);
8556
195
    if (njs_slow_path(object == NULL)) {
8557
0
        return NJS_TOKEN_ERROR;
8558
0
    }
8559
8560
195
    object->token_line = value->token_line;
8561
195
    object->u.object = parent;
8562
8563
195
    propref = njs_parser_node_new(parser, 0);
8564
195
    if (njs_slow_path(propref == NULL)) {
8565
0
        return NJS_ERROR;
8566
0
    }
8567
8568
195
    propref->left = object;
8569
195
    propref->right = property;
8570
8571
195
    node = njs_parser_node_new(parser, accessor);
8572
195
    if (njs_slow_path(node == NULL)) {
8573
0
        return NJS_ERROR;
8574
0
    }
8575
8576
195
    node->token_line = value->token_line;
8577
195
    node->left = propref;
8578
195
    node->right = value;
8579
8580
195
    stmt = njs_parser_node_new(parser, NJS_TOKEN_STATEMENT);
8581
195
    if (njs_slow_path(stmt == NULL)) {
8582
0
        return NJS_ERROR;
8583
0
    }
8584
8585
195
    stmt->right = node;
8586
195
    stmt->left = parent->left;
8587
195
    parent->left = stmt;
8588
8589
195
    return NJS_OK;
8590
195
}
8591
8592
8593
static njs_int_t
8594
njs_parser_array_item(njs_parser_t *parser, njs_parser_node_t *array,
8595
    njs_parser_node_t *value)
8596
1.14M
{
8597
1.14M
    njs_int_t          ret;
8598
1.14M
    njs_parser_node_t  *number;
8599
8600
1.14M
    number = njs_parser_node_new(parser, NJS_TOKEN_NUMBER);
8601
1.14M
    if (njs_slow_path(number == NULL)) {
8602
0
        return NJS_ERROR;
8603
0
    }
8604
8605
1.14M
    njs_set_number(&number->u.value, array->u.length);
8606
8607
1.14M
    number->token_line = value->token_line;
8608
8609
1.14M
    ret = njs_parser_object_property(parser, array, number, value, 0);
8610
1.14M
    if (njs_slow_path(ret != NJS_OK)) {
8611
0
        return NJS_ERROR;
8612
0
    }
8613
8614
1.14M
    array->ctor = 0;
8615
1.14M
    array->u.length++;
8616
8617
1.14M
    return NJS_OK;
8618
1.14M
}
8619
8620
8621
static njs_int_t
8622
njs_parser_template_string(njs_parser_t *parser, njs_lexer_token_t *token)
8623
121k
{
8624
121k
    u_char             *p, c;
8625
121k
    njs_int_t          ret;
8626
121k
    njs_str_t          *text;
8627
121k
    njs_bool_t         escape;
8628
121k
    njs_lexer_t        *lexer;
8629
121k
    njs_parser_node_t  *node;
8630
8631
121k
    lexer = parser->lexer;
8632
121k
    text = &token->text;
8633
8634
121k
    escape = 0;
8635
121k
    p = text->start;
8636
8637
121k
    if (p == NULL) {
8638
0
        return NJS_ERROR;
8639
0
    }
8640
8641
1.32M
    while (p < lexer->end) {
8642
8643
1.32M
        c = *p++;
8644
8645
1.32M
        switch (c) {
8646
11.9k
        case '\\':
8647
11.9k
            if (p == lexer->end) {
8648
0
                return NJS_ERROR;
8649
0
            }
8650
8651
11.9k
            p++;
8652
11.9k
            escape = 1;
8653
8654
11.9k
            continue;
8655
8656
118k
        case '`':
8657
118k
            text->length = p - text->start - 1;
8658
118k
            goto done;
8659
8660
9.55k
        case '$':
8661
9.55k
            if (p < lexer->end && *p == '{') {
8662
3.04k
                p++;
8663
3.04k
                text->length = p - text->start - 2;
8664
8665
3.04k
                ret = njs_lexer_in_stack_push(lexer);
8666
3.04k
                if (njs_slow_path(ret != NJS_OK)) {
8667
0
                    return NJS_ERROR;
8668
0
                }
8669
8670
3.04k
                goto done;
8671
3.04k
            }
8672
8673
6.50k
            break;
8674
8675
65.4k
        case '\n':
8676
65.4k
            parser->lexer->line++;
8677
65.4k
            break;
8678
1.32M
        }
8679
1.32M
    }
8680
8681
1
    return NJS_ERROR;
8682
8683
121k
done:
8684
8685
121k
    node = njs_parser_node_new(parser, NJS_TOKEN_STRING);
8686
121k
    if (njs_slow_path(node == NULL)) {
8687
0
        return NJS_ERROR;
8688
0
    }
8689
8690
121k
    node->token_line = token->line;
8691
8692
121k
    if (escape) {
8693
1.64k
        ret = njs_parser_escape_string_create(parser, token, &node->u.value);
8694
1.64k
        if (njs_slow_path(ret != NJS_TOKEN_STRING)) {
8695
2
            return NJS_ERROR;
8696
2
        }
8697
8698
120k
    } else {
8699
120k
        ret = njs_parser_string_create(parser->vm, token, &node->u.value);
8700
120k
        if (njs_slow_path(ret != NJS_OK)) {
8701
0
            return NJS_ERROR;
8702
0
        }
8703
120k
    }
8704
8705
121k
    lexer->start = p;
8706
121k
    parser->node = node;
8707
8708
121k
    return c == '`' ? NJS_DONE : NJS_OK;
8709
121k
}
8710
8711
8712
njs_int_t
8713
njs_parser_string_create(njs_vm_t *vm, njs_lexer_token_t *token,
8714
    njs_value_t *value)
8715
161k
{
8716
161k
    size_t     length;
8717
161k
    njs_str_t  dst;
8718
8719
161k
    length = njs_decode_utf8_length(&token->text, &dst.length);
8720
161k
    dst.start = njs_string_alloc(vm, value, dst.length, length);
8721
161k
    if (njs_slow_path(dst.start == NULL)) {
8722
0
        return NJS_ERROR;
8723
0
    }
8724
8725
161k
    njs_decode_utf8(&dst, &token->text);
8726
8727
161k
    if (length > NJS_STRING_MAP_STRIDE && dst.length != length) {
8728
3.58k
        njs_string_utf8_offset_map_init(value->long_string.data->start,
8729
3.58k
                                        dst.length);
8730
3.58k
    }
8731
8732
161k
    return NJS_OK;
8733
161k
}
8734
8735
8736
static njs_token_type_t
8737
njs_parser_escape_string_create(njs_parser_t *parser, njs_lexer_token_t *token,
8738
    njs_value_t *value)
8739
4.99k
{
8740
4.99k
    u_char                c, *start, *dst;
8741
4.99k
    size_t                size, length, hex_length;
8742
4.99k
    uint64_t              cp, cp_pair;
8743
4.99k
    njs_int_t             ret;
8744
4.99k
    njs_str_t             *string;
8745
4.99k
    const u_char          *src, *end, *hex_end;
8746
4.99k
    njs_unicode_decode_t  ctx;
8747
8748
4.99k
    ret = njs_parser_escape_string_calc_length(parser, token, &size, &length);
8749
4.99k
    if (njs_slow_path(ret != NJS_OK)) {
8750
1.63k
        return NJS_TOKEN_ILLEGAL;
8751
1.63k
    }
8752
8753
3.36k
    start = njs_string_alloc(parser->vm, value, size, length);
8754
3.36k
    if (njs_slow_path(start == NULL)) {
8755
0
        return NJS_TOKEN_ERROR;
8756
0
    }
8757
8758
3.36k
    dst = start;
8759
3.36k
    cp_pair = 0;
8760
8761
3.36k
    string = &token->text;
8762
3.36k
    src = string->start;
8763
3.36k
    end = src + string->length;
8764
8765
771k
    while (src < end) {
8766
768k
        c = *src++;
8767
8768
768k
        if (c == '\\') {
8769
            /*
8770
             * Testing "src == end" is not required here
8771
             * since this has been already tested by lexer.
8772
             */
8773
8774
25.9k
            c = *src++;
8775
8776
25.9k
            switch (c) {
8777
243
            case 'u':
8778
                /*
8779
                 * A character after "u" can be safely tested here
8780
                 * because there is always a closing quote at the
8781
                 * end of string: ...\u".
8782
                 */
8783
8784
243
                if (*src != '{') {
8785
243
                    hex_length = 4;
8786
243
                    goto hex_length;
8787
243
                }
8788
8789
0
                src++;
8790
0
                hex_length = 0;
8791
0
                hex_end = end;
8792
8793
0
                goto hex;
8794
8795
0
            case 'x':
8796
0
                hex_length = 2;
8797
0
                goto hex_length;
8798
8799
254
            case '0':
8800
254
                c = '\0';
8801
254
                break;
8802
8803
281
            case '1':
8804
406
            case '2':
8805
458
            case '3':
8806
478
            case '4':
8807
511
            case '5':
8808
526
            case '6':
8809
572
            case '7':
8810
572
                if (parser->node != NULL) {
8811
301
                    switch (parser->node->token_type) {
8812
301
                    case NJS_TOKEN_METHOD_CALL:
8813
301
                    case NJS_TOKEN_FUNCTION_CALL:
8814
301
                    case NJS_TOKEN_FUNCTION_EXPRESSION:
8815
301
                    case NJS_TOKEN_EVAL:
8816
301
                        goto next_char;
8817
8818
0
                    default:
8819
0
                        break;
8820
301
                    }
8821
301
                }
8822
8823
271
                njs_parser_syntax_error(parser,
8824
271
                                        "Octal escape sequences can't be used "
8825
271
                                        "in untagged template literals "
8826
271
                                        "or in strict mode code");
8827
8828
271
                return NJS_TOKEN_ILLEGAL;
8829
8830
0
            case '8':
8831
6
            case '9':
8832
6
                if (parser->node != NULL) {
8833
6
                    switch (parser->node->token_type) {
8834
6
                    case NJS_TOKEN_METHOD_CALL:
8835
6
                    case NJS_TOKEN_FUNCTION_CALL:
8836
6
                    case NJS_TOKEN_FUNCTION_EXPRESSION:
8837
6
                    case NJS_TOKEN_EVAL:
8838
6
                        goto next_char;
8839
8840
0
                    default:
8841
0
                        break;
8842
6
                    }
8843
6
                }
8844
8845
0
                njs_parser_syntax_error(parser,
8846
0
                                        "The escapes \\8 and \\9 can't be used "
8847
0
                                        "in untagged template literals "
8848
0
                                        "or in strict mode code");
8849
8850
0
                return NJS_TOKEN_ILLEGAL;
8851
8852
307
next_char:
8853
8854
307
                break;
8855
8856
121
            case 'b':
8857
121
                c = '\b';
8858
121
                break;
8859
8860
979
            case 'f':
8861
979
                c = '\f';
8862
979
                break;
8863
8864
53
            case 'n':
8865
53
                c = '\n';
8866
53
                break;
8867
8868
110
            case 'r':
8869
110
                c = '\r';
8870
110
                break;
8871
8872
4
            case 't':
8873
4
                c = '\t';
8874
4
                break;
8875
8876
43
            case 'v':
8877
43
                c = '\v';
8878
43
                break;
8879
8880
104
            case '\r':
8881
                /*
8882
                 * A character after "\r" can be safely tested here
8883
                 * because there is always a closing quote at the
8884
                 * end of string: ...\\r".
8885
                 */
8886
8887
104
                if (*src == '\n') {
8888
29
                    src++;
8889
29
                }
8890
8891
104
                continue;
8892
8893
73
            case '\n':
8894
73
                continue;
8895
8896
23.3k
            default:
8897
23.3k
                if (c >= 0x80) {
8898
1.63k
                    goto utf8_copy;
8899
1.63k
                }
8900
8901
21.7k
                break;
8902
25.9k
            }
8903
25.9k
        }
8904
8905
765k
        if (c < 0x80) {
8906
569k
            *dst++ = c;
8907
8908
569k
            continue;
8909
569k
        }
8910
8911
197k
    utf8_copy:
8912
8913
197k
        src--;
8914
8915
197k
        njs_utf8_decode_init(&ctx);
8916
8917
197k
        cp = njs_utf8_decode(&ctx, &src, end);
8918
197k
        if (cp > NJS_UNICODE_MAX_CODEPOINT) {
8919
178k
            cp = NJS_UNICODE_REPLACEMENT;
8920
178k
        }
8921
8922
197k
        dst = njs_utf8_encode(dst, cp);
8923
8924
197k
        continue;
8925
8926
243
    hex_length:
8927
8928
243
        hex_end = src + hex_length;
8929
8930
243
    hex:
8931
243
        cp = njs_number_hex_parse(&src, hex_end, 0);
8932
8933
        /* Skip '}' character. */
8934
8935
243
        if (hex_length == 0) {
8936
0
            src++;
8937
0
        }
8938
8939
243
        if (cp_pair != 0) {
8940
98
            if (njs_fast_path(njs_surrogate_trailing(cp))) {
8941
80
                cp = njs_surrogate_pair(cp_pair, cp);
8942
8943
80
            } else if (njs_slow_path(njs_surrogate_leading(cp))) {
8944
13
                cp = NJS_UNICODE_REPLACEMENT;
8945
8946
13
                dst = njs_utf8_encode(dst, (uint32_t) cp);
8947
8948
13
            } else {
8949
5
                dst = njs_utf8_encode(dst, NJS_UNICODE_REPLACEMENT);
8950
5
            }
8951
8952
98
            cp_pair = 0;
8953
8954
145
        } else if (njs_surrogate_any(cp)) {
8955
129
            if (cp <= 0xdbff && src[0] == '\\' && src[1] == 'u') {
8956
98
                cp_pair = cp;
8957
98
                continue;
8958
98
            }
8959
8960
31
            cp = NJS_UNICODE_REPLACEMENT;
8961
31
        }
8962
8963
145
        dst = njs_utf8_encode(dst, (uint32_t) cp);
8964
145
        if (njs_slow_path(dst == NULL)) {
8965
0
            njs_parser_syntax_error(parser, "Invalid Unicode code point \"%V\"",
8966
0
                                    &token->text);
8967
8968
0
            return NJS_TOKEN_ILLEGAL;
8969
0
        }
8970
145
    }
8971
8972
3.09k
    if (length > NJS_STRING_MAP_STRIDE && length != size) {
8973
1.75k
        njs_string_utf8_offset_map_init(start, size);
8974
1.75k
    }
8975
8976
3.09k
    return NJS_TOKEN_STRING;
8977
3.36k
}
8978
8979
8980
static njs_int_t
8981
njs_parser_escape_string_calc_length(njs_parser_t *parser,
8982
    njs_lexer_token_t *token, size_t *out_size, size_t *out_length)
8983
4.99k
{
8984
4.99k
    size_t                size, length, hex_length;
8985
4.99k
    uint64_t              cp, cp_pair;
8986
4.99k
    njs_str_t             *string;
8987
4.99k
    const u_char          *ptr, *src, *end, *hex_end;
8988
4.99k
    njs_unicode_decode_t  ctx;
8989
8990
4.99k
    size = 0;
8991
4.99k
    length = 0;
8992
4.99k
    cp_pair = 0;
8993
8994
4.99k
    string = &token->text;
8995
4.99k
    src = string->start;
8996
4.99k
    end = src + string->length;
8997
8998
1.04M
    while (src < end) {
8999
9000
1.04M
        if (*src == '\\') {
9001
29.9k
            src++;
9002
9003
29.9k
            switch (*src) {
9004
1.87k
            case 'u':
9005
1.87k
                src++;
9006
9007
1.87k
                if (*src != '{') {
9008
243
                    hex_length = 4;
9009
243
                    goto hex_length;
9010
243
                }
9011
9012
1.63k
                src++;
9013
1.63k
                hex_length = 0;
9014
1.63k
                hex_end = end;
9015
9016
1.63k
                goto hex;
9017
9018
0
            case 'x':
9019
0
                src++;
9020
0
                hex_length = 2;
9021
0
                goto hex_length;
9022
9023
104
            case '\r':
9024
104
                src++;
9025
9026
104
                if (*src == '\n') {
9027
29
                    src++;
9028
29
                }
9029
9030
104
                continue;
9031
9032
73
            case '\n':
9033
73
                src++;
9034
73
                continue;
9035
9036
27.9k
            default:
9037
27.9k
                break;
9038
29.9k
            }
9039
29.9k
        }
9040
9041
1.03M
        if (*src >= 0x80) {
9042
407k
            njs_utf8_decode_init(&ctx);
9043
9044
407k
            cp = njs_utf8_decode(&ctx, &src, end);
9045
407k
            if (cp > NJS_UNICODE_MAX_CODEPOINT) {
9046
178k
                cp = NJS_UNICODE_REPLACEMENT;
9047
178k
            }
9048
9049
407k
            size += njs_utf8_size(cp);
9050
407k
            length++;
9051
9052
407k
            continue;
9053
407k
        }
9054
9055
632k
        src++;
9056
632k
        size++;
9057
632k
        length++;
9058
9059
632k
        continue;
9060
9061
243
    hex_length:
9062
9063
243
        hex_end = src + hex_length;
9064
9065
243
        if (njs_slow_path(hex_end > end)) {
9066
0
            goto invalid;
9067
0
        }
9068
9069
1.87k
    hex:
9070
9071
1.87k
        ptr = src;
9072
1.87k
        cp = njs_number_hex_parse(&src, hex_end, 0);
9073
9074
1.87k
        if (hex_length != 0) {
9075
243
            if (src != hex_end) {
9076
0
                goto invalid;
9077
0
            }
9078
9079
1.63k
        } else {
9080
1.63k
            if (src == ptr || (src - ptr) > 6) {
9081
797
                goto invalid;
9082
797
            }
9083
9084
837
            if (src == end || *src++ != '}') {
9085
837
                goto invalid;
9086
837
            }
9087
837
        }
9088
9089
243
        if (cp_pair != 0) {
9090
98
            if (njs_fast_path(njs_surrogate_trailing(cp))) {
9091
80
                cp = njs_surrogate_pair(cp_pair, cp);
9092
9093
80
            } else if (njs_slow_path(njs_surrogate_leading(cp))) {
9094
13
                cp = NJS_UNICODE_REPLACEMENT;
9095
9096
13
                size += njs_utf8_size(cp);
9097
13
                length++;
9098
9099
13
            } else {
9100
5
                size += njs_utf8_size(NJS_UNICODE_REPLACEMENT);
9101
5
                length++;
9102
5
            }
9103
9104
98
            cp_pair = 0;
9105
9106
145
        } else if (njs_surrogate_any(cp)) {
9107
129
            if (cp <= 0xdbff && src[0] == '\\' && src[1] == 'u') {
9108
98
                cp_pair = cp;
9109
98
                continue;
9110
98
            }
9111
9112
31
            cp = NJS_UNICODE_REPLACEMENT;
9113
31
        }
9114
9115
145
        size += njs_utf8_size(cp);
9116
145
        length++;
9117
145
    }
9118
9119
3.36k
    *out_size = size;
9120
3.36k
    *out_length = length;
9121
9122
3.36k
    return NJS_OK;
9123
9124
1.63k
invalid:
9125
9126
1.63k
    njs_parser_syntax_error(parser, "Invalid Unicode code point \"%V\"",
9127
1.63k
                            &token->text);
9128
1.63k
    return NJS_ERROR;
9129
4.99k
}
9130
9131
9132
njs_bool_t
9133
njs_parser_has_side_effect(njs_parser_node_t *node)
9134
4.44M
{
9135
4.44M
    njs_bool_t  side_effect;
9136
9137
4.44M
    if (node == NULL) {
9138
2.41M
        return 0;
9139
2.41M
    }
9140
9141
2.03M
    if (node->token_type >= NJS_TOKEN_ASSIGNMENT
9142
2.03M
        && node->token_type <= NJS_TOKEN_LAST_ASSIGNMENT)
9143
16.3k
    {
9144
16.3k
        return 1;
9145
16.3k
    }
9146
9147
2.01M
    if (node->token_type == NJS_TOKEN_FUNCTION_CALL
9148
2.01M
        || node->token_type == NJS_TOKEN_METHOD_CALL)
9149
1.49k
    {
9150
1.49k
        return 1;
9151
1.49k
    }
9152
9153
2.01M
    side_effect = njs_parser_has_side_effect(node->left);
9154
9155
2.01M
    if (njs_fast_path(!side_effect)) {
9156
1.23M
        return njs_parser_has_side_effect(node->right);
9157
1.23M
    }
9158
9159
781k
    return side_effect;
9160
2.01M
}
9161
9162
9163
njs_int_t
9164
njs_parser_variable_reference(njs_parser_t *parser, njs_parser_scope_t *scope,
9165
    njs_parser_node_t *node, uintptr_t unique_id, njs_reference_type_t type)
9166
631k
{
9167
631k
    njs_rbtree_node_t         *rb_node;
9168
631k
    njs_variable_reference_t  *vr;
9169
631k
    njs_parser_rbtree_node_t  parse_node, *rb_parse_node;
9170
9171
631k
    vr = &node->u.reference;
9172
9173
631k
    vr->unique_id = unique_id;
9174
631k
    vr->type = type;
9175
9176
631k
    parse_node.key = unique_id;
9177
9178
631k
    rb_node = njs_rbtree_find(&scope->references, &parse_node.node);
9179
631k
    if (rb_node != NULL) {
9180
172k
        return NJS_OK;
9181
172k
    }
9182
9183
459k
    rb_parse_node = njs_mp_alloc(parser->vm->mem_pool,
9184
459k
                                 sizeof(njs_parser_rbtree_node_t));
9185
459k
    if (njs_slow_path(rb_parse_node == NULL)) {
9186
0
        return NJS_ERROR;
9187
0
    }
9188
9189
459k
    rb_parse_node->key = unique_id;
9190
459k
    rb_parse_node->index = NJS_INDEX_NONE;
9191
9192
459k
    njs_rbtree_insert(&scope->references, &rb_parse_node->node);
9193
9194
459k
    return NJS_OK;
9195
459k
}
9196
9197
9198
njs_token_type_t
9199
njs_parser_unexpected_token(njs_vm_t *vm, njs_parser_t *parser,
9200
    njs_str_t *name, njs_token_type_t type)
9201
0
{
9202
0
    if (type != NJS_TOKEN_END) {
9203
0
        njs_parser_syntax_error(parser, "Unexpected token \"%V\"", name);
9204
9205
0
    } else {
9206
0
        njs_parser_syntax_error(parser, "Unexpected end of input");
9207
0
    }
9208
9209
0
    return NJS_DONE;
9210
0
}
9211
9212
9213
static void
9214
njs_parser_error(njs_vm_t *vm, njs_object_type_t type, njs_str_t *file,
9215
    uint32_t line, const char *fmt, va_list args)
9216
37.0k
{
9217
37.0k
    size_t       width;
9218
37.0k
    u_char       msg[NJS_MAX_ERROR_STR];
9219
37.0k
    u_char       *p, *end;
9220
37.0k
    njs_int_t    ret;
9221
37.0k
    njs_value_t  value, error;
9222
9223
37.0k
    static const njs_value_t  file_name = njs_string("fileName");
9224
37.0k
    static const njs_value_t  line_number = njs_string("lineNumber");
9225
9226
37.0k
    if (njs_slow_path(vm->top_frame == NULL)) {
9227
0
        njs_vm_runtime_init(vm);
9228
0
    }
9229
9230
37.0k
    p = msg;
9231
37.0k
    end = msg + NJS_MAX_ERROR_STR;
9232
9233
37.0k
    p = njs_vsprintf(p, end, fmt, args);
9234
9235
37.0k
    width = njs_length(" in ") + file->length + NJS_INT_T_LEN;
9236
9237
37.0k
    if (p > end - width) {
9238
513
        p = end - width;
9239
513
    }
9240
9241
37.0k
    if (file->length != 0 && !vm->options.quiet) {
9242
37.0k
        p = njs_sprintf(p, end, " in %V:%uD", file, line);
9243
9244
37.0k
    } else {
9245
0
        p = njs_sprintf(p, end, " in %uD", line);
9246
0
    }
9247
9248
37.0k
    njs_error_new(vm, &error, njs_vm_proto(vm, type), msg, p - msg);
9249
9250
37.0k
    njs_set_number(&value, line);
9251
37.0k
    njs_value_property_set(vm, &error, njs_value_arg(&line_number), &value);
9252
9253
37.0k
    if (file->length != 0) {
9254
37.0k
        ret = njs_string_create(vm, &value, file->start, file->length);
9255
37.0k
        if (ret == NJS_OK) {
9256
37.0k
            njs_value_property_set(vm, &error, njs_value_arg(&file_name),
9257
37.0k
                                   &value);
9258
37.0k
        }
9259
37.0k
    }
9260
9261
37.0k
    njs_vm_throw(vm, &error);
9262
37.0k
}
9263
9264
9265
void
9266
njs_parser_lexer_error(njs_parser_t *parser, njs_object_type_t type,
9267
    const char *fmt, ...)
9268
38.5k
{
9269
38.5k
    va_list  args;
9270
9271
38.5k
    if (njs_is_error(&parser->vm->exception)) {
9272
1.77k
        return;
9273
1.77k
    }
9274
9275
36.7k
    va_start(args, fmt);
9276
36.7k
    njs_parser_error(parser->vm, type, &parser->lexer->file,
9277
36.7k
                     parser->lexer->line, fmt, args);
9278
36.7k
    va_end(args);
9279
36.7k
}
9280
9281
9282
void
9283
njs_parser_node_error(njs_vm_t *vm, njs_object_type_t type,
9284
    njs_parser_node_t *node, njs_str_t *file, const char *fmt, ...)
9285
272
{
9286
272
    va_list  args;
9287
9288
272
    va_start(args, fmt);
9289
272
    njs_parser_error(vm, type, file, node->token_line, fmt, args);
9290
272
    va_end(args);
9291
272
}
9292
9293
9294
njs_int_t
9295
njs_parser_traverse(njs_vm_t *vm, njs_parser_node_t *root, void *ctx,
9296
    njs_parser_traverse_cb_t cb)
9297
20.1k
{
9298
20.1k
    njs_int_t          ret;
9299
20.1k
    njs_arr_t          *stack;
9300
20.1k
    njs_parser_node_t  *node, **ref;
9301
9302
20.1k
    if (root == NULL) {
9303
12.1k
        return NJS_OK;
9304
12.1k
    }
9305
9306
7.97k
    stack = njs_arr_create(vm->mem_pool, 8, sizeof(njs_parser_node_t *));
9307
7.97k
    if (njs_slow_path(stack == NULL)) {
9308
0
        return NJS_ERROR;
9309
9310
0
    }
9311
9312
7.97k
    ref = njs_arr_add(stack);
9313
7.97k
    if (njs_slow_path(ref == NULL)) {
9314
0
        goto failed;
9315
0
    }
9316
9317
7.97k
    *ref = root;
9318
9319
51.0k
    while (1) {
9320
51.0k
        if (njs_arr_is_empty(stack)) {
9321
7.97k
            break;
9322
7.97k
        }
9323
9324
43.1k
        ref = njs_arr_remove_last(stack);
9325
43.1k
        node = *ref;
9326
9327
43.1k
        ret = cb(vm, node, ctx);
9328
43.1k
        if (njs_slow_path(ret != NJS_OK)) {
9329
0
            goto failed;
9330
0
        }
9331
9332
43.1k
        if (node->left != NULL) {
9333
15.6k
            ref = njs_arr_add(stack);
9334
15.6k
            if (njs_slow_path(ref == NULL)) {
9335
0
                goto failed;
9336
0
            }
9337
9338
15.6k
            *ref = node->left;
9339
15.6k
        }
9340
9341
43.1k
        if (node->right != NULL) {
9342
19.4k
            ref = njs_arr_add(stack);
9343
19.4k
            if (njs_slow_path(ref == NULL)) {
9344
0
                goto failed;
9345
0
            }
9346
9347
19.4k
            *ref = node->right;
9348
19.4k
        }
9349
43.1k
    }
9350
9351
7.97k
    njs_arr_destroy(stack);
9352
9353
7.97k
    return NJS_OK;
9354
9355
0
failed:
9356
9357
0
    njs_arr_destroy(stack);
9358
9359
0
    return NJS_ERROR;
9360
7.97k
}
9361
9362
9363
njs_int_t
9364
njs_parser_serialize_ast(njs_parser_node_t *node, njs_chb_t *chain)
9365
0
{
9366
0
    njs_int_t  ret;
9367
9368
0
    ret = NJS_OK;
9369
9370
0
    njs_parser_serialize_tree(chain, node, &ret, 0);
9371
0
    njs_chb_append_literal(chain, "\n");
9372
9373
0
    return ret;
9374
0
}
9375
9376
9377
njs_inline void
9378
njs_parser_serialize_indent(njs_chb_t *chain, size_t indent)
9379
0
{
9380
0
    size_t  i;
9381
9382
0
    for (i = 0; i < indent; i++) {
9383
0
        njs_chb_append_literal(chain, "  ");
9384
0
    }
9385
0
}
9386
9387
9388
static void
9389
njs_parser_serialize_tree(njs_chb_t *chain, njs_parser_node_t *node,
9390
    njs_int_t *ret, size_t indent)
9391
0
{
9392
0
    njs_str_t  str;
9393
9394
0
    njs_chb_append_literal(chain, "{\"name\": \"");
9395
9396
0
    *ret |= njs_parser_serialize_node(chain, node);
9397
9398
0
    njs_chb_append_literal(chain, "\",\n");
9399
0
    njs_parser_serialize_indent(chain, indent);
9400
0
    njs_chb_sprintf(chain, 32, " \"line\": %d", node->token_line);
9401
9402
0
    switch (node->token_type) {
9403
0
    case NJS_TOKEN_NUMBER:
9404
0
    case NJS_TOKEN_STRING:
9405
0
    case NJS_TOKEN_NAME:
9406
0
    case NJS_TOKEN_FUNCTION_CALL:
9407
0
        njs_chb_append_literal(chain, ",\n");
9408
0
        njs_parser_serialize_indent(chain, indent);
9409
0
        njs_chb_sprintf(chain, 32, " \"index\": \"%p\"", node->index);
9410
9411
0
        switch (node->token_type) {
9412
0
        case NJS_TOKEN_NUMBER:
9413
0
        case NJS_TOKEN_STRING:
9414
0
            njs_chb_append_literal(chain, ",\n");
9415
0
            njs_parser_serialize_indent(chain, indent);
9416
9417
0
            if (node->token_type == NJS_TOKEN_NUMBER) {
9418
0
                njs_chb_sprintf(chain, 32, " \"value\": %f",
9419
0
                                njs_number(&node->u.value));
9420
9421
0
            } else {
9422
0
                njs_string_get(&node->u.value, &str);
9423
0
                njs_chb_append_literal(chain, " \"value\": \"");
9424
0
                njs_chb_append_str(chain, &str);
9425
0
                njs_chb_append_literal(chain, "\"");
9426
0
            }
9427
9428
0
            break;
9429
9430
0
        default:
9431
0
            break;
9432
0
        }
9433
9434
0
        break;
9435
9436
0
    default:
9437
0
        break;
9438
0
    }
9439
9440
0
    if (node->left != NULL) {
9441
0
        njs_chb_append_literal(chain, ",\n");
9442
0
        njs_parser_serialize_indent(chain, indent);
9443
0
        njs_chb_append_literal(chain, " \"left\": ");
9444
9445
0
        njs_parser_serialize_tree(chain, node->left, ret, indent + 1);
9446
0
    }
9447
9448
0
    if (node->right != NULL) {
9449
0
        njs_chb_append_literal(chain, ",\n");
9450
0
        njs_parser_serialize_indent(chain, indent);
9451
0
        njs_chb_append_literal(chain, " \"right\": ");
9452
9453
0
        njs_parser_serialize_tree(chain, node->right, ret, indent + 1);
9454
0
    }
9455
9456
0
    njs_chb_append_literal(chain, "}");
9457
0
}
9458
9459
9460
static njs_int_t
9461
njs_parser_serialize_node(njs_chb_t *chain, njs_parser_node_t *node)
9462
0
{
9463
0
    const char  *name;
9464
9465
0
#define njs_token_serialize(token)                                          \
9466
0
    case token:                                                             \
9467
0
        name = &njs_stringify(token)[njs_length("NJS_TOKEN_")];             \
9468
0
        njs_chb_append(chain, name, njs_strlen(name));                      \
9469
0
        break
9470
9471
0
    switch (node->token_type) {
9472
0
    njs_token_serialize(NJS_TOKEN_END);
9473
    /* FIXME: NJS_TOKEN_ILLEGAL should not be present in AST */
9474
0
    njs_token_serialize(NJS_TOKEN_ILLEGAL);
9475
0
    njs_token_serialize(NJS_TOKEN_COMMA);
9476
0
    njs_token_serialize(NJS_TOKEN_CONDITIONAL);
9477
0
    njs_token_serialize(NJS_TOKEN_ASSIGNMENT);
9478
0
    njs_token_serialize(NJS_TOKEN_ADDITION_ASSIGNMENT);
9479
0
    njs_token_serialize(NJS_TOKEN_SUBTRACTION_ASSIGNMENT);
9480
0
    njs_token_serialize(NJS_TOKEN_MULTIPLICATION_ASSIGNMENT);
9481
0
    njs_token_serialize(NJS_TOKEN_EXPONENTIATION_ASSIGNMENT);
9482
0
    njs_token_serialize(NJS_TOKEN_DIVISION_ASSIGNMENT);
9483
0
    njs_token_serialize(NJS_TOKEN_REMAINDER_ASSIGNMENT);
9484
0
    njs_token_serialize(NJS_TOKEN_LEFT_SHIFT_ASSIGNMENT);
9485
0
    njs_token_serialize(NJS_TOKEN_RIGHT_SHIFT_ASSIGNMENT);
9486
0
    njs_token_serialize(NJS_TOKEN_UNSIGNED_RIGHT_SHIFT_ASSIGNMENT);
9487
0
    njs_token_serialize(NJS_TOKEN_BITWISE_OR_ASSIGNMENT);
9488
0
    njs_token_serialize(NJS_TOKEN_BITWISE_XOR_ASSIGNMENT);
9489
0
    njs_token_serialize(NJS_TOKEN_BITWISE_AND_ASSIGNMENT);
9490
0
    njs_token_serialize(NJS_TOKEN_EQUAL);
9491
0
    njs_token_serialize(NJS_TOKEN_NOT_EQUAL);
9492
0
    njs_token_serialize(NJS_TOKEN_STRICT_EQUAL);
9493
0
    njs_token_serialize(NJS_TOKEN_STRICT_NOT_EQUAL);
9494
0
    njs_token_serialize(NJS_TOKEN_ADDITION);
9495
0
    njs_token_serialize(NJS_TOKEN_UNARY_PLUS);
9496
0
    njs_token_serialize(NJS_TOKEN_INCREMENT);
9497
0
    njs_token_serialize(NJS_TOKEN_POST_INCREMENT);
9498
0
    njs_token_serialize(NJS_TOKEN_SUBTRACTION);
9499
0
    njs_token_serialize(NJS_TOKEN_UNARY_NEGATION);
9500
0
    njs_token_serialize(NJS_TOKEN_DECREMENT);
9501
0
    njs_token_serialize(NJS_TOKEN_POST_DECREMENT);
9502
0
    njs_token_serialize(NJS_TOKEN_MULTIPLICATION);
9503
0
    njs_token_serialize(NJS_TOKEN_EXPONENTIATION);
9504
0
    njs_token_serialize(NJS_TOKEN_DIVISION);
9505
0
    njs_token_serialize(NJS_TOKEN_REMAINDER);
9506
0
    njs_token_serialize(NJS_TOKEN_LESS);
9507
0
    njs_token_serialize(NJS_TOKEN_LESS_OR_EQUAL);
9508
0
    njs_token_serialize(NJS_TOKEN_LEFT_SHIFT);
9509
0
    njs_token_serialize(NJS_TOKEN_GREATER);
9510
0
    njs_token_serialize(NJS_TOKEN_GREATER_OR_EQUAL);
9511
0
    njs_token_serialize(NJS_TOKEN_RIGHT_SHIFT);
9512
0
    njs_token_serialize(NJS_TOKEN_UNSIGNED_RIGHT_SHIFT);
9513
0
    njs_token_serialize(NJS_TOKEN_BITWISE_OR);
9514
0
    njs_token_serialize(NJS_TOKEN_LOGICAL_OR);
9515
0
    njs_token_serialize(NJS_TOKEN_BITWISE_XOR);
9516
0
    njs_token_serialize(NJS_TOKEN_BITWISE_AND);
9517
0
    njs_token_serialize(NJS_TOKEN_LOGICAL_AND);
9518
0
    njs_token_serialize(NJS_TOKEN_BITWISE_NOT);
9519
0
    njs_token_serialize(NJS_TOKEN_LOGICAL_NOT);
9520
0
    njs_token_serialize(NJS_TOKEN_COALESCE);
9521
0
    njs_token_serialize(NJS_TOKEN_IN);
9522
0
    njs_token_serialize(NJS_TOKEN_OF);
9523
0
    njs_token_serialize(NJS_TOKEN_INSTANCEOF);
9524
0
    njs_token_serialize(NJS_TOKEN_TYPEOF);
9525
0
    njs_token_serialize(NJS_TOKEN_VOID);
9526
0
    njs_token_serialize(NJS_TOKEN_NEW);
9527
0
    njs_token_serialize(NJS_TOKEN_DELETE);
9528
0
    njs_token_serialize(NJS_TOKEN_YIELD);
9529
9530
0
    njs_token_serialize(NJS_TOKEN_NULL);
9531
0
    njs_token_serialize(NJS_TOKEN_NUMBER);
9532
0
    njs_token_serialize(NJS_TOKEN_TRUE);
9533
0
    njs_token_serialize(NJS_TOKEN_FALSE);
9534
0
    njs_token_serialize(NJS_TOKEN_STRING);
9535
0
    njs_token_serialize(NJS_TOKEN_TEMPLATE_LITERAL);
9536
0
    njs_token_serialize(NJS_TOKEN_NAME);
9537
0
    njs_token_serialize(NJS_TOKEN_OBJECT);
9538
0
    njs_token_serialize(NJS_TOKEN_OBJECT_VALUE);
9539
0
    njs_token_serialize(NJS_TOKEN_ARRAY);
9540
0
    njs_token_serialize(NJS_TOKEN_REGEXP);
9541
9542
0
    njs_token_serialize(NJS_TOKEN_PROPERTY);
9543
0
    njs_token_serialize(NJS_TOKEN_PROPERTY_INIT);
9544
0
    njs_token_serialize(NJS_TOKEN_PROPERTY_DELETE);
9545
0
    njs_token_serialize(NJS_TOKEN_PROPERTY_GETTER);
9546
0
    njs_token_serialize(NJS_TOKEN_PROPERTY_SETTER);
9547
9548
0
    njs_token_serialize(NJS_TOKEN_PROTO_INIT);
9549
9550
0
    njs_token_serialize(NJS_TOKEN_FUNCTION);
9551
0
    njs_token_serialize(NJS_TOKEN_ASYNC_FUNCTION);
9552
0
    njs_token_serialize(NJS_TOKEN_FUNCTION_DECLARATION);
9553
0
    njs_token_serialize(NJS_TOKEN_ASYNC_FUNCTION_DECLARATION);
9554
0
    njs_token_serialize(NJS_TOKEN_FUNCTION_EXPRESSION);
9555
0
    njs_token_serialize(NJS_TOKEN_ASYNC_FUNCTION_EXPRESSION);
9556
0
    njs_token_serialize(NJS_TOKEN_FUNCTION_CALL);
9557
0
    njs_token_serialize(NJS_TOKEN_METHOD_CALL);
9558
9559
0
    njs_token_serialize(NJS_TOKEN_ARGUMENT);
9560
0
    njs_token_serialize(NJS_TOKEN_RETURN);
9561
0
    njs_token_serialize(NJS_TOKEN_STATEMENT);
9562
0
    njs_token_serialize(NJS_TOKEN_BLOCK);
9563
0
    njs_token_serialize(NJS_TOKEN_VAR);
9564
0
    njs_token_serialize(NJS_TOKEN_LET);
9565
0
    njs_token_serialize(NJS_TOKEN_CONST);
9566
0
    njs_token_serialize(NJS_TOKEN_IF);
9567
0
    njs_token_serialize(NJS_TOKEN_ELSE);
9568
0
    njs_token_serialize(NJS_TOKEN_BRANCHING);
9569
0
    njs_token_serialize(NJS_TOKEN_WHILE);
9570
0
    njs_token_serialize(NJS_TOKEN_DO);
9571
0
    njs_token_serialize(NJS_TOKEN_FOR);
9572
0
    njs_token_serialize(NJS_TOKEN_FOR_IN);
9573
0
    njs_token_serialize(NJS_TOKEN_BREAK);
9574
0
    njs_token_serialize(NJS_TOKEN_CONTINUE);
9575
0
    njs_token_serialize(NJS_TOKEN_SWITCH);
9576
0
    njs_token_serialize(NJS_TOKEN_CASE);
9577
0
    njs_token_serialize(NJS_TOKEN_DEFAULT);
9578
0
    njs_token_serialize(NJS_TOKEN_WITH);
9579
0
    njs_token_serialize(NJS_TOKEN_TRY);
9580
0
    njs_token_serialize(NJS_TOKEN_CATCH);
9581
0
    njs_token_serialize(NJS_TOKEN_FINALLY);
9582
0
    njs_token_serialize(NJS_TOKEN_THROW);
9583
0
    njs_token_serialize(NJS_TOKEN_THIS);
9584
0
    njs_token_serialize(NJS_TOKEN_ARGUMENTS);
9585
0
    njs_token_serialize(NJS_TOKEN_EVAL);
9586
0
    njs_token_serialize(NJS_TOKEN_IMPORT);
9587
0
    njs_token_serialize(NJS_TOKEN_EXPORT);
9588
0
    njs_token_serialize(NJS_TOKEN_DEBUGGER);
9589
9590
#if 0
9591
9592
    njs_token_serialize(NJS_TOKEN_TARGET);
9593
    njs_token_serialize(NJS_TOKEN_META);
9594
    njs_token_serialize(NJS_TOKEN_ASYNC);
9595
    njs_token_serialize(NJS_TOKEN_AWAIT);
9596
    njs_token_serialize(NJS_TOKEN_ENUM);
9597
9598
    njs_token_serialize(NJS_TOKEN_CLASS);
9599
    njs_token_serialize(NJS_TOKEN_EXTENDS);
9600
    njs_token_serialize(NJS_TOKEN_IMPLEMENTS);
9601
    njs_token_serialize(NJS_TOKEN_INTERFACE);
9602
    njs_token_serialize(NJS_TOKEN_PACKAGE);
9603
    njs_token_serialize(NJS_TOKEN_PRIVATE);
9604
    njs_token_serialize(NJS_TOKEN_PROTECTED);
9605
    njs_token_serialize(NJS_TOKEN_PUBLIC);
9606
    njs_token_serialize(NJS_TOKEN_STATIC);
9607
    njs_token_serialize(NJS_TOKEN_SUPER);
9608
9609
#endif
9610
9611
0
    default:
9612
0
        njs_chb_sprintf(chain, 32, "#UNDEF(%d)", (int) node->token_type);
9613
0
        return NJS_DECLINED;
9614
0
    }
9615
9616
0
    return NJS_OK;
9617
0
}