• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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