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 */
37void
38scanner_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 */
63static void
64scanner_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 */
84void
85scanner_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 */
135void
136scanner_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 */
169void
170scanner_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 */
258bool
259scanner_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 */
317void
318scanner_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 */
339typedef 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 */
351void
352scanner_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 */
540void
541scanner_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