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
18 #if ENABLED (JERRY_ES2015_MODULE_SYSTEM)
19 #include "jcontext.h"
20 #include "jerryscript-port.h"
21
22 #include "ecma-function-object.h"
23 #include "ecma-gc.h"
24 #include "ecma-globals.h"
25 #include "ecma-helpers.h"
26 #include "ecma-lex-env.h"
27 #include "ecma-module.h"
28
29 /**
30 * Description of "*default*" literal string.
31 */
32 const lexer_lit_location_t lexer_default_literal =
33 {
34 (const uint8_t *) "*default*", 9, LEXER_IDENT_LITERAL, false
35 };
36
37 /**
38 * Check for duplicated imported binding names.
39 *
40 * @return true - if the given name is a duplicate
41 * false - otherwise
42 */
43 bool
parser_module_check_duplicate_import(parser_context_t * context_p,ecma_string_t * local_name_p)44 parser_module_check_duplicate_import (parser_context_t *context_p, /**< parser context */
45 ecma_string_t *local_name_p) /**< newly imported name */
46 {
47 ecma_module_names_t *module_names_p = context_p->module_current_node_p->module_names_p;
48 while (module_names_p != NULL)
49 {
50 if (ecma_compare_ecma_strings (module_names_p->local_name_p, local_name_p))
51 {
52 return true;
53 }
54
55 module_names_p = module_names_p->next_p;
56 }
57
58 ecma_module_node_t *module_node_p = JERRY_CONTEXT (module_top_context_p)->imports_p;
59 while (module_node_p != NULL)
60 {
61 module_names_p = module_node_p->module_names_p;
62
63 while (module_names_p != NULL)
64 {
65 if (ecma_compare_ecma_strings (module_names_p->local_name_p, local_name_p))
66 {
67 return true;
68 }
69
70 module_names_p = module_names_p->next_p;
71 }
72
73 module_node_p = module_node_p->next_p;
74 }
75
76 return false;
77 } /* parser_module_check_duplicate_import */
78
79 /**
80 * Append an identifier to the exported bindings.
81 */
82 void
parser_module_append_export_name(parser_context_t * context_p)83 parser_module_append_export_name (parser_context_t *context_p) /**< parser context */
84 {
85 if (!(context_p->status_flags & PARSER_MODULE_STORE_IDENT))
86 {
87 return;
88 }
89
90 context_p->module_identifier_lit_p = context_p->lit_object.literal_p;
91
92 ecma_string_t *name_p = ecma_new_ecma_string_from_utf8 (context_p->lit_object.literal_p->u.char_p,
93 context_p->lit_object.literal_p->prop.length);
94
95 if (parser_module_check_duplicate_export (context_p, name_p))
96 {
97 ecma_deref_ecma_string (name_p);
98 parser_raise_error (context_p, PARSER_ERR_DUPLICATED_EXPORT_IDENTIFIER);
99 }
100
101 parser_module_add_names_to_node (context_p,
102 name_p,
103 name_p);
104 ecma_deref_ecma_string (name_p);
105 } /* parser_module_append_export_name */
106
107 /**
108 * Check for duplicated exported bindings.
109 * @return - true - if the exported name is a duplicate
110 * false - otherwise
111 */
112 bool
parser_module_check_duplicate_export(parser_context_t * context_p,ecma_string_t * export_name_p)113 parser_module_check_duplicate_export (parser_context_t *context_p, /**< parser context */
114 ecma_string_t *export_name_p) /**< exported identifier */
115 {
116 /* We have to check in the currently constructed node, as well as all of the already added nodes. */
117 ecma_module_names_t *current_names_p = context_p->module_current_node_p->module_names_p;
118 while (current_names_p != NULL)
119 {
120 if (ecma_compare_ecma_strings (current_names_p->imex_name_p, export_name_p))
121 {
122 return true;
123 }
124 current_names_p = current_names_p->next_p;
125 }
126
127 ecma_module_node_t *export_node_p = JERRY_CONTEXT (module_top_context_p)->local_exports_p;
128 if (export_node_p != NULL)
129 {
130 JERRY_ASSERT (export_node_p->next_p == NULL);
131 ecma_module_names_t *name_p = export_node_p->module_names_p;
132
133 while (name_p != NULL)
134 {
135 if (ecma_compare_ecma_strings (name_p->imex_name_p, export_name_p))
136 {
137 return true;
138 }
139
140 name_p = name_p->next_p;
141 }
142 }
143
144 export_node_p = JERRY_CONTEXT (module_top_context_p)->indirect_exports_p;
145 while (export_node_p != NULL)
146 {
147 ecma_module_names_t *name_p = export_node_p->module_names_p;
148
149 while (name_p != NULL)
150 {
151 if (ecma_compare_ecma_strings (name_p->imex_name_p, export_name_p))
152 {
153 return true;
154 }
155
156 name_p = name_p->next_p;
157 }
158
159 export_node_p = export_node_p->next_p;
160 }
161
162 /* Star exports don't have any names associated with them, so no need to check those. */
163 return false;
164 } /* parser_module_check_duplicate_export */
165
166 /**
167 * Add export node to parser context.
168 */
169 void
parser_module_add_export_node_to_context(parser_context_t * context_p)170 parser_module_add_export_node_to_context (parser_context_t *context_p) /**< parser context */
171 {
172 ecma_module_node_t *module_node_p = context_p->module_current_node_p;
173 context_p->module_current_node_p = NULL;
174 ecma_module_node_t **export_list_p;
175
176 /* Check which list we should add it to. */
177 if (module_node_p->module_request_p)
178 {
179 /* If the export node has a module request, that means it's either an indirect export, or a star export. */
180 if (!module_node_p->module_names_p)
181 {
182 /* If there are no names in the node, then it's a star export. */
183 export_list_p = &(JERRY_CONTEXT (module_top_context_p)->star_exports_p);
184 }
185 else
186 {
187 export_list_p = &(JERRY_CONTEXT (module_top_context_p)->indirect_exports_p);
188 }
189 }
190 else
191 {
192 /* If there is no module request, then it's a local export. */
193 export_list_p = &(JERRY_CONTEXT (module_top_context_p)->local_exports_p);
194 }
195
196 /* Check if we have a node with the same module request, append to it if we do. */
197 ecma_module_node_t *stored_exports_p = *export_list_p;
198 while (stored_exports_p != NULL)
199 {
200 if (stored_exports_p->module_request_p == module_node_p->module_request_p)
201 {
202 ecma_module_names_t *module_names_p = module_node_p->module_names_p;
203
204 if (module_names_p != NULL)
205 {
206 while (module_names_p->next_p != NULL)
207 {
208 module_names_p = module_names_p->next_p;
209 }
210
211 module_names_p->next_p = stored_exports_p->module_names_p;
212 stored_exports_p->module_names_p = module_node_p->module_names_p;
213 module_node_p->module_names_p = NULL;
214 }
215
216 ecma_module_release_module_nodes (module_node_p);
217 return;
218 }
219
220 stored_exports_p = stored_exports_p->next_p;
221 }
222
223 module_node_p->next_p = *export_list_p;
224 *export_list_p = module_node_p;
225 } /* parser_module_add_export_node_to_context */
226
227 /**
228 * Add import node to parser context.
229 */
230 void
parser_module_add_import_node_to_context(parser_context_t * context_p)231 parser_module_add_import_node_to_context (parser_context_t *context_p) /**< parser context */
232 {
233 ecma_module_node_t *module_node_p = context_p->module_current_node_p;
234 context_p->module_current_node_p = NULL;
235 ecma_module_node_t *stored_imports = JERRY_CONTEXT (module_top_context_p)->imports_p;
236
237 /* Check if we have a node with the same module request, append to it if we do. */
238 while (stored_imports != NULL)
239 {
240 if (stored_imports->module_request_p == module_node_p->module_request_p)
241 {
242 ecma_module_names_t *module_names_p = module_node_p->module_names_p;
243
244 if (module_names_p != NULL)
245 {
246 while (module_names_p->next_p != NULL)
247 {
248 module_names_p = module_names_p->next_p;
249 }
250
251 module_names_p->next_p = stored_imports->module_names_p;
252 stored_imports->module_names_p = module_node_p->module_names_p;
253 module_node_p->module_names_p = NULL;
254 }
255
256 ecma_module_release_module_nodes (module_node_p);
257 return;
258 }
259
260 stored_imports = stored_imports->next_p;
261 }
262
263 module_node_p->next_p = JERRY_CONTEXT (module_top_context_p)->imports_p;
264 JERRY_CONTEXT (module_top_context_p)->imports_p = module_node_p;
265 } /* parser_module_add_import_node_to_context */
266
267 /**
268 * Add module names to current module node.
269 */
270 void
parser_module_add_names_to_node(parser_context_t * context_p,ecma_string_t * imex_name_p,ecma_string_t * local_name_p)271 parser_module_add_names_to_node (parser_context_t *context_p, /**< parser context */
272 ecma_string_t *imex_name_p, /**< import/export name */
273 ecma_string_t *local_name_p) /**< local name */
274 {
275 ecma_module_names_t *new_names_p = (ecma_module_names_t *) parser_malloc (context_p,
276 sizeof (ecma_module_names_t));
277 memset (new_names_p, 0, sizeof (ecma_module_names_t));
278
279 ecma_module_node_t *module_node_p = context_p->module_current_node_p;
280 new_names_p->next_p = module_node_p->module_names_p;
281 module_node_p->module_names_p = new_names_p;
282
283 JERRY_ASSERT (imex_name_p != NULL);
284 ecma_ref_ecma_string (imex_name_p);
285 new_names_p->imex_name_p = imex_name_p;
286
287 JERRY_ASSERT (local_name_p != NULL);
288 ecma_ref_ecma_string (local_name_p);
289 new_names_p->local_name_p = local_name_p;
290 } /* parser_module_add_names_to_node */
291
292 /**
293 * Create module context if needed.
294 */
295 void
parser_module_context_init(void)296 parser_module_context_init (void)
297 {
298 if (JERRY_CONTEXT (module_top_context_p) == NULL)
299 {
300 ecma_module_context_t *module_context_p;
301 module_context_p = (ecma_module_context_t *) jmem_heap_alloc_block (sizeof (ecma_module_context_t));
302 memset (module_context_p, 0, sizeof (ecma_module_context_t));
303 JERRY_CONTEXT (module_top_context_p) = module_context_p;
304
305 ecma_string_t *path_str_p = ecma_get_string_from_value (JERRY_CONTEXT (resource_name));
306
307 lit_utf8_size_t path_str_size;
308 uint8_t flags = ECMA_STRING_FLAG_EMPTY;
309
310 const lit_utf8_byte_t *path_str_chars_p = ecma_string_get_chars (path_str_p,
311 &path_str_size,
312 NULL,
313 NULL,
314 &flags);
315
316 ecma_string_t *path_p = ecma_module_create_normalized_path (path_str_chars_p,
317 (prop_length_t) path_str_size);
318
319 if (path_p == NULL)
320 {
321 ecma_ref_ecma_string (path_str_p);
322 path_p = path_str_p;
323 }
324
325 ecma_module_t *module_p = ecma_module_find_or_create_module (path_p);
326
327 module_p->state = ECMA_MODULE_STATE_EVALUATED;
328 /* The lexical scope of the root module does not exist yet. */
329 module_p->scope_p = NULL;
330
331 module_p->context_p = module_context_p;
332 module_context_p->module_p = module_p;
333 }
334 } /* parser_module_context_init */
335
336 /**
337 * Create a permanent import/export node from a template node.
338 * @return - the copy of the template if the second parameter is not NULL.
339 * - otherwise: an empty node.
340 */
341 ecma_module_node_t *
parser_module_create_module_node(parser_context_t * context_p)342 parser_module_create_module_node (parser_context_t *context_p) /**< parser context */
343 {
344 ecma_module_node_t *node_p = (ecma_module_node_t *) parser_malloc (context_p, sizeof (ecma_module_node_t));
345 memset (node_p, 0, sizeof (ecma_module_node_t));
346
347 return node_p;
348 } /* parser_module_create_module_node */
349
350 /**
351 * Parse an ExportClause.
352 */
353 void
parser_module_parse_export_clause(parser_context_t * context_p)354 parser_module_parse_export_clause (parser_context_t *context_p) /**< parser context */
355 {
356 JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE);
357 lexer_next_token (context_p);
358
359 while (true)
360 {
361 if (context_p->token.type == LEXER_RIGHT_BRACE)
362 {
363 lexer_next_token (context_p);
364 break;
365 }
366
367 /* 15.2.3.1 The referenced binding cannot be a reserved word. */
368 if (context_p->token.type != LEXER_LITERAL
369 || context_p->token.lit_location.type != LEXER_IDENT_LITERAL
370 || context_p->token.keyword_type >= LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD)
371 {
372 parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
373 }
374
375 ecma_string_t *export_name_p = NULL;
376 ecma_string_t *local_name_p = NULL;
377
378 lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_NEW_IDENT_LITERAL);
379
380 uint16_t local_name_index = context_p->lit_object.index;
381 uint16_t export_name_index = PARSER_MAXIMUM_NUMBER_OF_LITERALS;
382
383 lexer_next_token (context_p);
384 if (lexer_token_is_identifier (context_p, "as", 2))
385 {
386 lexer_next_token (context_p);
387
388 if (context_p->token.type != LEXER_LITERAL
389 || context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
390 {
391 parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
392 }
393
394 lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_NEW_IDENT_LITERAL);
395
396 export_name_index = context_p->lit_object.index;
397
398 lexer_next_token (context_p);
399 }
400
401 lexer_literal_t *literal_p = PARSER_GET_LITERAL (local_name_index);
402 local_name_p = ecma_new_ecma_string_from_utf8 (literal_p->u.char_p, literal_p->prop.length);
403
404 if (export_name_index != PARSER_MAXIMUM_NUMBER_OF_LITERALS)
405 {
406 lexer_literal_t *as_literal_p = PARSER_GET_LITERAL (export_name_index);
407 export_name_p = ecma_new_ecma_string_from_utf8 (as_literal_p->u.char_p, as_literal_p->prop.length);
408 }
409 else
410 {
411 export_name_p = local_name_p;
412 ecma_ref_ecma_string (local_name_p);
413 }
414
415 if (parser_module_check_duplicate_export (context_p, export_name_p))
416 {
417 ecma_deref_ecma_string (local_name_p);
418 ecma_deref_ecma_string (export_name_p);
419 parser_raise_error (context_p, PARSER_ERR_DUPLICATED_EXPORT_IDENTIFIER);
420 }
421
422 parser_module_add_names_to_node (context_p, export_name_p, local_name_p);
423 ecma_deref_ecma_string (local_name_p);
424 ecma_deref_ecma_string (export_name_p);
425
426 if (context_p->token.type != LEXER_COMMA
427 && context_p->token.type != LEXER_RIGHT_BRACE)
428 {
429 parser_raise_error (context_p, PARSER_ERR_RIGHT_BRACE_COMMA_EXPECTED);
430 }
431 else if (context_p->token.type == LEXER_COMMA)
432 {
433 lexer_next_token (context_p);
434 }
435
436 if (lexer_token_is_identifier (context_p, "from", 4))
437 {
438 parser_raise_error (context_p, PARSER_ERR_RIGHT_BRACE_EXPECTED);
439 }
440 }
441 } /* parser_module_parse_export_clause */
442
443 /**
444 * Parse an ImportClause
445 */
446 void
parser_module_parse_import_clause(parser_context_t * context_p)447 parser_module_parse_import_clause (parser_context_t *context_p) /**< parser context */
448 {
449 JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE);
450 lexer_next_token (context_p);
451
452 while (true)
453 {
454 if (context_p->token.type == LEXER_RIGHT_BRACE)
455 {
456 lexer_next_token (context_p);
457 break;
458 }
459
460 if (context_p->token.type != LEXER_LITERAL
461 || context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
462 {
463 parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
464 }
465
466 #if ENABLED (JERRY_ES2015)
467 if (context_p->next_scanner_info_p->source_p == context_p->source_p)
468 {
469 JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED);
470 parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED);
471 }
472 #endif /* ENABLED (JERRY_ES2015) */
473
474 ecma_string_t *import_name_p = NULL;
475 ecma_string_t *local_name_p = NULL;
476
477 lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_NEW_IDENT_LITERAL);
478
479 uint16_t import_name_index = context_p->lit_object.index;
480 uint16_t local_name_index = PARSER_MAXIMUM_NUMBER_OF_LITERALS;
481
482 lexer_next_token (context_p);
483 if (lexer_token_is_identifier (context_p, "as", 2))
484 {
485 lexer_next_token (context_p);
486
487 if (context_p->token.type != LEXER_LITERAL
488 || context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
489 {
490 parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
491 }
492
493 #if ENABLED (JERRY_ES2015)
494 if (context_p->next_scanner_info_p->source_p == context_p->source_p)
495 {
496 JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED);
497 parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED);
498 }
499 #endif /* ENABLED (JERRY_ES2015) */
500
501 lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_NEW_IDENT_LITERAL);
502
503 local_name_index = context_p->lit_object.index;
504
505 lexer_next_token (context_p);
506 }
507
508 lexer_literal_t *literal_p = PARSER_GET_LITERAL (import_name_index);
509 import_name_p = ecma_new_ecma_string_from_utf8 (literal_p->u.char_p, literal_p->prop.length);
510
511 if (local_name_index != PARSER_MAXIMUM_NUMBER_OF_LITERALS)
512 {
513 lexer_literal_t *as_literal_p = PARSER_GET_LITERAL (local_name_index);
514 local_name_p = ecma_new_ecma_string_from_utf8 (as_literal_p->u.char_p, as_literal_p->prop.length);
515 }
516 else
517 {
518 local_name_p = import_name_p;
519 ecma_ref_ecma_string (local_name_p);
520 }
521
522 if (parser_module_check_duplicate_import (context_p, local_name_p))
523 {
524 ecma_deref_ecma_string (local_name_p);
525 ecma_deref_ecma_string (import_name_p);
526 parser_raise_error (context_p, PARSER_ERR_DUPLICATED_IMPORT_BINDING);
527 }
528
529 parser_module_add_names_to_node (context_p, import_name_p, local_name_p);
530 ecma_deref_ecma_string (local_name_p);
531 ecma_deref_ecma_string (import_name_p);
532
533 if (context_p->token.type != LEXER_COMMA
534 && (context_p->token.type != LEXER_RIGHT_BRACE))
535 {
536 parser_raise_error (context_p, PARSER_ERR_RIGHT_BRACE_COMMA_EXPECTED);
537 }
538 else if (context_p->token.type == LEXER_COMMA)
539 {
540 lexer_next_token (context_p);
541 }
542
543 if (lexer_token_is_identifier (context_p, "from", 4))
544 {
545 parser_raise_error (context_p, PARSER_ERR_RIGHT_BRACE_EXPECTED);
546 }
547 }
548 } /* parser_module_parse_import_clause */
549
550 /**
551 * Raises parser error if the import or export statement is not in the global scope.
552 */
553 void
parser_module_check_request_place(parser_context_t * context_p)554 parser_module_check_request_place (parser_context_t *context_p) /**< parser context */
555 {
556 if (context_p->last_context_p != NULL
557 || context_p->stack_top_uint8 != 0
558 || (context_p->status_flags & PARSER_IS_FUNCTION)
559 || (context_p->global_status_flags & ECMA_PARSE_EVAL))
560 {
561 parser_raise_error (context_p, PARSER_ERR_MODULE_UNEXPECTED);
562 }
563 } /* parser_module_check_request_place */
564
565 /**
566 * Handle module specifier at the end of the import / export statement.
567 */
568 void
parser_module_handle_module_specifier(parser_context_t * context_p)569 parser_module_handle_module_specifier (parser_context_t *context_p) /**< parser context */
570 {
571 ecma_module_node_t *module_node_p = context_p->module_current_node_p;
572 if (context_p->token.type != LEXER_LITERAL
573 || context_p->token.lit_location.type != LEXER_STRING_LITERAL
574 || context_p->token.lit_location.length == 0)
575 {
576 parser_raise_error (context_p, PARSER_ERR_STRING_EXPECTED);
577 }
578
579 lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_STRING_LITERAL);
580
581 ecma_string_t *name_p = ecma_new_ecma_string_from_utf8 (context_p->lit_object.literal_p->u.char_p,
582 context_p->lit_object.literal_p->prop.length);
583
584 ecma_module_t *module_p = ecma_module_find_module (name_p);
585 if (module_p)
586 {
587 ecma_deref_ecma_string (name_p);
588 goto module_found;
589 }
590
591 ecma_value_t native = jerry_port_get_native_module (ecma_make_string_value (name_p));
592
593 if (!ecma_is_value_undefined (native))
594 {
595 JERRY_ASSERT (ecma_is_value_object (native));
596 ecma_object_t *module_object_p = ecma_get_object_from_value (native);
597
598 module_p = ecma_module_create_native_module (name_p, module_object_p);
599 goto module_found;
600 }
601
602 ecma_deref_ecma_string (name_p);
603 ecma_string_t *path_p = ecma_module_create_normalized_path (context_p->lit_object.literal_p->u.char_p,
604 context_p->lit_object.literal_p->prop.length);
605
606 if (path_p == NULL)
607 {
608 parser_raise_error (context_p, PARSER_ERR_FILE_NOT_FOUND);
609 }
610
611 module_p = ecma_module_find_or_create_module (path_p);
612
613 module_found:
614 module_node_p->module_request_p = module_p;
615 lexer_next_token (context_p);
616 } /* parser_module_handle_module_specifier */
617
618 #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */
619