1 /* Copyright JS Foundation and other contributors, http://js.foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "js-parser-internal.h"
17 #include "js-scanner-internal.h"
18 #include "lit-char-helpers.h"
19
20 #if ENABLED (JERRY_PARSER)
21
22 /** \addtogroup parser Parser
23 * @{
24 *
25 * \addtogroup jsparser JavaScript
26 * @{
27 *
28 * \addtogroup jsparser_scanner Scanner
29 * @{
30 */
31
32 #if ENABLED (JERRY_ES2015)
33
34 /**
35 * Add the "async" literal to the literal pool.
36 */
37 void
scanner_add_async_literal(parser_context_t * context_p,scanner_context_t * scanner_context_p)38 scanner_add_async_literal (parser_context_t *context_p, /**< context */
39 scanner_context_t *scanner_context_p) /**< scanner context */
40 {
41 lexer_lit_location_t async_literal;
42
43 JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_USE_ASYNC);
44
45 parser_stack_pop_uint8 (context_p);
46 parser_stack_pop (context_p, &async_literal, sizeof (lexer_lit_location_t));
47
48 lexer_lit_location_t *lit_location_p = scanner_add_custom_literal (context_p,
49 scanner_context_p->active_literal_pool_p,
50 &async_literal);
51
52 lit_location_p->type |= SCANNER_LITERAL_IS_USED;
53
54 if (scanner_context_p->active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH)
55 {
56 lit_location_p->type |= SCANNER_LITERAL_NO_REG;
57 }
58 } /* scanner_add_async_literal */
59
60 /**
61 * Init scanning the body of an arrow function.
62 */
63 static void
scanner_check_arrow_body(parser_context_t * context_p,scanner_context_t * scanner_context_p)64 scanner_check_arrow_body (parser_context_t *context_p, /**< context */
65 scanner_context_t *scanner_context_p) /**< scanner context */
66 {
67 lexer_next_token (context_p);
68
69 if (context_p->token.type != LEXER_LEFT_BRACE)
70 {
71 scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
72 parser_stack_push_uint8 (context_p, SCAN_STACK_ARROW_EXPRESSION);
73 return;
74 }
75
76 lexer_next_token (context_p);
77 parser_stack_push_uint8 (context_p, SCAN_STACK_FUNCTION_ARROW);
78 scanner_check_directives (context_p, scanner_context_p);
79 } /* scanner_check_arrow_body */
80
81 /**
82 * Process arrow function with argument list.
83 */
84 void
scanner_check_arrow(parser_context_t * context_p,scanner_context_t * scanner_context_p)85 scanner_check_arrow (parser_context_t *context_p, /**< context */
86 scanner_context_t *scanner_context_p) /**< scanner context */
87 {
88 parser_stack_pop_uint8 (context_p);
89
90 lexer_next_token (context_p);
91
92 if (context_p->token.type != LEXER_ARROW
93 || (context_p->token.flags & LEXER_WAS_NEWLINE))
94 {
95 if (context_p->stack_top_uint8 == SCAN_STACK_USE_ASYNC)
96 {
97 scanner_add_async_literal (context_p, scanner_context_p);
98 }
99
100 scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
101 scanner_pop_literal_pool (context_p, scanner_context_p);
102 return;
103 }
104
105 if (context_p->stack_top_uint8 == SCAN_STACK_USE_ASYNC)
106 {
107 parser_stack_pop (context_p, NULL, sizeof (lexer_lit_location_t) + 1);
108 }
109
110 scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p;
111 uint16_t status_flags = literal_pool_p->status_flags;
112
113 status_flags |= SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS;
114 status_flags &= (uint16_t) ~(SCANNER_LITERAL_POOL_IN_WITH
115 | SCANNER_LITERAL_POOL_GENERATOR
116 | SCANNER_LITERAL_POOL_ASYNC);
117
118 context_p->status_flags &= (uint32_t) ~(PARSER_IS_GENERATOR_FUNCTION | PARSER_IS_ASYNC_FUNCTION);
119
120 if (status_flags & SCANNER_LITERAL_POOL_ASYNC_ARROW)
121 {
122 status_flags |= SCANNER_LITERAL_POOL_ASYNC;
123 context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION;
124 }
125
126 literal_pool_p->status_flags = status_flags;
127
128 scanner_filter_arguments (context_p, scanner_context_p);
129 scanner_check_arrow_body (context_p, scanner_context_p);
130 } /* scanner_check_arrow */
131
132 /**
133 * Process arrow function with a single argument.
134 */
135 void
scanner_scan_simple_arrow(parser_context_t * context_p,scanner_context_t * scanner_context_p,const uint8_t * source_p)136 scanner_scan_simple_arrow (parser_context_t *context_p, /**< context */
137 scanner_context_t *scanner_context_p, /**< scanner context */
138 const uint8_t *source_p) /**< identifier end position */
139 {
140 uint16_t status_flags = SCANNER_LITERAL_POOL_FUNCTION_WITHOUT_ARGUMENTS;
141
142 context_p->status_flags &= (uint32_t) ~(PARSER_IS_GENERATOR_FUNCTION | PARSER_IS_ASYNC_FUNCTION);
143
144 if (scanner_context_p->async_source_p != NULL)
145 {
146 JERRY_ASSERT (scanner_context_p->async_source_p == source_p);
147
148 status_flags |= SCANNER_LITERAL_POOL_ASYNC;
149 context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION;
150 }
151
152 scanner_literal_pool_t *literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, status_flags);
153 literal_pool_p->source_p = source_p;
154
155 lexer_lit_location_t *location_p = scanner_add_literal (context_p, scanner_context_p);
156 location_p->type |= SCANNER_LITERAL_IS_ARG;
157
158 /* Skip the => token, which size is two. */
159 context_p->source_p += 2;
160 PARSER_PLUS_EQUAL_LC (context_p->column, 2);
161 context_p->token.flags = (uint8_t) (context_p->token.flags & ~LEXER_NO_SKIP_SPACES);
162
163 scanner_check_arrow_body (context_p, scanner_context_p);
164 } /* scanner_scan_simple_arrow */
165
166 /**
167 * Process the next argument of a might-be arrow function.
168 */
169 void
scanner_check_arrow_arg(parser_context_t * context_p,scanner_context_t * scanner_context_p)170 scanner_check_arrow_arg (parser_context_t *context_p, /**< context */
171 scanner_context_t *scanner_context_p) /**< scanner context */
172 {
173 JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_ARROW_ARGUMENTS);
174
175 const uint8_t *source_p = context_p->source_p;
176 bool process_arrow = false;
177
178 scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
179
180 if (context_p->token.type == LEXER_THREE_DOTS)
181 {
182 lexer_next_token (context_p);
183 }
184
185 if (context_p->token.type == LEXER_LITERAL
186 && context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
187 {
188 scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
189
190 if (lexer_check_arrow (context_p))
191 {
192 process_arrow = true;
193 }
194 else
195 {
196 lexer_lit_location_t *argument_literal_p = scanner_append_argument (context_p, scanner_context_p);
197
198 scanner_detect_eval_call (context_p, scanner_context_p);
199
200 lexer_next_token (context_p);
201
202 if (context_p->token.type == LEXER_ASSIGN)
203 {
204 if (argument_literal_p->type & SCANNER_LITERAL_IS_USED)
205 {
206 JERRY_ASSERT (argument_literal_p->type & SCANNER_LITERAL_EARLY_CREATE);
207 return;
208 }
209
210 scanner_binding_literal_t binding_literal;
211 binding_literal.literal_p = argument_literal_p;
212
213 parser_stack_push (context_p, &binding_literal, sizeof (scanner_binding_literal_t));
214 parser_stack_push_uint8 (context_p, SCAN_STACK_BINDING_INIT);
215 return;
216 }
217
218 if (context_p->token.type == LEXER_COMMA || context_p->token.type == LEXER_RIGHT_PAREN)
219 {
220 return;
221 }
222 }
223 }
224 else if (context_p->token.type == LEXER_LEFT_SQUARE || context_p->token.type == LEXER_LEFT_BRACE)
225 {
226 scanner_append_hole (context_p, scanner_context_p);
227 scanner_push_destructuring_pattern (context_p, scanner_context_p, SCANNER_BINDING_ARROW_ARG, false);
228
229 if (context_p->token.type == LEXER_LEFT_BRACE)
230 {
231 parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL);
232 scanner_context_p->mode = SCAN_MODE_PROPERTY_NAME;
233 return;
234 }
235
236 parser_stack_push_uint8 (context_p, SCAN_STACK_ARRAY_LITERAL);
237 scanner_context_p->mode = SCAN_MODE_BINDING;
238 lexer_next_token (context_p);
239 return;
240 }
241
242 scanner_pop_literal_pool (context_p, scanner_context_p);
243
244 parser_stack_pop_uint8 (context_p);
245 parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION);
246
247 if (process_arrow)
248 {
249 scanner_scan_simple_arrow (context_p, scanner_context_p, source_p);
250 }
251 } /* scanner_check_arrow_arg */
252
253 /**
254 * Detect async functions.
255 *
256 * @return true, if async is followed by a function keyword, false otherwise
257 */
258 bool
scanner_check_async_function(parser_context_t * context_p,scanner_context_t * scanner_context_p)259 scanner_check_async_function (parser_context_t *context_p, /**< context */
260 scanner_context_t *scanner_context_p) /**< scanner context */
261 {
262 JERRY_ASSERT (lexer_token_is_async (context_p));
263 JERRY_ASSERT (scanner_context_p->mode == SCAN_MODE_PRIMARY_EXPRESSION
264 || scanner_context_p->mode == SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW);
265 JERRY_ASSERT (scanner_context_p->async_source_p != NULL);
266
267 lexer_lit_location_t async_literal = context_p->token.lit_location;
268
269 lexer_next_token (context_p);
270
271 if (!(context_p->token.flags & LEXER_WAS_NEWLINE))
272 {
273 if (context_p->token.type == LEXER_KEYW_FUNCTION)
274 {
275 return true;
276 }
277
278 if (context_p->token.type == LEXER_LITERAL
279 && context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
280 {
281 if (!lexer_check_arrow (context_p))
282 {
283 scanner_raise_error (context_p);
284 }
285
286 scanner_scan_simple_arrow (context_p, scanner_context_p, scanner_context_p->async_source_p);
287 scanner_context_p->async_source_p = NULL;
288 return false;
289 }
290
291 if (context_p->token.type == LEXER_LEFT_PAREN)
292 {
293 parser_stack_push (context_p, &async_literal, sizeof (lexer_lit_location_t));
294 parser_stack_push_uint8 (context_p, SCAN_STACK_USE_ASYNC);
295 return false;
296 }
297 }
298
299 lexer_lit_location_t *lit_location_p = scanner_add_custom_literal (context_p,
300 scanner_context_p->active_literal_pool_p,
301 &async_literal);
302 lit_location_p->type |= SCANNER_LITERAL_IS_USED;
303
304 if (scanner_context_p->active_literal_pool_p->status_flags & SCANNER_LITERAL_POOL_IN_WITH)
305 {
306 lit_location_p->type |= SCANNER_LITERAL_NO_REG;
307 }
308
309 scanner_context_p->async_source_p = NULL;
310 scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
311 return false;
312 } /* scanner_check_async_function */
313
314 /**
315 * Check whether the statement of an if/else construct is a function statement.
316 */
317 void
scanner_check_function_after_if(parser_context_t * context_p,scanner_context_t * scanner_context_p)318 scanner_check_function_after_if (parser_context_t *context_p, /**< context */
319 scanner_context_t *scanner_context_p) /**< scanner context */
320 {
321 lexer_next_token (context_p);
322 scanner_context_p->mode = SCAN_MODE_STATEMENT;
323
324 if (JERRY_UNLIKELY (context_p->token.type == LEXER_KEYW_FUNCTION))
325 {
326 scanner_literal_pool_t *literal_pool_p;
327 literal_pool_p = scanner_push_literal_pool (context_p,
328 scanner_context_p,
329 SCANNER_LITERAL_POOL_BLOCK);
330
331 literal_pool_p->source_p = context_p->source_p;
332 parser_stack_push_uint8 (context_p, SCAN_STACK_PRIVATE_BLOCK);
333 }
334 } /* scanner_check_function_after_if */
335
336 /**
337 * Arrow types for scanner_scan_bracket() function.
338 */
339 typedef enum
340 {
341 SCANNER_SCAN_BRACKET_NO_ARROW, /**< not an arrow function */
342 SCANNER_SCAN_BRACKET_SIMPLE_ARROW, /**< simple arrow function */
343 SCANNER_SCAN_BRACKET_ARROW_WITH_ONE_ARG, /**< arrow function with one argument */
344 } scanner_scan_bracket_arrow_type_t;
345
346 #endif /* ENABLED (JERRY_ES2015) */
347
348 /**
349 * Scan bracketed expressions.
350 */
351 void
scanner_scan_bracket(parser_context_t * context_p,scanner_context_t * scanner_context_p)352 scanner_scan_bracket (parser_context_t *context_p, /**< context */
353 scanner_context_t *scanner_context_p) /**< scanner context */
354 {
355 size_t depth = 0;
356 #if ENABLED (JERRY_ES2015)
357 const uint8_t *arrow_source_p;
358 const uint8_t *async_source_p = NULL;
359 scanner_scan_bracket_arrow_type_t arrow_type = SCANNER_SCAN_BRACKET_NO_ARROW;
360 #endif /* ENABLED (JERRY_ES2015) */
361
362 JERRY_ASSERT (context_p->token.type == LEXER_LEFT_PAREN);
363
364 do
365 {
366 #if ENABLED (JERRY_ES2015)
367 arrow_source_p = context_p->source_p;
368 #endif /* ENABLED (JERRY_ES2015) */
369 depth++;
370 lexer_next_token (context_p);
371 }
372 while (context_p->token.type == LEXER_LEFT_PAREN);
373
374 scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION;
375
376 switch (context_p->token.type)
377 {
378 case LEXER_LITERAL:
379 {
380 if (context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
381 {
382 #if ENABLED (JERRY_ES2015)
383 arrow_source_p = NULL;
384 #endif /* ENABLED (JERRY_ES2015) */
385 break;
386 }
387
388 #if ENABLED (JERRY_ES2015)
389 const uint8_t *source_p = context_p->source_p;
390
391 if (lexer_check_arrow (context_p))
392 {
393 arrow_source_p = source_p;
394 arrow_type = SCANNER_SCAN_BRACKET_SIMPLE_ARROW;
395 break;
396 }
397
398 size_t total_depth = depth;
399 #endif /* ENABLED (JERRY_ES2015) */
400
401 while (depth > 0 && lexer_check_next_character (context_p, LIT_CHAR_RIGHT_PAREN))
402 {
403 lexer_consume_next_character (context_p);
404 depth--;
405 }
406
407 if (context_p->token.keyword_type == LEXER_KEYW_EVAL
408 && lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
409 {
410 #if ENABLED (JERRY_ES2015)
411 /* A function call cannot be an eval function. */
412 arrow_source_p = NULL;
413 #endif /* ENABLED (JERRY_ES2015) */
414
415 scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_CAN_EVAL;
416 break;
417 }
418
419 #if ENABLED (JERRY_ES2015)
420 if (total_depth == depth)
421 {
422 if (lexer_check_arrow_param (context_p))
423 {
424 JERRY_ASSERT (depth > 0);
425 depth--;
426 break;
427 }
428
429 if (JERRY_UNLIKELY (lexer_token_is_async (context_p)))
430 {
431 async_source_p = source_p;
432 }
433 }
434 else if (depth == total_depth - 1)
435 {
436 if (lexer_check_arrow (context_p))
437 {
438 arrow_type = SCANNER_SCAN_BRACKET_ARROW_WITH_ONE_ARG;
439 break;
440 }
441
442 if (context_p->stack_top_uint8 == SCAN_STACK_USE_ASYNC)
443 {
444 scanner_add_async_literal (context_p, scanner_context_p);
445 }
446 }
447
448 arrow_source_p = NULL;
449 #endif /* ENABLED (JERRY_ES2015) */
450 break;
451 }
452 #if ENABLED (JERRY_ES2015)
453 case LEXER_THREE_DOTS:
454 case LEXER_LEFT_SQUARE:
455 case LEXER_LEFT_BRACE:
456 case LEXER_RIGHT_PAREN:
457 {
458 JERRY_ASSERT (depth > 0);
459 depth--;
460 break;
461 }
462 #endif /* ENABLED (JERRY_ES2015) */
463 default:
464 {
465 #if ENABLED (JERRY_ES2015)
466 arrow_source_p = NULL;
467 #endif /* ENABLED (JERRY_ES2015) */
468 break;
469 }
470 }
471
472 #if ENABLED (JERRY_ES2015)
473 if (JERRY_UNLIKELY (scanner_context_p->async_source_p != NULL)
474 && (arrow_source_p == NULL || depth > 0))
475 {
476 scanner_context_p->async_source_p = NULL;
477 }
478 #endif /* ENABLED (JERRY_ES2015) */
479
480 while (depth > 0)
481 {
482 parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION);
483 depth--;
484 }
485
486 #if ENABLED (JERRY_ES2015)
487 if (arrow_source_p != NULL)
488 {
489 JERRY_ASSERT (async_source_p == NULL);
490
491 if (arrow_type == SCANNER_SCAN_BRACKET_SIMPLE_ARROW)
492 {
493 scanner_scan_simple_arrow (context_p, scanner_context_p, arrow_source_p);
494 return;
495 }
496
497 parser_stack_push_uint8 (context_p, SCAN_STACK_ARROW_ARGUMENTS);
498
499 uint16_t status_flags = 0;
500
501 if (JERRY_UNLIKELY (scanner_context_p->async_source_p != NULL))
502 {
503 status_flags |= SCANNER_LITERAL_POOL_ASYNC_ARROW;
504 arrow_source_p = scanner_context_p->async_source_p;
505 scanner_context_p->async_source_p = NULL;
506 }
507
508 scanner_literal_pool_t *literal_pool_p;
509 literal_pool_p = scanner_push_literal_pool (context_p, scanner_context_p, status_flags);
510 literal_pool_p->source_p = arrow_source_p;
511
512 if (arrow_type == SCANNER_SCAN_BRACKET_ARROW_WITH_ONE_ARG)
513 {
514 scanner_append_argument (context_p, scanner_context_p);
515 scanner_detect_eval_call (context_p, scanner_context_p);
516
517 context_p->token.type = LEXER_RIGHT_PAREN;
518 scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
519 }
520 else if (context_p->token.type == LEXER_RIGHT_PAREN)
521 {
522 scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
523 }
524 else
525 {
526 scanner_check_arrow_arg (context_p, scanner_context_p);
527 }
528 }
529 else if (JERRY_UNLIKELY (async_source_p != NULL))
530 {
531 scanner_context_p->async_source_p = async_source_p;
532 scanner_check_async_function (context_p, scanner_context_p);
533 }
534 #endif /* ENABLED (JERRY_ES2015) */
535 } /* scanner_scan_bracket */
536
537 /**
538 * Check directives before a source block.
539 */
540 void
scanner_check_directives(parser_context_t * context_p,scanner_context_t * scanner_context_p)541 scanner_check_directives (parser_context_t *context_p, /**< context */
542 scanner_context_t *scanner_context_p) /**< scanner context */
543 {
544 scanner_context_p->mode = SCAN_MODE_STATEMENT_OR_TERMINATOR;
545
546 while (context_p->token.type == LEXER_LITERAL
547 && context_p->token.lit_location.type == LEXER_STRING_LITERAL)
548 {
549 bool is_use_strict = false;
550
551 if (lexer_string_is_use_strict (context_p)
552 && !(context_p->status_flags & PARSER_IS_STRICT))
553 {
554 is_use_strict = true;
555 context_p->status_flags |= PARSER_IS_STRICT;
556 }
557
558 lexer_next_token (context_p);
559
560 if (!lexer_string_is_directive (context_p))
561 {
562 if (is_use_strict)
563 {
564 context_p->status_flags &= (uint32_t) ~PARSER_IS_STRICT;
565 }
566
567 /* The string is part of an expression statement. */
568 scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
569 break;
570 }
571
572 if (is_use_strict)
573 {
574 scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_IS_STRICT;
575 }
576
577 if (context_p->token.type == LEXER_SEMICOLON)
578 {
579 lexer_next_token (context_p);
580 }
581 }
582 } /* scanner_check_directives */
583
584 /**
585 * @}
586 * @}
587 * @}
588 */
589
590 #endif /* ENABLED (JERRY_PARSER) */
591