diff --git a/docs/05.PORT-API.md b/docs/05.PORT-API.md index 67f992a3f7..47b3957ebc 100644 --- a/docs/05.PORT-API.md +++ b/docs/05.PORT-API.md @@ -85,7 +85,8 @@ void jerry_port_print_char (char c); ### ES2015 Module system helper functions -The import statement requires two specific functions for opening and closing files (the modules) port specific. +The module system requires two specific functions for opening and closing files. +It also requires a platform specific way of normalizing file paths. ```c /** @@ -108,6 +109,21 @@ jerry_port_release_source (uint8_t *buffer_p) /**< buffer to free */ { free (buffer_p); } /* jerry_port_release_source */ + +/** + * Normalize a file path + * + * @return length of the path written to the output buffer + */ +size_t +jerry_port_normalize_path (const char *in_path_p, /**< input file path */ + char *out_buf_p, /**< output buffer */ + size_t out_buf_size) /**< size of output buffer */ +{ + // normalize in_path_p by expanding relative paths etc. + // write to out_buf_p the normalized path + // return length of written path +} /* jerry_port_normalize_path */ ``` ## Date diff --git a/docs/15.MODULE-SYSTEM.md b/docs/15.MODULE-SYSTEM.md index efac2912f8..48f4255306 100644 --- a/docs/15.MODULE-SYSTEM.md +++ b/docs/15.MODULE-SYSTEM.md @@ -1,34 +1,48 @@ # ES6 module support for JerryScript -The module system allows users to write import and export statements in scripts. Therefore the logic of the application could be separated in custom modules. +The module system allows users to write import and export statements in scripts, which can be used to separate the logic of the application into custom modules. The standard's relevant part can be found [here](https://www.ecma-international.org/ecma-262/6.0/#sec-modules). ## General -If the main script contains import statements, then Jerry opens and runs the appropriate scripts before the main script (as the standard says). The script's and the module's extension is `.js`, custom extensions are unnecessary. +If a script contains import statements, then JerryScript will open and evaluate the the referenced modules before the main script runs, resolving and creating bindings for the referenced identifiers in the process. +It is not necessary to use any specific filename extensions for modules, JerryScript will try to open the given file paths as they are, but will try to normalize them before doing so. The exact normalization process is dependant on the port implementation provided. It is the user's responsibility to verify that the given files are valid EcmaScript modules. main.js ```js -import { secret_number } from "./module.js" +import { exported_value } from "./module.js" -print (secret_number); +print (exported_value); ``` module.js ```js -var secret_number = 42; +var exported_value = 42; -export secret_number; +export exported_value; ``` ## Supported features -* import variable or function - * add alias name to the imported variable (function) -* export variable or function - * add alias name to the exported variable (function) +* exporting identifiers from the module's lexical environment + * specifying export names for the exported values +* importing exported identifiers from a module + * specifying local binding names for the imported values +* module namespace imports + * `import * as module from 'module.js` +* indirect export statements + * `export {variable} from 'module.js'` +* star export statements + * `export * from 'module.js'` +* importing a module for side-effects + * `import 'module.js'` +* default import and export statements + * `export default local_identifier` + * `import def from 'module.js'` +* anonymous default exports + * `export default function () {}` ### Example @@ -69,22 +83,20 @@ export function getFeatureDetails() { } ``` -## Unsupported features +### Module namespace import statements -* **snapshot** -* errors from the imported scripts -* redirection ( `export { a, b } from 'module.js'` ) -* default import and export - * `import b from 'module.js'` - * `export default b`, -* whole module import statements - * `import * from 'module.js` - * `import { * as module } from 'module.js` -* object freezing ( `Object.freeze (this)` ) +A module namespace object can be imported. In this case the local binding will contain an object holding the exported values of the module, including local exports and all indirect exports. Ambiguous exported names are exluded from the namespace object. + +```js +import * as module from './module.js'; + +print(">> Engine: " + module.engine); +print(">> Version: " + module.version); +``` -### Redirection +### Indirect export statements -An export statement can import variables from a custom module and export it directly from the current script. This statement is called redirection. In this case the `export { b } from 'module2.js'` works as the `b` was imported before then exported as a local variable. +An export statement can transitively export variables from another module, either via named indirect exports or a star export statement. In this case the resolving process will follow the chain until it reaches a module containing a local binding for that export name. If there are multiple modules which satisfy the export, that means the export is ambiguous, and will result in a SyntaxError. ```js import { a, b } from 'module.js' @@ -105,28 +117,42 @@ export var b = 40; ### Default imports and exports -TODO: This part is going to be written in the next part of the patch. +Each module can optionally provide a single default export by using the `export default` statement. Default exports can either reference identifiers in the module's lexical environment, or be an anonymous default export, in which case they will only be accessible by an importing script. -### Import the whole module +```js +import defaultExport, { b as c } from 'module.js' -The whole module can be imported. In this case the `m` object would contain the exported parts of the module. If the import is not aliased, the `global object` would contain the exports. +print (defaultExport); // 2 +print (c ()); // 42 +``` ```js -import { * as m } from "./module.js" +// module.js +export default 2; +export function b () { + return 42; +} +``` + +### Importing modules for side-effects + +Evaluate a module without importing anything. Any errors encountered in the module will be propagated. -print (m.secret_number); -print (m.getPrettifiedNumber()); -print (m.api.version); +```js +import 'module.js' // > module.js +// "> module.js" is printed +b (); // (ReferenceError) b is not defined ``` ```js // module.js -var secret_number = 42; -export secret_number; - -export function getPrettifiedNumber() { - return "*** " + secret_number + " ***"; +export function b () { + print ("> module.js"); + return 42; } - -export { ble as api } from "./ble.js"; +b (); ``` + +## Unsupported features + +* **snapshot** diff --git a/jerry-core/ecma/base/ecma-init-finalize.c b/jerry-core/ecma/base/ecma-init-finalize.c index 0187d2c680..037c218834 100644 --- a/jerry-core/ecma/base/ecma-init-finalize.c +++ b/jerry-core/ecma/base/ecma-init-finalize.c @@ -60,11 +60,6 @@ void ecma_finalize (void) { jmem_unregister_free_unused_memory_callback (ecma_free_unused_memory); - -#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - ecma_module_finalize_lex_envs (); -#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ - ecma_finalize_global_lex_env (); ecma_finalize_builtins (); ecma_gc_run (JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW); diff --git a/jerry-core/ecma/base/ecma-module.c b/jerry-core/ecma/base/ecma-module.c index 5ec708e8b8..ca3bd94665 100644 --- a/jerry-core/ecma/base/ecma-module.c +++ b/jerry-core/ecma/base/ecma-module.c @@ -13,246 +13,876 @@ * limitations under the License. */ -#include "jerryscript.h" #include "jcontext.h" +#include "jerryscript.h" -#include "ecma-helpers.h" +#include "ecma-exceptions.h" #include "ecma-function-object.h" -#include "ecma-literal-storage.h" -#include "ecma-lex-env.h" #include "ecma-gc.h" +#include "ecma-globals.h" +#include "ecma-helpers.h" +#include "ecma-lex-env.h" #include "ecma-module.h" +#include "ecma-objects.h" +#include "lit-char-helpers.h" #include "vm.h" #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) /** - * Check if property is exported from the script. - * @returns the export name - if the given property is exported - * NULL - otherwise + * Takes a ModuleSpecifier and applies path normalization to it. + * It's not checked if the ModuleSpecifier is a valid path or not. + * Note: See 15.2.1.17 + * + * @return pointer to ecma_string_t containing the normalized and zero terminated path */ -static parser_module_names_t * -ecma_parser_module_is_property_exported (ecma_string_t *property_name_p, /**< property name */ - parser_module_node_t *export_node_p) /**< export node */ +ecma_string_t * +ecma_module_create_normalized_path (const uint8_t *char_p, /**< module specifier */ + prop_length_t size) /**< size of module specifier */ { - parser_module_names_t *current_p = export_node_p->module_names_p; + JERRY_ASSERT (size > 0); + ecma_string_t *ret_p; + + /* Zero terminate the string. */ + uint8_t *temp_p = (uint8_t *) jmem_heap_alloc_block (size + 1u); + memcpy (temp_p, char_p, size); + temp_p[size] = LIT_CHAR_NULL; + + uint8_t *normalized_p = (uint8_t *) jmem_heap_alloc_block (ECMA_MODULE_MAX_PATH); + size_t new_size = jerry_port_normalize_path ((const char *) temp_p, + (char *) normalized_p, + ECMA_MODULE_MAX_PATH); - if (current_p == NULL) + + if (new_size == 0) { - return NULL; + /* Failed to normalize path, use original. */ + ret_p = ecma_new_ecma_string_from_utf8 (temp_p, (lit_utf8_size_t) (size + 1u)); } - - for (uint16_t i = 0; i < export_node_p->module_request_count; i++) + else { - parser_module_names_t *next_p = current_p->next_p; + /* Copy the trailing \0 into the string as well, to make it more convenient to use later. */ + ret_p = ecma_new_ecma_string_from_utf8 (normalized_p, (lit_utf8_size_t) (new_size + 1u)); + } - bool found = ecma_compare_ecma_strings (current_p->local_name_p, property_name_p); + jmem_heap_free_block (temp_p, size + 1u); + jmem_heap_free_block (normalized_p, ECMA_MODULE_MAX_PATH); - if (found) + return ret_p; +} /* ecma_module_create_normalized_path */ + +/** + * Checks if we already have a module request in the module list. + * + * @return pointer to found or newly created module structure + */ +ecma_module_t * +ecma_module_find_or_create_module (ecma_string_t * const path_p) /**< module path */ +{ + ecma_module_t *current_p = JERRY_CONTEXT (ecma_modules_p); + while (current_p != NULL) + { + if (ecma_compare_ecma_strings (path_p, current_p->path_p)) { return current_p; } - current_p = next_p; + current_p = current_p->next_p; } - return NULL; -} /* ecma_parser_module_is_property_exported */ + current_p = (ecma_module_t *) jmem_heap_alloc_block (sizeof (ecma_module_t)); + memset (current_p, 0, sizeof (ecma_module_t)); + + ecma_ref_ecma_string (path_p); + current_p->path_p = path_p; + current_p->next_p = JERRY_CONTEXT (ecma_modules_p); + JERRY_CONTEXT (ecma_modules_p) = current_p; + return current_p; +} /* ecma_module_find_or_create_module */ /** - * Compare property name with imports. - * @return the export name - if the exported property is imported - * NULL - otherwise + * Creates a module context. + * + * @return pointer to created module context */ -static parser_module_names_t * -ecma_parser_module_compare_property_name_with_import (parser_module_node_t *module_node_p, /**< module node */ - parser_module_names_t *export_names_p) /**< export names */ +static ecma_module_context_t * +ecma_module_create_module_context (void) { - parser_module_names_t *current_p = module_node_p->module_names_p; + ecma_module_context_t *context_p = (ecma_module_context_t *) jmem_heap_alloc_block (sizeof (ecma_module_context_t)); + memset (context_p, 0, sizeof (ecma_module_context_t)); - if (current_p == NULL) - { - return NULL; - } + return context_p; +} /* ecma_module_create_module_context */ - for (uint16_t i = 0; i < module_node_p->module_request_count; i++) - { - parser_module_names_t *next_p = current_p->next_p; +/** + * Inserts a {module, export_name} record into a resolve set. + * Note: See 15.2.1.16.3 - resolveSet and exportStarSet + * + * @return true - if the set already contains the record + * false - otherwise + */ +bool +ecma_module_resolve_set_insert (ecma_module_resolve_set_t **set_p, /**< [in, out] resolve set */ + ecma_module_t * const module_p, /**< module */ + ecma_string_t * const export_name_p) /**< export name */ +{ + JERRY_ASSERT (set_p != NULL); + ecma_module_resolve_set_t *current_p = *set_p; - if (ecma_compare_ecma_strings (current_p->local_name_p, export_names_p->import_name_p)) + while (current_p != NULL) + { + if (current_p->record.module_p == module_p + && ecma_compare_ecma_strings (current_p->record.name_p, export_name_p)) { - return current_p; + return false; } - current_p = next_p; + current_p = current_p->next_p; } - return NULL; -} /* ecma_parser_module_compare_property_name_with_import */ + ecma_module_resolve_set_t *new_p; + new_p = (ecma_module_resolve_set_t *) jmem_heap_alloc_block (sizeof (ecma_module_resolve_set_t)); + + new_p->next_p = *set_p; + new_p->record.module_p = module_p; + ecma_ref_ecma_string (export_name_p); + new_p->record.name_p = export_name_p; + + *set_p = new_p; + return true; +} /* ecma_module_resolve_set_insert */ /** - * Connect the imported script's properties to the main script. + * Cleans up contents of a resolve set. */ -static void -ecma_module_connect_properties (ecma_object_t *scope_p) /** scope_p */ +void +ecma_module_resolve_set_cleanup (ecma_module_resolve_set_t *set_p) /**< resolve set */ { - JERRY_ASSERT (ecma_is_lexical_environment (scope_p)); - JERRY_ASSERT (ecma_get_lex_env_type (scope_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE); + while (set_p != NULL) + { + ecma_module_resolve_set_t *next_p = set_p->next_p; + ecma_deref_ecma_string (set_p->record.name_p); + jmem_heap_free_block (set_p, sizeof (ecma_module_resolve_set_t)); + set_p = next_p; + } +} /* ecma_module_resolve_set_cleanup */ - parser_module_context_t *module_context_p = JERRY_CONTEXT (module_top_context_p); +/** + * Pushes a new resolve frame on top of a resolve stack and initializes it + * to begin resolving the specified exported name in the base module. + */ +void +ecma_module_resolve_stack_push (ecma_module_resolve_stack_t **stack_p, /**< [in, out] resolve stack */ + ecma_module_t * const module_p, /**< base module */ + ecma_string_t * const export_name_p) /**< exported name */ +{ + JERRY_ASSERT (stack_p != NULL); + ecma_module_resolve_stack_t *new_frame_p; + new_frame_p = (ecma_module_resolve_stack_t *) jmem_heap_alloc_block (sizeof (ecma_module_resolve_stack_t)); - if (module_context_p == NULL || module_context_p->exports_p == NULL || module_context_p->imports_p == NULL) + ecma_ref_ecma_string (export_name_p); + new_frame_p->export_name_p = export_name_p; + new_frame_p->module_p = module_p; + new_frame_p->resolving = false; + + new_frame_p->next_p = *stack_p; + *stack_p = new_frame_p; +} /* ecma_module_resolve_stack_push */ + +/** + * Pops the topmost frame from a resolve stack. + */ +void +ecma_module_resolve_stack_pop (ecma_module_resolve_stack_t **stack_p) /**< [in, out] resolve stack */ +{ + JERRY_ASSERT (stack_p != NULL); + ecma_module_resolve_stack_t *current_p = *stack_p; + + if (current_p != NULL) { - return; + *stack_p = current_p->next_p; + ecma_deref_ecma_string (current_p->export_name_p); + jmem_heap_free_block (current_p, sizeof (ecma_module_resolve_stack_t)); } +} /* ecma_module_resolve_stack_pop */ + +/** + * Resolves which module satisfies an export based from a specific module in the import tree. + * If no error occurs, out_record_p will contain a {module, local_name} record, which satisfies + * the export, or {NULL, NULL} if the export is ambiguous. + * Note: See 15.2.1.16.3 + * + * @return ECMA_VALUE_ERROR - if an error occured + * ECMA_VALUE_EMPTY - otherwise + */ +static ecma_value_t +ecma_module_resolve_export (ecma_module_t * const module_p, /**< base module */ + ecma_string_t * const export_name_p, /**< export name */ + ecma_module_record_t *out_record_p) /**< [out] found module record */ +{ + ecma_module_resolve_set_t *resolve_set_p = NULL; + ecma_module_resolve_stack_t *stack_p = NULL; + + bool found = false; + ecma_module_record_t found_record = { NULL, NULL }; + ecma_value_t ret_value = ECMA_VALUE_EMPTY; - ecma_object_t *global_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL); - ecma_property_header_t *module_properties_p = ecma_get_property_list (scope_p); + ecma_module_resolve_stack_push (&stack_p, module_p, export_name_p); - while (module_properties_p != NULL) + while (stack_p != NULL) { - ecma_property_pair_t *prop_pair_p = (ecma_property_pair_t *) module_properties_p; + ecma_module_resolve_stack_t *current_frame_p = stack_p; - for (int i = 0; i < ECMA_PROPERTY_PAIR_ITEM_COUNT; i++) + ecma_module_t *current_module_p = current_frame_p->module_p; + JERRY_ASSERT (current_module_p->state >= ECMA_MODULE_STATE_PARSED); + ecma_module_context_t *context_p = current_module_p->context_p; + ecma_string_t *current_export_name_p = current_frame_p->export_name_p; + + if (!current_frame_p->resolving) { - ecma_property_t *property_p = (ecma_property_t *) (module_properties_p->types + i); + current_frame_p->resolving = true; - if (ECMA_PROPERTY_GET_NAME_TYPE (*property_p) == ECMA_DIRECT_STRING_MAGIC - && prop_pair_p->names_cp[i] >= LIT_NON_INTERNAL_MAGIC_STRING__COUNT) + /* 15.2.1.16.3 / 2-3 */ + if (!ecma_module_resolve_set_insert (&resolve_set_p, current_module_p, current_export_name_p)) { + /* This is a circular import request. */ + ecma_module_resolve_stack_pop (&stack_p); continue; } - ecma_string_t *prop_name_p = ecma_string_from_property_name (*property_p, prop_pair_p->names_cp[i]); - - parser_module_names_t *exported_name_p = ecma_parser_module_is_property_exported (prop_name_p, - module_context_p->exports_p); + if (context_p->local_exports_p != NULL) + { + /* 15.2.1.16.3 / 4 */ + JERRY_ASSERT (context_p->local_exports_p->next_p == NULL); + ecma_module_names_t *export_names_p = context_p->local_exports_p->module_names_p; + while (export_names_p != NULL) + { + if (ecma_compare_ecma_strings (current_export_name_p, export_names_p->imex_name_p)) + { + if (found) + { + /* This is an ambigous export. */ + found_record.module_p = NULL; + found_record.name_p = NULL; + break; + } + + /* The current module provides a direct binding for this export. */ + found = true; + found_record.module_p = current_module_p; + found_record.name_p = export_names_p->local_name_p; + break; + } + + export_names_p = export_names_p->next_p; + } + } - if (exported_name_p == NULL) + if (found) { - ecma_deref_ecma_string (prop_name_p); + /* We found a resolution for the current frame, return to the previous. */ + ecma_module_resolve_stack_pop (&stack_p); continue; } - parser_module_names_t *new_name_p = - ecma_parser_module_compare_property_name_with_import (module_context_p->imports_p, - exported_name_p); - - if (new_name_p != NULL) + /* 15.2.1.16.3 / 5 */ + ecma_module_node_t *indirect_export_p = context_p->indirect_exports_p; + while (indirect_export_p != NULL) { - ecma_property_t *new_property_p; - ecma_create_named_data_property (global_obj_p, - new_name_p->import_name_p, - ECMA_PROPERTY_NOT_WRITABLE, - &new_property_p); + ecma_module_names_t *export_names_p = indirect_export_p->module_names_p; + while (export_names_p != NULL) + { + if (ecma_compare_ecma_strings (current_export_name_p, export_names_p->imex_name_p)) + { + /* 5.2.1.16.3 / 5.a.iv */ + ecma_module_resolve_stack_push (&stack_p, + indirect_export_p->module_request_p, + export_names_p->local_name_p); + } + + export_names_p = export_names_p->next_p; + } + + indirect_export_p = indirect_export_p->next_p; + } - ecma_named_data_property_assign_value (global_obj_p, - ECMA_PROPERTY_VALUE_PTR (new_property_p), - prop_pair_p->values[i].value); + /* We need to check whether the newly pushed indirect exports resolve to anything. + * Keep current frame in the stack, and continue from the topmost frame. */ + continue; + } /* if (!current_frame_p->resolving) */ - } - ecma_deref_ecma_string (prop_name_p); + /* By the time we return to the current frame, the indirect exports will have finished resolving. */ + if (found) + { + /* We found at least one export that satisfies the current request. + * Pop current frame, and return to the previous. */ + ecma_module_resolve_stack_pop (&stack_p); + continue; + } + + /* 15.2.1.16.3 / 6 */ + if (ecma_compare_ecma_string_to_magic_id (current_export_name_p, LIT_MAGIC_STRING_DEFAULT)) + { + ret_value = ecma_raise_syntax_error (ECMA_ERR_MSG ("No explicitly defined default export in module.")); + break; + } + + /* 15.2.1.16.3 / 7-8 */ + if (!ecma_module_resolve_set_insert (&resolve_set_p, + current_module_p, + ecma_get_magic_string (LIT_MAGIC_STRING_ASTERIX_CHAR))) + { + /* This is a circular import request. */ + ecma_module_resolve_stack_pop (&stack_p); + continue; } - module_properties_p = ECMA_GET_POINTER (ecma_property_header_t, - module_properties_p->next_property_cp); + /* Pop the current frame, we have nothing else to do here after the star export resolutions are queued. */ + ecma_module_resolve_stack_pop (&stack_p); + + /* 15.2.1.16.3 / 10 */ + ecma_module_node_t *star_export_p = context_p->star_exports_p; + while (star_export_p != NULL) + { + JERRY_ASSERT (star_export_p->module_names_p == NULL); + + /* 15.2.1.16.3 / 10.c */ + ecma_module_resolve_stack_push (&stack_p, star_export_p->module_request_p, export_name_p); + + star_export_p = star_export_p->next_p; + } } - ecma_module_add_lex_env (scope_p); - parser_module_free_saved_names (module_context_p->exports_p); -} /* ecma_module_connect_properties */ + /* Clean up. */ + ecma_module_resolve_set_cleanup (resolve_set_p); + while (stack_p) + { + ecma_module_resolve_stack_pop (&stack_p); + } + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + /* No default export was found */ + return ret_value; + } + + if (found) + { + *out_record_p = found_record; + } + else + { + ret_value = ecma_raise_syntax_error (ECMA_ERR_MSG ("Unexported or circular import request.")); + } + + return ret_value; +} /* ecma_module_resolve_export */ /** - * Run an EcmaScript module loaded by ecma_module_load_modules. + * Resolves an export and adds it to the modules namespace object, if the export name is not yet handled. + * Note: See 15.2.1.16.2 and 15.2.1.18 + * + * @return ECMA_VALUE_ERROR - if an error occured + * ECMA_VALUE_EMPTY - otherwise */ -static parser_error_t -ecma_parser_module_run (const char *file_path_p, /**< file path */ - size_t path_size, /**< length of the path */ - const char *source_p, /**< module source */ - size_t source_size, /**< length of the source */ - parser_module_node_t *module_node_p) /**< module node */ +static ecma_value_t +ecma_module_namespace_object_add_export_if_needed (ecma_module_t *module_p, /**< module */ + ecma_string_t *export_name_p) /**< export name */ { - parser_module_node_t export_node; - memset (&export_node, 0, sizeof (parser_module_node_t)); + JERRY_ASSERT (module_p->namespace_object_p != NULL); + ecma_value_t result = ECMA_VALUE_EMPTY; + + if (ecma_find_named_property (module_p->namespace_object_p, export_name_p) != NULL) + { + /* This export name has already been handled. */ + return result; + } - parser_module_context_t module_context; - module_context.imports_p = module_node_p; - module_context.exports_p = &export_node; + ecma_module_record_t record; + result = ecma_module_resolve_export (module_p, export_name_p, &record); - parser_module_context_t *prev_module_context_p = JERRY_CONTEXT (module_top_context_p); - JERRY_CONTEXT (module_top_context_p) = &module_context; + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } - jerry_value_t ret_value = jerry_parse ((jerry_char_t *) file_path_p, - path_size, - (jerry_char_t *) source_p, - source_size, - JERRY_PARSE_STRICT_MODE); + if (record.module_p == NULL) + { + /* 15.2.1.18 / 3.d.iv Skip ambiguous names. */ + return result; + } + ecma_object_t *ref_base_lex_env_p; + ecma_value_t prop_value = ecma_op_get_value_lex_env_base (record.module_p->scope_p, + &ref_base_lex_env_p, + record.name_p); + ecma_property_t *new_property_p; + ecma_create_named_data_property (module_p->namespace_object_p, + export_name_p, + ECMA_PROPERTY_FIXED, + &new_property_p); - if (jerry_value_is_error (ret_value)) + ecma_named_data_property_assign_value (module_p->namespace_object_p, + ECMA_PROPERTY_VALUE_PTR (new_property_p), + prop_value); + + ecma_free_value (prop_value); + return result; +} /* ecma_module_namespace_object_add_export_if_needed */ + +/** + * Creates a namespace object for a module. + * Note: See 15.2.1.18 + * + * @return ECMA_VALUE_ERROR - if an error occured + * ECMA_VALUE_EMPTY - otherwise + */ +static ecma_value_t +ecma_module_create_namespace_object (ecma_module_t *module_p) /**< module */ +{ + ecma_value_t result = ECMA_VALUE_EMPTY; + if (module_p->namespace_object_p != NULL) { - jerry_release_value (ret_value); - return PARSER_ERR_MODULE_REQUEST_NOT_FOUND; + return result; } - parser_error_t error = PARSER_ERR_NO_ERROR; + JERRY_ASSERT (module_p->state == ECMA_MODULE_STATE_EVALUATED); + ecma_module_resolve_set_t *resolve_set_p = NULL; + ecma_module_resolve_stack_t *stack_p = NULL; + + module_p->namespace_object_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE), + 0, + ECMA_OBJECT_TYPE_GENERAL); + + ecma_module_resolve_stack_push (&stack_p, module_p, ecma_get_magic_string (LIT_MAGIC_STRING_ASTERIX_CHAR)); + while (stack_p != NULL) + { + ecma_module_resolve_stack_t *current_frame_p = stack_p; + ecma_module_t *current_module_p = current_frame_p->module_p; + ecma_module_context_t *context_p = current_module_p->context_p; + + ecma_module_resolve_stack_pop (&stack_p); + + /* 15.2.1.16.2 / 2-3 */ + if (!ecma_module_resolve_set_insert (&resolve_set_p, + current_module_p, + ecma_get_magic_string (LIT_MAGIC_STRING_ASTERIX_CHAR))) + { + /* Circular import. */ + continue; + } + + if (context_p->local_exports_p != NULL) + { + /* 15.2.1.16.2 / 5 */ + JERRY_ASSERT (context_p->local_exports_p->next_p == NULL); + ecma_module_names_t *export_names_p = context_p->local_exports_p->module_names_p; + while (export_names_p != NULL && ecma_is_value_empty (result)) + { + result = ecma_module_namespace_object_add_export_if_needed (module_p, + export_names_p->imex_name_p); + export_names_p = export_names_p->next_p; + } + } + + /* 15.2.1.16.2 / 6 */ + ecma_module_node_t *indirect_export_p = context_p->indirect_exports_p; + while (indirect_export_p != NULL && ecma_is_value_empty (result)) + { + ecma_module_names_t *export_names_p = indirect_export_p->module_names_p; + while (export_names_p != NULL && ecma_is_value_empty (result)) + { + result = ecma_module_namespace_object_add_export_if_needed (module_p, + export_names_p->imex_name_p); + export_names_p = export_names_p->next_p; + } + indirect_export_p = indirect_export_p->next_p; + } - jerry_value_t func_val = ret_value; - ecma_object_t *func_obj_p = ecma_get_object_from_value (func_val); + /* 15.2.1.16.2 / 7 */ + ecma_module_node_t *star_export_p = context_p->star_exports_p; + while (star_export_p != NULL && ecma_is_value_empty (result)) + { + JERRY_ASSERT (star_export_p->module_names_p == NULL); - JERRY_ASSERT (ecma_get_object_type (func_obj_p) == ECMA_OBJECT_TYPE_FUNCTION); + /* 15.2.1.16.3/10.c */ + ecma_module_resolve_stack_push (&stack_p, + star_export_p->module_request_p, + ecma_get_magic_string (LIT_MAGIC_STRING_ASTERIX_CHAR)); - ecma_object_t *scope_p = ecma_create_decl_lex_env (ecma_get_global_environment ()); - ret_value = vm_run_module (ecma_op_function_get_compiled_code ((ecma_extended_object_t *) func_obj_p), scope_p); + star_export_p = star_export_p->next_p; + } + } - if (jerry_value_is_error (ret_value)) + /* Clean up. */ + ecma_module_resolve_set_cleanup (resolve_set_p); + while (stack_p) + { + ecma_module_resolve_stack_pop (&stack_p); + } + + return result; +} /* ecma_module_create_namespace_object */ + +/** + * Evaluates an EcmaScript module. + * + * @return ECMA_VALUE_ERROR - if an error occured + * ECMA_VALUE_EMPTY - otherwise + */ +static ecma_value_t +ecma_module_evaluate (ecma_module_t *module_p) /**< module */ +{ + JERRY_ASSERT (module_p->state >= ECMA_MODULE_STATE_PARSED); + + if (module_p->state >= ECMA_MODULE_STATE_EVALUATING) + { + return ECMA_VALUE_EMPTY; + } + + module_p->state = ECMA_MODULE_STATE_EVALUATING; + module_p->scope_p = ecma_create_decl_lex_env (ecma_get_global_environment ()); + module_p->context_p->parent_p = JERRY_CONTEXT (module_top_context_p); + JERRY_CONTEXT (module_top_context_p) = module_p->context_p; + + ecma_value_t ret_value; + ret_value = vm_run_module (ecma_op_function_get_compiled_code ((ecma_extended_object_t *) module_p->compiled_code_p), + module_p->scope_p); + + if (!ECMA_IS_VALUE_ERROR (ret_value)) { jerry_release_value (ret_value); - error = PARSER_ERR_MODULE_REQUEST_NOT_FOUND; + ret_value = ECMA_VALUE_EMPTY; } - ecma_module_connect_properties (scope_p); - jerry_release_value (func_val); + JERRY_CONTEXT (module_top_context_p) = module_p->context_p->parent_p; - JERRY_CONTEXT (module_top_context_p) = prev_module_context_p; - return error; -} /* ecma_parser_module_run */ + ecma_deref_object (module_p->compiled_code_p); + module_p->state = ECMA_MODULE_STATE_EVALUATED; + + return ret_value; +} /* ecma_module_evaluate */ /** - * Load imported modules. + * Connects imported values to the current context. + * + * @return ECMA_VALUE_ERROR - if an error occured + * ECMA_VALUE_EMPTY - otherwise */ -void -ecma_module_load_modules (parser_context_t *context_p) /**< parser context */ +ecma_value_t +ecma_module_connect_imports (void) { - parser_module_node_t *current_p = context_p->module_context_p->imports_p; + ecma_module_context_t *current_context_p = JERRY_CONTEXT (module_top_context_p); - while (current_p != NULL) + ecma_object_t *local_env_p; + + if (current_context_p->module_p != NULL) + { + local_env_p = current_context_p->module_p->scope_p; + } + else { - uint8_t *script_path_p = current_p->script_path.value_p; - prop_length_t path_length = current_p->script_path.length; + /* This is the root context. */ + local_env_p = ecma_get_global_environment (); + } + JERRY_ASSERT (ecma_is_lexical_environment (local_env_p)); - size_t size = 0; - uint8_t *buffer_p = jerry_port_read_source ((const char *) script_path_p, &size); + ecma_module_node_t *import_node_p = current_context_p->imports_p; + while (import_node_p != NULL) + { + ecma_value_t result = ecma_module_evaluate (import_node_p->module_request_p); + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } - if (buffer_p == NULL) + ecma_module_names_t *import_names_p = import_node_p->module_names_p; + while (import_names_p != NULL) { - parser_raise_error (context_p, PARSER_ERR_FILE_NOT_FOUND); + const bool is_namespace_import = ecma_compare_ecma_string_to_magic_id (import_names_p->imex_name_p, + LIT_MAGIC_STRING_ASTERIX_CHAR); + + if (is_namespace_import) + { + result = ecma_module_create_namespace_object (import_node_p->module_request_p); + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + ecma_op_create_mutable_binding (local_env_p, import_names_p->local_name_p, true /* is_deletable */); + ecma_op_set_mutable_binding (local_env_p, + import_names_p->local_name_p, + ecma_make_object_value (import_node_p->module_request_p->namespace_object_p), + false /* is_strict */); + } + else /* !is_namespace_import */ + { + ecma_module_record_t record; + result = ecma_module_resolve_export (import_node_p->module_request_p, import_names_p->imex_name_p, &record); + + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + if (record.module_p == NULL) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Ambiguous import request.")); + } + + result = ecma_module_evaluate (record.module_p); + + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + ecma_object_t *ref_base_lex_env_p; + ecma_value_t prop_value = ecma_op_get_value_lex_env_base (record.module_p->scope_p, + &ref_base_lex_env_p, + record.name_p); + + ecma_op_create_mutable_binding (local_env_p, import_names_p->local_name_p, true /* is_deletable */); + ecma_op_set_mutable_binding (local_env_p, + import_names_p->local_name_p, + prop_value, + false /* is_strict */); + + ecma_free_value (prop_value); + } + + import_names_p = import_names_p->next_p; } - parser_error_t error = ecma_parser_module_run ((const char *) script_path_p, - path_length, - (const char *) buffer_p, - size, - current_p); + import_node_p = import_node_p->next_p; + } - jerry_port_release_source (buffer_p); + return ECMA_VALUE_EMPTY; +} /* ecma_module_connect_imports */ - if (error != PARSER_ERR_NO_ERROR) +/** + * Parses an EcmaScript module. + * + * @return ECMA_VALUE_ERROR - if an error occured + * ECMA_VALUE_EMPTY - otherwise + */ +static jerry_value_t +ecma_module_parse (ecma_module_t *module_p) /**< module */ +{ + if (module_p->state >= ECMA_MODULE_STATE_PARSING) + { + return ECMA_VALUE_EMPTY; + } + + module_p->state = ECMA_MODULE_STATE_PARSING; + module_p->context_p = ecma_module_create_module_context (); + + lit_utf8_size_t script_path_size; + uint8_t flags = ECMA_STRING_FLAG_EMPTY; + const lit_utf8_byte_t *script_path_p = ecma_string_get_chars (module_p->path_p, + &script_path_size, + &flags); + + size_t source_size = 0; + uint8_t *source_p = jerry_port_read_source ((const char *) script_path_p, &source_size); + + if (source_p == NULL) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("File not found.")); + } + + module_p->context_p->module_p = module_p; + module_p->context_p->parent_p = JERRY_CONTEXT (module_top_context_p); + JERRY_CONTEXT (module_top_context_p) = module_p->context_p; + + ecma_value_t ret_value = jerry_parse ((jerry_char_t *) script_path_p, + script_path_size, + (jerry_char_t *) source_p, + source_size, + JERRY_PARSE_NO_OPTS); + + JERRY_CONTEXT (module_top_context_p) = module_p->context_p->parent_p; + + jerry_port_release_source (source_p); + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + return ret_value; + } + + module_p->compiled_code_p = ecma_get_object_from_value (ret_value); + module_p->state = ECMA_MODULE_STATE_PARSED; + + return ECMA_VALUE_EMPTY; +} /* ecma_module_parse */ + +/** + * Parses all referenced modules. + * + * @return ECMA_VALUE_ERROR - if an error occured + * ECMA_VALUE_EMPTY - otherwise + */ +ecma_value_t +ecma_module_parse_modules (void) +{ + ecma_module_t *current_p = JERRY_CONTEXT (ecma_modules_p); + + while (current_p != NULL) + { + ecma_value_t ret_value = ecma_module_parse (current_p); + if (ECMA_IS_VALUE_ERROR (ret_value)) { - parser_raise_error (context_p, error); + return ret_value; } + JERRY_ASSERT (ecma_is_value_empty (ret_value)); current_p = current_p->next_p; } -} /* ecma_module_load_modules */ + + return ECMA_VALUE_EMPTY; +} /* ecma_module_parse_modules */ + +/** + * Checks if indirect exports in the current context are resolvable. + * Note: See 15.2.1.16.4 / 9. + * + * @return ECMA_VALUE_ERROR - if an error occured + * ECMA_VALUE_EMPTY - otherwise + */ +ecma_value_t +ecma_module_check_indirect_exports (void) +{ + ecma_module_node_t *indirect_export_p = JERRY_CONTEXT (module_top_context_p)->indirect_exports_p; + while (indirect_export_p != NULL) + { + ecma_module_names_t *name_p = indirect_export_p->module_names_p; + while (name_p != NULL) + { + ecma_module_record_t record; + ecma_value_t result = ecma_module_resolve_export (indirect_export_p->module_request_p, + name_p->local_name_p, + &record); + + if (ECMA_IS_VALUE_ERROR (result)) + { + return result; + } + + if (record.module_p == NULL) + { + return ecma_raise_syntax_error (ECMA_ERR_MSG ("Ambiguous indirect export request.")); + } + + name_p = name_p->next_p; + } + + indirect_export_p = indirect_export_p->next_p; + } + + return ECMA_VALUE_EMPTY; +} /* ecma_module_check_indirect_exports */ + +/** + * Cleans up a list of module names. + */ +void +ecma_module_release_module_names (ecma_module_names_t *module_name_p) /**< first module name */ +{ + while (module_name_p != NULL) + { + ecma_module_names_t *next_p = module_name_p->next_p; + + ecma_deref_ecma_string (module_name_p->imex_name_p); + ecma_deref_ecma_string (module_name_p->local_name_p); + jmem_heap_free_block (module_name_p, sizeof (ecma_module_names_t)); + + module_name_p = next_p; + } +} /* ecma_module_release_module_names */ + +/** + * Cleans up a list of module nodes. + */ +static void +ecma_module_release_module_nodes (ecma_module_node_t *module_node_p) /**< first module node */ +{ + while (module_node_p != NULL) + { + ecma_module_node_t *next_p = module_node_p->next_p; + + ecma_module_release_module_names (module_node_p->module_names_p); + jmem_heap_free_block (module_node_p, sizeof (ecma_module_node_t)); + + module_node_p = next_p; + } +} /* ecma_module_release_module_nodes */ + +/** + * Cleans up a module context. + */ +static void +ecma_module_release_module_context (ecma_module_context_t *module_context_p) /**< modle context */ +{ + ecma_module_release_module_nodes (module_context_p->imports_p); + ecma_module_release_module_nodes (module_context_p->local_exports_p); + ecma_module_release_module_nodes (module_context_p->indirect_exports_p); + ecma_module_release_module_nodes (module_context_p->star_exports_p); + + jmem_heap_free_block (module_context_p, sizeof (ecma_module_context_t)); +} /* ecma_module_release_module_context */ + +/** + * Cleans up a module structure. + */ +static void +ecma_module_release_module (ecma_module_t *module_p) /**< module */ +{ + ecma_deref_ecma_string (module_p->path_p); + if (module_p->state >= ECMA_MODULE_STATE_PARSING) + { + ecma_module_release_module_context (module_p->context_p); + } + + if (module_p->state >= ECMA_MODULE_STATE_EVALUATING) + { + ecma_deref_object (module_p->scope_p); + } + + if (module_p->state >= ECMA_MODULE_STATE_PARSED + && module_p->state < ECMA_MODULE_STATE_EVALUATED) + { + ecma_deref_object (module_p->compiled_code_p); + } + + if (module_p->namespace_object_p != NULL) + { + ecma_deref_object (module_p->namespace_object_p); + } + + jmem_heap_free_block (module_p, sizeof (ecma_module_t)); +} /* ecma_module_release_module */ + +/** + * Cleans up all modules if the current context is the root context. + */ +void +ecma_module_cleanup (void) +{ + if (JERRY_CONTEXT (module_top_context_p)->parent_p != NULL) + { + return; + } + + ecma_module_t *current_p = JERRY_CONTEXT (ecma_modules_p); + while (current_p != NULL) + { + ecma_module_t *next_p = current_p->next_p; + ecma_module_release_module (current_p); + current_p = next_p; + } + + ecma_module_release_module_context (JERRY_CONTEXT (module_top_context_p)); + JERRY_CONTEXT (module_top_context_p) = NULL; +} /* ecma_module_cleanup */ #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ diff --git a/jerry-core/ecma/base/ecma-module.h b/jerry-core/ecma/base/ecma-module.h index 7ecfea8f2e..9511747715 100644 --- a/jerry-core/ecma/base/ecma-module.h +++ b/jerry-core/ecma/base/ecma-module.h @@ -16,12 +16,125 @@ #ifndef ECMA_MODULE_H #define ECMA_MODULE_H -#include "js-parser-internal.h" - #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) -void ecma_module_load_modules (parser_context_t *context_p); +#include "common.h" +#include "ecma-globals.h" + +#define ECMA_MODULE_MAX_PATH 255u + +/** + * Imported or exported names, such as "a as b" + * Note: See https://www.ecma-international.org/ecma-262/6.0/#table-39 + * and https://www.ecma-international.org/ecma-262/6.0/#table-41 + */ +typedef struct ecma_module_names +{ + struct ecma_module_names *next_p; /**< next linked list node */ + ecma_string_t *imex_name_p; /**< Import/export name of the item */ + ecma_string_t *local_name_p; /**< Local name of the item */ +} ecma_module_names_t; + +typedef struct ecma_module ecma_module_t; + +/** + * Module node to store imports / exports. + */ +typedef struct ecma_module_node +{ + struct ecma_module_node *next_p; /**< next linked list node */ + ecma_module_names_t *module_names_p; /**< names of the requested import/export node */ + ecma_module_t *module_request_p; /**< module structure of the requested module */ +} ecma_module_node_t; + +/** + * Module context containing all import and export nodes. + */ +typedef struct ecma_module_context +{ + struct ecma_module_context *parent_p; /**< parent context */ + ecma_module_node_t *imports_p; /**< import item of the current context */ + ecma_module_node_t *local_exports_p; /**< export item of the current context */ + ecma_module_node_t *indirect_exports_p; /**< export item of the current context */ + ecma_module_node_t *star_exports_p; /**< export item of the current context */ + ecma_module_t *module_p; /**< module request */ +} ecma_module_context_t; + +/** + * An enum identifing the current state of the module + */ +typedef enum +{ + ECMA_MODULE_STATE_INIT = 0, /**< module is initialized */ + ECMA_MODULE_STATE_PARSING = 1, /**< module is currently being parsed */ + ECMA_MODULE_STATE_PARSED = 2, /**< module has been parsed */ + ECMA_MODULE_STATE_EVALUATING = 3, /**< module is currently being evaluated */ + ECMA_MODULE_STATE_EVALUATED = 4, /**< module has been evaluated */ +} ecma_module_state_t; + +/** + * Module structure storing an instance of a module + */ +struct ecma_module +{ + struct ecma_module *next_p; /**< next linked list node */ + ecma_module_state_t state; /**< state of the mode */ + ecma_string_t *path_p; /**< path of the module */ + ecma_module_context_t *context_p; /**< module context of the module */ + ecma_object_t *compiled_code_p; /**< compiled code of the module */ + ecma_object_t *scope_p; /**< lexica lenvironment of the module */ + ecma_object_t *namespace_object_p; /**< namespace import object of the module */ +}; + +/** + * A record that can be used to store {module, identifier} pairs + */ +typedef struct ecma_module_record +{ + ecma_module_t *module_p; /**< module */ + ecma_string_t *name_p; /**< identifier name */ +} ecma_module_record_t; + +/** + * A list of module records that can be used to identify circular imports during resolution + */ +typedef struct ecma_module_resolve_set +{ + struct ecma_module_resolve_set *next_p; /**< next in linked list */ + ecma_module_record_t record; /**< module record */ +} ecma_module_resolve_set_t; + +/** + * A list that is used like a stack to drive the resolution process, instead of recursion. + */ +typedef struct ecma_module_resolve_stack +{ + struct ecma_module_resolve_stack *next_p; /**< next in linked list */ + ecma_module_t *module_p; /**< module request */ + ecma_string_t *export_name_p; /**< export identifier name */ + bool resolving; /**< flag storing wether the current frame started resolving */ +} ecma_module_resolve_stack_t; + +bool ecma_module_resolve_set_insert (ecma_module_resolve_set_t **set_p, + ecma_module_t *module_p, + ecma_string_t *export_name_p); +void ecma_module_resolve_set_cleanup (ecma_module_resolve_set_t *set_p); + +void ecma_module_resolve_stack_push (ecma_module_resolve_stack_t **stack_p, + ecma_module_t *module_p, + ecma_string_t *export_name_p); +void ecma_module_resolve_stack_pop (ecma_module_resolve_stack_t **stack_p); + +ecma_string_t *ecma_module_create_normalized_path (const uint8_t *char_p, + prop_length_t size); +ecma_module_t *ecma_module_find_or_create_module (ecma_string_t *path_p); + +ecma_value_t ecma_module_connect_imports (void); +ecma_value_t ecma_module_parse_modules (void); +ecma_value_t ecma_module_check_indirect_exports (void); +void ecma_module_release_module_names (ecma_module_names_t *module_name_p); +void ecma_module_cleanup (void); #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ #endif /* !ECMA_MODULE_H */ diff --git a/jerry-core/ecma/operations/ecma-lex-env.c b/jerry-core/ecma/operations/ecma-lex-env.c index 73c548dfa4..de5bb96c01 100644 --- a/jerry-core/ecma/operations/ecma-lex-env.c +++ b/jerry-core/ecma/operations/ecma-lex-env.c @@ -68,46 +68,6 @@ ecma_get_global_environment (void) return JERRY_CONTEXT (ecma_global_lex_env_p); } /* ecma_get_global_environment */ -#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) -/** - * Add the lexenv of the newly imported module to the JERRY_CONTEXT. - */ -void -ecma_module_add_lex_env (ecma_object_t *lex_env_p) /**< module lexenv */ -{ - JERRY_ASSERT (lex_env_p != NULL); - JERRY_ASSERT (ecma_is_lexical_environment (lex_env_p)); - - ecma_module_lex_envs_t *new_module_lex_env_p; - new_module_lex_env_p = jmem_heap_alloc_block (sizeof (ecma_module_lex_envs_t)); - new_module_lex_env_p->lex_env_p = lex_env_p; - - new_module_lex_env_p->next_p = JERRY_CONTEXT (ecma_module_lex_envs_p); - JERRY_CONTEXT (ecma_module_lex_envs_p) = new_module_lex_env_p; -} /* ecma_module_add_lex_env */ - -/** - * Finalize the lexenvs of the imported modules and its ECMA components. - */ -void -ecma_module_finalize_lex_envs (void) -{ - ecma_module_lex_envs_t *module_lex_envs = JERRY_CONTEXT (ecma_module_lex_envs_p); - - while (module_lex_envs != NULL) - { - ecma_module_lex_envs_t *next_p = module_lex_envs->next_p; - - ecma_deref_object (module_lex_envs->lex_env_p); - jmem_heap_free_block (module_lex_envs, sizeof (ecma_module_lex_envs_t)); - - module_lex_envs = next_p; - } - - JERRY_CONTEXT (ecma_module_lex_envs_p) = NULL; -} /* ecma_module_finalize_lex_envs */ -#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ - /** * @} */ diff --git a/jerry-core/include/jerryscript-port.h b/jerry-core/include/jerryscript-port.h index 96a4daca36..84f0ba50fb 100644 --- a/jerry-core/include/jerryscript-port.h +++ b/jerry-core/include/jerryscript-port.h @@ -199,11 +199,11 @@ void jerry_port_print_char (char c); * is enabled. The path is specified in the import statement's 'from "..."' * section. * - * @param file_name_p Path that points to the EcmaScript file in the - * filesystem. - * @param out_size_p The opened file's size in bytes. + * @param file_name_p Path that points to the EcmaScript file in the + * filesystem. + * @param out_size_p The opened file's size in bytes. * - * @return the pointer to the buffer which contains the content of the file. + * @return the pointer to the buffer which contains the content of the file. */ uint8_t *jerry_port_read_source (const char *file_name_p, size_t *out_size_p); @@ -215,6 +215,22 @@ uint8_t *jerry_port_read_source (const char *file_name_p, size_t *out_size_p); */ void jerry_port_release_source (uint8_t *buffer_p); +/** + * Normalize a file path string. + * + * Note: + * This port function is called by jerry-core when ES2015_MODULE_SYSTEM + * is enabled. The normalized path is used to uniquely identify modules. + * + * @param in_path_p Input path as a zero terminated string. + * @param out_buf_p Pointer to the output buffer where the normalized path should be written. + * @param out_buf_size Size of the output buffer. + * + * @return length of the string written to the output buffer + * zero, if the buffer was not sufficient or an error occured + */ +size_t jerry_port_normalize_path (const char *in_path_p, char *out_buf_p, size_t out_buf_size); + /** * @} */ diff --git a/jerry-core/jcontext/jcontext.h b/jerry-core/jcontext/jcontext.h index 04c75f82a8..3f71816072 100644 --- a/jerry-core/jcontext/jcontext.h +++ b/jerry-core/jcontext/jcontext.h @@ -67,17 +67,6 @@ typedef struct jerry_context_data_header */ #define JERRY_CONTEXT_FIRST_MEMBER ecma_builtin_objects -#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) -/** - * Contains the lexical environments of the loaded modules. - */ -typedef struct ecma_module_lex_envs -{ - ecma_object_t *lex_env_p; /**< pointer to loaded module's lexical environment */ - struct ecma_module_lex_envs *next_p; /**< pointer to the next item in the linked list */ -} ecma_module_lex_envs_t; -#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ - /** * JerryScript context * @@ -116,8 +105,8 @@ struct jerry_context_t ecma_object_t *ecma_global_lex_env_p; /**< global lexical environment */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - ecma_module_lex_envs_t *ecma_module_lex_envs_p; /**< list of module's lexical environments */ - parser_module_context_t *module_top_context_p; /**< top (current) module parser context */ + ecma_module_t *ecma_modules_p; /**< list of referenced modules */ + ecma_module_context_t *module_top_context_p; /**< top (current) module parser context */ #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ vm_frame_ctx_t *vm_top_context_p; /**< top (current) interpreter context */ diff --git a/jerry-core/lit/lit-magic-strings.inc.h b/jerry-core/lit/lit-magic-strings.inc.h index f794b3d4a3..842c4ab834 100644 --- a/jerry-core/lit/lit-magic-strings.inc.h +++ b/jerry-core/lit/lit-magic-strings.inc.h @@ -22,6 +22,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SPACE_CHAR, " ") #if ENABLED (JERRY_ES2015_BUILTIN_SYMBOL) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_RIGHT_PAREN, ")") #endif +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ASTERIX_CHAR, "*") +#endif LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COMMA_CHAR, ",") #if ENABLED (JERRY_BUILTIN_REGEXP) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_SLASH_CHAR, "/") @@ -325,6 +328,9 @@ LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_BOOLEAN, "boolean") #if ENABLED (JERRY_BUILTIN_ANNEXB) && ENABLED (JERRY_BUILTIN_REGEXP) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_COMPILE, "compile") #endif +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) +LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_DEFAULT, "default") +#endif #if ENABLED (JERRY_BUILTIN_ARRAY) && ENABLED (JERRY_ES2015_BUILTIN_ITERATOR) LIT_MAGIC_STRING_DEF (LIT_MAGIC_STRING_ENTRIES, "entries") #endif diff --git a/jerry-core/lit/lit-magic-strings.ini b/jerry-core/lit/lit-magic-strings.ini index fcc722ca29..60c82bc3be 100644 --- a/jerry-core/lit/lit-magic-strings.ini +++ b/jerry-core/lit/lit-magic-strings.ini @@ -23,6 +23,7 @@ [LIT_MAGIC_STRINGS] LIT_MAGIC_STRING__EMPTY = "" +LIT_MAGIC_STRING_ASTERIX_CHAR = "*" LIT_MAGIC_STRING_SPACE_CHAR = " " LIT_MAGIC_STRING_RIGHT_PAREN = ")" LIT_MAGIC_STRING_COMMA_CHAR = "," @@ -152,6 +153,7 @@ LIT_MAGIC_STRING_SYMBOL_LEFT_PAREN_UL = "Symbol(" LIT_MAGIC_STRING_SYMBOL_DOT_UL = "Symbol." LIT_MAGIC_STRING_BOOLEAN = "boolean" LIT_MAGIC_STRING_COMPILE = "compile" +LIT_MAGIC_STRING_DEFAULT = "default" LIT_MAGIC_STRING_FOR_EACH_UL = "forEach" LIT_MAGIC_STRING_GET_DATE_UL = "getDate" LIT_MAGIC_STRING_GET_INT8_UL = "getInt8" diff --git a/jerry-core/parser/js/js-lexer.c b/jerry-core/parser/js/js-lexer.c index 90167e1b77..8c0fec25af 100644 --- a/jerry-core/parser/js/js-lexer.c +++ b/jerry-core/parser/js/js-lexer.c @@ -2277,6 +2277,21 @@ lexer_expect_identifier (parser_context_t *context_p, /**< context */ return; } } +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + else if (context_p->status_flags & PARSER_MODULE_DEFAULT_CLASS_OR_FUNC) + { + /* When parsing default exports for modules, it is not required by functions or classes to have identifiers. + * In this case we use a synthetic name for them. */ + context_p->token.type = LEXER_LITERAL; + context_p->token.literal_is_reserved = false; + context_p->token.lit_location.type = LEXER_IDENT_LITERAL; + context_p->token.lit_location.has_escape = false; + lexer_construct_literal_object (context_p, + (lexer_lit_location_t *) &lexer_default_literal, + lexer_default_literal.type); + return; + } +#endif parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); } /* lexer_expect_identifier */ diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 50e7a3c257..7f81c604b1 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -17,6 +17,8 @@ #ifndef JERRY_DISABLE_JS_PARSER #include "jcontext.h" + +#include "ecma-helpers.h" #include "lit-char-helpers.h" /** \addtogroup parser Parser @@ -568,6 +570,14 @@ parser_parse_class (parser_context_t *context_p, /**< context */ class_ident_index = context_p->lit_object.index; context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR; + +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + if (JERRY_CONTEXT (module_top_context_p) != NULL && context_p->module_current_node_p != NULL) + { + context_p->module_identifier_lit_p = context_p->lit_object.literal_p; + } +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + lexer_next_token (context_p); } else @@ -1266,6 +1276,15 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ lexer_construct_literal_object (context_p, &context_p->token.lit_location, context_p->token.lit_location.type); +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + if (context_p->status_flags & PARSER_MODULE_DEFAULT_EXPR + && context_p->token.lit_location.type == LEXER_IDENT_LITERAL) + { + context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR; + context_p->module_identifier_lit_p = context_p->lit_object.literal_p; + context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_DEFAULT_EXPR); + } +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ } else if (context_p->token.lit_location.type == LEXER_NUMBER_LITERAL) { diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index d9c2771231..a0fcfd777f 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -24,6 +24,8 @@ #include "js-parser-limits.h" #include "js-lexer.h" +#include "ecma-module.h" + /** \addtogroup parser Parser * @{ * @@ -78,6 +80,10 @@ typedef enum PARSER_CLASS_STATIC_FUNCTION = (1u << 23), /**< this function is a static class method */ PARSER_CLASS_SUPER_PROP_REFERENCE = (1u << 24), /**< super property call or assignment */ #endif /* ENABLED (JERRY_ES2015_CLASS) */ +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + PARSER_MODULE_DEFAULT_CLASS_OR_FUNC = (1u << 25), /**< parsing a function or class default export */ + PARSER_MODULE_DEFAULT_EXPR = (1u << 26), /**< parsing a default export expression */ +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ } parser_general_flags_t; /** @@ -296,59 +302,6 @@ typedef struct #endif /* JERRY_DEBUGGER */ -#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) -/** - * String struct for storing the module path. - */ -typedef struct parser_module_utf8_string -{ - uint8_t *value_p; /**< string value stored as uint8_t */ - prop_length_t length; /**< length of the string */ -} parser_module_utf8_string_t; - -/** - * Imported or exported names, for example: - * import { v as x } from "module"; - * exported name: v - * imported name: x - * export x as v; - * exported variable: x - * exported as: v - * Reference: https://www.ecma-international.org/ecma-262/6.0/#table-41 - */ -typedef struct parser_module_names -{ - ecma_string_t *import_name_p; /**< local name of the import - export item */ - ecma_string_t *local_name_p; /**< import name of the import - export item */ - - struct parser_module_names *next_p; /**< next linked list node */ -} parser_module_names_t; - -/** - * Module node to store imports / exports. - */ -typedef struct parser_module_node -{ - parser_module_names_t *module_names_p; /**< names of the requested imports - exports */ - uint16_t module_request_count; /**< count of the requested imports - exports */ - - parser_module_utf8_string_t script_path; /**< path of the requested module*/ - - struct parser_module_node *next_p; /**< next linked list node */ -} parser_module_node_t; - -/** - * Module context in the parser context. It is not in the context if modules - * are not enabled during the build. It's value is NULL if there is no import / - * export in the script, otherwise it contains all the imports and exports. - */ -typedef struct -{ - parser_module_node_t *imports_p; /**< import item of the current context */ - parser_module_node_t *exports_p; /**< export item of the current context */ -} parser_module_context_t; -#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ - /** * Those members of a context which needs * to be saved when a sub-function is parsed. @@ -396,8 +349,8 @@ typedef struct parser_stack_iterator_t last_statement; /**< last statement position */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - parser_module_context_t *module_context_p; /**< shared module context inside the parser */ - parser_module_node_t *module_current_node_p; /**< import / export node that is being processed */ + ecma_module_node_t *module_current_node_p; /**< import / export node that is being processed */ + lexer_literal_t *module_identifier_lit_p; /**< the literal for the identifier of the current element */ #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ /* Lexer members. */ @@ -614,27 +567,23 @@ void parser_free_jumps (parser_stack_iterator_t iterator); * @{ */ +extern const lexer_lit_location_t lexer_default_literal; void parser_module_add_export_node_to_context (parser_context_t *context_p); void parser_module_add_import_node_to_context (parser_context_t *context_p); void parser_module_check_request_place (parser_context_t *context_p); -void parser_module_context_cleanup (parser_context_t *context_p); void parser_module_context_init (parser_context_t *context_p); -void parser_module_free_saved_names (parser_module_node_t *module_node_p); -void parser_module_handle_from_clause (parser_context_t *context_p); +void parser_module_handle_module_specifier (parser_context_t *context_p); void parser_module_handle_requests (parser_context_t *context_p); -void parser_module_partial_cleanup_on_error (parser_module_node_t *module_node_p); -void parser_module_parse_export_item_list (parser_context_t *context_p); -void parser_module_parse_import_item_list (parser_context_t *context_p); - -parser_module_node_t *parser_module_create_module_node (parser_context_t *context_p, - parser_module_node_t *template_node_p); -parser_module_node_t *parser_module_get_export_node (parser_context_t *context_p); - -void parser_module_add_item_to_node (parser_context_t *context_p, - parser_module_node_t *module_node_p, - lexer_literal_t *import_name_p, - lexer_literal_t *local_name_p, - bool is_import_item); +void parser_module_parse_export_clause (parser_context_t *context_p); +void parser_module_parse_import_clause (parser_context_t *context_p); +void parser_module_set_default (parser_context_t *context_p); +ecma_module_node_t *parser_module_create_module_node (parser_context_t *context_p, + ecma_module_node_t *template_node_p); +bool parser_module_check_duplicate_import (parser_context_t *context_p, ecma_string_t *local_name_p); +bool parser_module_check_duplicate_export (parser_context_t *context_p, ecma_string_t *export_name_p); +void parser_module_add_names_to_node (parser_context_t *context_p, + ecma_string_t *imex_name_p, + ecma_string_t *local_name_p); #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ diff --git a/jerry-core/parser/js/js-parser-module.c b/jerry-core/parser/js/js-parser-module.c index a9222949f8..b92c8f62a0 100644 --- a/jerry-core/parser/js/js-parser-module.c +++ b/jerry-core/parser/js/js-parser-module.c @@ -19,114 +19,121 @@ #include "jcontext.h" #include "jerryscript-port.h" -#include "ecma-exceptions.h" #include "ecma-function-object.h" +#include "ecma-gc.h" +#include "ecma-globals.h" #include "ecma-helpers.h" -#include "ecma-literal-storage.h" #include "ecma-lex-env.h" #include "ecma-module.h" /** - * Maximum import count limit. + * Description of "*default*" literal string. */ -#define MAX_IMPORT_COUNT UINT16_MAX +const lexer_lit_location_t lexer_default_literal = +{ + (const uint8_t *) "*default*", 9, LEXER_IDENT_LITERAL, false +}; /** - * Check duplicates in module node. - * @return true - if the given item is duplicated entry in the current node + * Check for duplicated imported binding names. + * + * @return true - if the given name is a duplicate * false - otherwise */ -static bool -parser_module_check_for_duplicates_in_node (parser_module_node_t *module_node_p, /**< module node */ - lexer_literal_t *import_name_p) /**< newly imported name */ +bool +parser_module_check_duplicate_import (parser_context_t *context_p, /**< parser context */ + ecma_string_t *local_name_p) /**< newly imported name */ { - JERRY_ASSERT (import_name_p != NULL); - - parser_module_names_t *import_names_p = module_node_p->module_names_p; - - while (import_names_p != NULL) + ecma_module_names_t *module_names_p = context_p->module_current_node_p->module_names_p; + while (module_names_p != NULL) { - uint8_t flags = ECMA_STRING_FLAG_IS_ASCII; - lit_utf8_size_t current_length = 0; - const uint8_t *current_p = ecma_string_get_chars (import_names_p->import_name_p, ¤t_length, &flags); - - if (current_p != NULL && current_length == import_name_p->prop.length - && memcmp (current_p, import_name_p->u.char_p, current_length) == 0) + if (ecma_compare_ecma_strings (module_names_p->local_name_p, local_name_p)) { return true; } - import_names_p = import_names_p->next_p; + module_names_p = module_names_p->next_p; } - return false; -} /* parser_module_check_for_duplicates_in_node */ - -/** - * Check duplicates in the whole module context. - * @return true - if the given item is duplicated entry - * false - otherwise - */ -static bool -parser_module_check_for_duplicates (parser_context_t *context_p, /**< parser context */ - parser_module_node_t *module_node_p, /**< module noda */ - lexer_literal_t *import_name_p) /**< newly imported name */ -{ - if (import_name_p == NULL) + ecma_module_node_t *module_node_p = JERRY_CONTEXT (module_top_context_p)->imports_p; + while (module_node_p != NULL) { - return false; - } - - bool hasDuplicate = parser_module_check_for_duplicates_in_node (module_node_p, - import_name_p); + module_names_p = module_node_p->module_names_p; - if (!hasDuplicate) - { - parser_module_node_t *node_p = context_p->module_context_p->imports_p; - while (node_p != NULL && !hasDuplicate) + while (module_names_p != NULL) { - hasDuplicate = parser_module_check_for_duplicates_in_node (node_p, - import_name_p); - node_p = node_p->next_p; + if (ecma_compare_ecma_strings (module_names_p->local_name_p, local_name_p)) + { + return true; + } + + module_names_p = module_names_p->next_p; } + + module_node_p = module_node_p->next_p; } - return hasDuplicate; -} /* parser_module_check_for_duplicates */ + return false; +} /* parser_module_check_duplicate_import */ /** - * Delete the saved names from the given module node. + * Check for duplicated exported bindings. + * @return - true - if the exported name is a duplicate + * false - otherwise */ -void -parser_module_free_saved_names (parser_module_node_t *module_node_p) /**< module node */ +bool +parser_module_check_duplicate_export (parser_context_t *context_p, /**< parser context */ + ecma_string_t *export_name_p) /**< exported identifier */ { - if (module_node_p == NULL || module_node_p->module_names_p == NULL) + /* We have to check in the currently constructed node, as well as all of the already added nodes. */ + ecma_module_names_t *current_names_p = context_p->module_current_node_p->module_names_p; + while (current_names_p != NULL) { - return; + if (ecma_compare_ecma_strings (current_names_p->imex_name_p, export_name_p)) + { + return true; + } + current_names_p = current_names_p->next_p; } - parser_module_names_t *current_p = module_node_p->module_names_p; - - for (uint16_t i = 0; i < module_node_p->module_request_count; i++) + ecma_module_node_t *export_node_p = JERRY_CONTEXT (module_top_context_p)->local_exports_p; + if (export_node_p != NULL) { - parser_module_names_t *next_p = current_p->next_p; + JERRY_ASSERT (export_node_p->next_p == NULL); + ecma_module_names_t *name_p = export_node_p->module_names_p; - if (current_p->import_name_p != NULL) + while (name_p != NULL) { - ecma_deref_ecma_string (current_p->import_name_p); - current_p->import_name_p = NULL; + if (ecma_compare_ecma_strings (name_p->imex_name_p, export_name_p)) + { + return true; + } + + name_p = name_p->next_p; } + } + + export_node_p = JERRY_CONTEXT (module_top_context_p)->indirect_exports_p; + while (export_node_p != NULL) + { + ecma_module_names_t *name_p = export_node_p->module_names_p; - if (current_p->local_name_p != NULL) + while (name_p != NULL) { - ecma_deref_ecma_string (current_p->local_name_p); - current_p->local_name_p = NULL; + if (ecma_compare_ecma_strings (name_p->imex_name_p, export_name_p)) + { + return true; + } + + name_p = name_p->next_p; } - parser_free (current_p, sizeof (parser_module_names_t)); - current_p = next_p; + export_node_p = export_node_p->next_p; } -} /* parser_module_free_saved_names */ + + /* Star exports don't have any names associated with them, so no need to check those. */ + return false; +} /* parser_module_check_duplicate_export */ /** * Add export node to parser context. @@ -134,37 +141,56 @@ parser_module_free_saved_names (parser_module_node_t *module_node_p) /**< module void parser_module_add_export_node_to_context (parser_context_t *context_p) /**< parser context */ { - parser_module_node_t *module_node_p = context_p->module_current_node_p; - parser_module_node_t *exports_p = context_p->module_context_p->exports_p; + ecma_module_node_t *module_node_p = context_p->module_current_node_p; + ecma_module_node_t **export_list_p; - if (exports_p != NULL) + /* Check which list we should add it to. */ + if (module_node_p->module_request_p) { - parser_module_names_t *module_names_p = module_node_p->module_names_p; - - for (uint16_t i = 0; i < module_node_p->module_request_count - 1 ; i++) + /* If the export node has a module request, that means it's either an indirect export, or a star export. */ + if (!module_node_p->module_names_p) { - module_names_p = module_names_p->next_p; - } - - module_names_p->next_p = exports_p->module_names_p; - exports_p->module_names_p = module_node_p->module_names_p; - - int request_count = exports_p->module_request_count + module_node_p->module_request_count; - - if ((uint16_t) request_count < MAX_IMPORT_COUNT) - { - exports_p->module_request_count = (uint16_t) request_count; + /* If there are no names in the node, then it's a star export. */ + export_list_p = &(JERRY_CONTEXT (module_top_context_p)->star_exports_p); } else { - parser_raise_error (context_p, PARSER_ERR_MODULE_REQUEST_LIMIT_REACHED); + export_list_p = &(JERRY_CONTEXT (module_top_context_p)->indirect_exports_p); } } else { - parser_module_node_t *export_node_p = parser_module_create_module_node (context_p, module_node_p); - context_p->module_context_p->exports_p = export_node_p; + /* If there is no module request, then it's a local export. */ + export_list_p = &(JERRY_CONTEXT (module_top_context_p)->local_exports_p); } + + /* Check if we have a node with the same module request, append to it if we do. */ + ecma_module_node_t *stored_exports_p = *export_list_p; + while (stored_exports_p != NULL) + { + if (stored_exports_p->module_request_p == module_node_p->module_request_p) + { + ecma_module_names_t *module_names_p = module_node_p->module_names_p; + + if (module_names_p != NULL) + { + while (module_names_p->next_p != NULL) + { + module_names_p = module_names_p->next_p; + } + + module_names_p->next_p = stored_exports_p->module_names_p; + stored_exports_p->module_names_p = module_node_p->module_names_p; + } + return; + } + + stored_exports_p = stored_exports_p->next_p; + } + + ecma_module_node_t *export_node_p = parser_module_create_module_node (context_p, module_node_p); + export_node_p->next_p = *export_list_p; + *export_list_p = export_node_p; } /* parser_module_add_export_node_to_context */ /** @@ -173,393 +199,275 @@ parser_module_add_export_node_to_context (parser_context_t *context_p) /**< pars void parser_module_add_import_node_to_context (parser_context_t *context_p) /**< parser context */ { - parser_module_node_t *module_node_p = context_p->module_current_node_p; - parser_module_node_t *stored_imports = context_p->module_context_p->imports_p; - bool is_stored_module = false; + ecma_module_node_t *module_node_p = context_p->module_current_node_p; + ecma_module_node_t *stored_imports = JERRY_CONTEXT (module_top_context_p)->imports_p; + /* Check if we have a node with the same module request, append to it if we do. */ while (stored_imports != NULL) { - if (stored_imports->script_path.length == module_node_p->script_path.length - && memcmp (stored_imports->script_path.value_p, - module_node_p->script_path.value_p, - stored_imports->script_path.length) == 0) + if (stored_imports->module_request_p == module_node_p->module_request_p) { - parser_free (module_node_p->script_path.value_p, module_node_p->script_path.length * sizeof (uint8_t)); - - parser_module_names_t *module_names_p = module_node_p->module_names_p; - is_stored_module = true; + ecma_module_names_t *module_names_p = module_node_p->module_names_p; - for (uint16_t i = 0; i < module_node_p->module_request_count - 1; i++) + if (module_names_p != NULL) { - module_names_p = module_names_p->next_p; - } - - module_names_p->next_p = stored_imports->module_names_p; - stored_imports->module_names_p = module_node_p->module_names_p; + while (module_names_p->next_p != NULL) + { + module_names_p = module_names_p->next_p; + } - int request_count = stored_imports->module_request_count + module_node_p->module_request_count; - if ((uint16_t) request_count < MAX_IMPORT_COUNT) - { - stored_imports->module_request_count = (uint16_t) request_count; + module_names_p->next_p = stored_imports->module_names_p; + stored_imports->module_names_p = module_node_p->module_names_p; } - else - { - parser_raise_error (context_p, PARSER_ERR_MODULE_REQUEST_LIMIT_REACHED); - } - - break; + return; } - stored_imports = stored_imports->next_p; - } - if (!is_stored_module) - { - parser_module_node_t *permanent_node_p = parser_module_create_module_node (context_p, module_node_p); - permanent_node_p->next_p = context_p->module_context_p->imports_p; - context_p->module_context_p->imports_p = permanent_node_p; + stored_imports = stored_imports->next_p; } + ecma_module_node_t *permanent_node_p = parser_module_create_module_node (context_p, module_node_p); + permanent_node_p->next_p = JERRY_CONTEXT (module_top_context_p)->imports_p; + JERRY_CONTEXT (module_top_context_p)->imports_p = permanent_node_p; } /* parser_module_add_import_node_to_context */ /** - * Add import or export item to module node. + * Add module names to current module node. */ void -parser_module_add_item_to_node (parser_context_t *context_p, /**< parser context */ - parser_module_node_t *module_node_p, /**< current module node */ - lexer_literal_t *import_name_p, /**< import name */ - lexer_literal_t *local_name_p, /**< local name */ - bool is_import_item) /**< given item is import item */ +parser_module_add_names_to_node (parser_context_t *context_p, /**< parser context */ + ecma_string_t *imex_name_p, /**< import/export name */ + ecma_string_t *local_name_p) /**< local name */ { - if (is_import_item - && parser_module_check_for_duplicates (context_p, module_node_p, import_name_p)) - { - parser_raise_error (context_p, PARSER_ERR_DUPLICATED_LABEL); - } - - parser_module_names_t *new_names_p = (parser_module_names_t *) parser_malloc (context_p, - sizeof (parser_module_names_t)); + ecma_module_names_t *new_names_p = (ecma_module_names_t *) parser_malloc (context_p, + sizeof (ecma_module_names_t)); + memset (new_names_p, 0, sizeof (ecma_module_names_t)); + ecma_module_node_t *module_node_p = context_p->module_current_node_p; new_names_p->next_p = module_node_p->module_names_p; module_node_p->module_names_p = new_names_p; - module_node_p->module_names_p->import_name_p = ecma_new_ecma_string_from_utf8 (import_name_p->u.char_p, - import_name_p->prop.length); - - module_node_p->module_names_p->local_name_p = ecma_new_ecma_string_from_utf8 (local_name_p->u.char_p, - local_name_p->prop.length); - - module_node_p->module_request_count++; -} /* parser_module_add_item_to_node */ - -/** - * Cleanup the whole module context from parser context. - */ -void -parser_module_context_cleanup (parser_context_t *context_p) /**< parser context */ -{ - parser_module_context_t *module_context_p = context_p->module_context_p; - - if (module_context_p == NULL) - { - return; - } - - parser_module_node_t *current_node_p = module_context_p->imports_p; - - while (current_node_p != NULL) - { - parser_free (current_node_p->script_path.value_p, current_node_p->script_path.length * sizeof (uint8_t)); - parser_module_free_saved_names (current_node_p); - - parser_module_node_t *next_node_p = current_node_p->next_p; - - parser_free (current_node_p, sizeof (parser_module_node_t)); - current_node_p = next_node_p; - } - - parser_module_context_t *parent_context_p = JERRY_CONTEXT (module_top_context_p); - if ((parent_context_p == NULL || parent_context_p->exports_p == NULL || parent_context_p->imports_p == NULL) - && module_context_p->exports_p != NULL) - { - parser_module_free_saved_names (module_context_p->exports_p); - parser_free (module_context_p->exports_p, sizeof (parser_module_node_t)); - } + JERRY_ASSERT (imex_name_p != NULL); + ecma_ref_ecma_string (imex_name_p); + new_names_p->imex_name_p = imex_name_p; - parser_free (module_context_p, sizeof (parser_module_context_t)); - context_p->module_context_p = NULL; -} /* parser_module_context_cleanup */ + JERRY_ASSERT (local_name_p != NULL); + ecma_ref_ecma_string (local_name_p); + new_names_p->local_name_p = local_name_p; +} /* parser_module_add_names_to_node */ /** - * Create module context and bind to the parser context. + * Create module context if needed. */ void parser_module_context_init (parser_context_t *context_p) /**< parser context */ { - if (context_p->module_context_p == NULL) + if (JERRY_CONTEXT (module_top_context_p) == NULL) { - context_p->module_context_p = (parser_module_context_t *) parser_malloc (context_p, - sizeof (parser_module_context_t)); + ecma_module_context_t *module_context_p; + module_context_p = (ecma_module_context_t *) parser_malloc (context_p, + sizeof (ecma_module_context_t)); - memset (context_p->module_context_p, 0, sizeof (parser_module_context_t)); + memset (module_context_p, 0, sizeof (ecma_module_context_t)); + JERRY_CONTEXT (module_top_context_p) = module_context_p; } } /* parser_module_context_init */ /** - * Create import node. + * Create a permanent import/export node from a template node. * @return - the copy of the template if the second parameter is not NULL. - * - otherwise: an empty import node. + * - otherwise: an empty node. */ -parser_module_node_t * +ecma_module_node_t * parser_module_create_module_node (parser_context_t *context_p, /**< parser context */ - parser_module_node_t *template_node_p) /**< template node for the new node */ + ecma_module_node_t *template_node_p) /**< template node for the new node */ { - parser_module_node_t *node = (parser_module_node_t *) parser_malloc (context_p, sizeof (parser_module_node_t)); + ecma_module_node_t *node_p = (ecma_module_node_t *) parser_malloc (context_p, sizeof (ecma_module_node_t)); if (template_node_p != NULL) { - node->module_names_p = template_node_p->module_names_p; - node->module_request_count = template_node_p->module_request_count; - - node->script_path.value_p = template_node_p->script_path.value_p; - node->script_path.length = template_node_p->script_path.length; - node->next_p = NULL; + node_p->module_names_p = template_node_p->module_names_p; + node_p->module_request_p = template_node_p->module_request_p; + node_p->next_p = NULL; } else { - memset (node, 0, sizeof (parser_module_node_t)); + memset (node_p, 0, sizeof (ecma_module_node_t)); } - return node; + return node_p; } /* parser_module_create_module_node */ /** - * Create export node or get the previously created one. - * @return the export node - */ -parser_module_node_t * -parser_module_get_export_node (parser_context_t *context_p) /**< parser context */ -{ - if (context_p->module_context_p->exports_p != NULL) - { - return context_p->module_context_p->exports_p; - } - - return parser_module_create_module_node (context_p, NULL); -} /* parser_module_get_export_node */ - -/** - * Parse export item list. + * Parse an ExportClause. */ void -parser_module_parse_export_item_list (parser_context_t *context_p) /**< parser context */ +parser_module_parse_export_clause (parser_context_t *context_p) /**< parser context */ { - if (context_p->token.type == LEXER_LITERAL - && lexer_compare_raw_identifier_to_current (context_p, "from", 4)) - { - parser_raise_error (context_p, PARSER_ERR_INVALID_CHARACTER); - } - - if (context_p->token.type == LEXER_KEYW_DEFAULT || context_p->token.type == LEXER_MULTIPLY) - { - /* TODO: This part is going to be implemented in the next part of the patch. */ - parser_raise_error (context_p, PARSER_ERR_NOT_IMPLEMENTED); - } - - bool has_export_name = false; - lexer_literal_t *export_name_p = NULL; - lexer_literal_t *local_name_p = NULL; - parser_module_node_t *module_node_p = context_p->module_current_node_p; + JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE); + lexer_next_token (context_p); while (true) { - if (has_export_name - && context_p->token.type != LEXER_KEYW_DEFAULT - && (context_p->token.type != LEXER_LITERAL - || lexer_compare_raw_identifier_to_current (context_p, "from", 4) - || lexer_compare_raw_identifier_to_current (context_p, "as", 2))) + if (context_p->token.type == LEXER_RIGHT_BRACE) { - parser_raise_error (context_p, PARSER_ERR_INVALID_CHARACTER); + lexer_next_token (context_p); + break; } - if (context_p->token.lit_location.type != LEXER_IDENT_LITERAL - && context_p->token.lit_location.type != LEXER_STRING_LITERAL) + /* 15.2.3.1 The referenced binding cannot be a reserved word. */ + if (context_p->token.type != LEXER_LITERAL + || context_p->token.lit_location.type != LEXER_IDENT_LITERAL + || context_p->token.literal_is_reserved) { - parser_raise_error (context_p, PARSER_ERR_PROPERTY_IDENTIFIER_EXPECTED); + parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); } - lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_STRING_LITERAL); + ecma_string_t *export_name_p = NULL; + ecma_string_t *local_name_p = NULL; + + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL); + + local_name_p = ecma_new_ecma_string_from_utf8 (context_p->lit_object.literal_p->u.char_p, + context_p->lit_object.literal_p->prop.length); + + ecma_ref_ecma_string (local_name_p); + export_name_p = local_name_p; - if (has_export_name) + lexer_next_token (context_p); + if (context_p->token.type == LEXER_LITERAL + && lexer_compare_raw_identifier_to_current (context_p, "as", 2)) { - export_name_p = context_p->lit_object.literal_p; + lexer_next_token (context_p); + + if (context_p->token.type != LEXER_LITERAL + || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) + { + ecma_deref_ecma_string (local_name_p); + ecma_deref_ecma_string (export_name_p); + parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); + } + + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL); + + ecma_deref_ecma_string (local_name_p); + export_name_p = ecma_new_ecma_string_from_utf8 (context_p->lit_object.literal_p->u.char_p, + context_p->lit_object.literal_p->prop.length); + + lexer_next_token (context_p); } - else + + if (parser_module_check_duplicate_export (context_p, export_name_p)) { - local_name_p = context_p->lit_object.literal_p; - export_name_p = context_p->lit_object.literal_p; + ecma_deref_ecma_string (local_name_p); + ecma_deref_ecma_string (export_name_p); + parser_raise_error (context_p, PARSER_ERR_DUPLICATED_EXPORT_IDENTIFIER); } - lexer_next_token (context_p); + parser_module_add_names_to_node (context_p, export_name_p, local_name_p); + ecma_deref_ecma_string (local_name_p); + ecma_deref_ecma_string (export_name_p); - if (context_p->token.type == LEXER_COMMA) + if (context_p->token.type != LEXER_COMMA + && context_p->token.type != LEXER_RIGHT_BRACE) { - has_export_name = false; - parser_module_add_item_to_node (context_p, module_node_p, export_name_p, local_name_p, false); + parser_raise_error (context_p, PARSER_ERR_RIGHT_BRACE_COMMA_EXPECTED); } - else if (context_p->token.type == LEXER_LITERAL - && lexer_compare_raw_identifier_to_current (context_p, "as", 2)) + else if (context_p->token.type == LEXER_COMMA) { - if (has_export_name) - { - parser_raise_error (context_p, PARSER_ERR_INVALID_CHARACTER); - } - - has_export_name = true; + lexer_next_token (context_p); } - else + + if (context_p->token.type == LEXER_LITERAL + && lexer_compare_raw_identifier_to_current (context_p, "from", 4)) { - parser_module_add_item_to_node (context_p, module_node_p, export_name_p, local_name_p, false); - break; + parser_raise_error (context_p, PARSER_ERR_RIGHT_BRACE_EXPECTED); } - lexer_next_token (context_p); } -} /* parser_module_parse_export_item_list */ +} /* parser_module_parse_export_clause */ /** - * Parse import item list. + * Parse an ImportClause */ void -parser_module_parse_import_item_list (parser_context_t *context_p) /**< parser context */ +parser_module_parse_import_clause (parser_context_t *context_p) /**< parser context */ { - /* Import list is empty, the whole module will be loaded. */ - if (context_p->token.type == LEXER_LITERAL - && lexer_compare_raw_identifier_to_current (context_p, "from", 4)) - { - /* TODO: This part is going to be implemented in the next part of the patch. */ - parser_raise_error (context_p, PARSER_ERR_NOT_IMPLEMENTED); - } - - bool has_import_name = false; - lexer_literal_t *import_name_p = NULL; - lexer_literal_t *local_name_p = NULL; - parser_module_node_t *module_node_p = context_p->module_current_node_p; + JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE); + lexer_next_token (context_p); while (true) { - bool whole_module_needed = context_p->token.type == LEXER_MULTIPLY; - - if (whole_module_needed) + if (context_p->token.type == LEXER_RIGHT_BRACE) { - parser_raise_error (context_p, PARSER_ERR_NOT_IMPLEMENTED); + lexer_next_token (context_p); + break; } if (context_p->token.type != LEXER_LITERAL - || lexer_compare_raw_identifier_to_current (context_p, "from", 4) - || lexer_compare_raw_identifier_to_current (context_p, "as", 2)) + || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) { - parser_raise_error (context_p, PARSER_ERR_INVALID_CHARACTER); + parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); } - lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL); + ecma_string_t *import_name_p = NULL; + ecma_string_t *local_name_p = NULL; - if (has_import_name) - { - import_name_p = context_p->lit_object.literal_p; - } - else - { - local_name_p = context_p->lit_object.literal_p; - import_name_p = context_p->lit_object.literal_p; - } + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL); + local_name_p = ecma_new_ecma_string_from_utf8 (context_p->lit_object.literal_p->u.char_p, + context_p->lit_object.literal_p->prop.length); + ecma_ref_ecma_string (local_name_p); + import_name_p = local_name_p; lexer_next_token (context_p); - - if (context_p->token.type == LEXER_RIGHT_BRACE - || (context_p->token.type == LEXER_LITERAL - && lexer_compare_raw_identifier_to_current (context_p, "from", 4))) + if (context_p->token.type == LEXER_LITERAL + && lexer_compare_raw_identifier_to_current (context_p, "as", 2)) { - parser_module_add_item_to_node (context_p, module_node_p, import_name_p, local_name_p, true); - break; - } + lexer_next_token (context_p); - if (context_p->token.type == LEXER_COMMA) - { - parser_module_add_item_to_node (context_p, module_node_p, import_name_p, local_name_p, true); - has_import_name = false; - } - else if (context_p->token.type == LEXER_LITERAL - && lexer_compare_raw_identifier_to_current (context_p, "as", 2)) - { - if (has_import_name) + if (context_p->token.type != LEXER_LITERAL + || context_p->token.lit_location.type != LEXER_IDENT_LITERAL) { - parser_raise_error (context_p, PARSER_ERR_INVALID_CHARACTER); + ecma_deref_ecma_string (local_name_p); + ecma_deref_ecma_string (import_name_p); + parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); } - has_import_name = true; + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL); + + ecma_deref_ecma_string (local_name_p); + local_name_p = ecma_new_ecma_string_from_utf8 (context_p->lit_object.literal_p->u.char_p, + context_p->lit_object.literal_p->prop.length); + lexer_next_token (context_p); } - else + + if (parser_module_check_duplicate_import (context_p, local_name_p)) { - parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_COMMA_FROM_EXPECTED); + ecma_deref_ecma_string (local_name_p); + ecma_deref_ecma_string (import_name_p); + parser_raise_error (context_p, PARSER_ERR_DUPLICATED_IMPORT_BINDING); } - lexer_next_token (context_p); - } -} /* parser_module_parse_import_item_list */ -/** - * Handle import requests. - * Check if imported variables are exported in the appropriate module. - * Raise parser error if imported item is not exported. - */ -void -parser_module_handle_requests (parser_context_t *context_p) /**< parser context */ -{ - parser_module_context_t *module_context_p = JERRY_CONTEXT (module_top_context_p); - - if (context_p->module_context_p->exports_p == NULL || module_context_p == NULL) - { - return; - } - - bool throw_error = false; - - parser_module_names_t *import_name_p = module_context_p->imports_p->module_names_p; - parser_module_names_t *current_exports_p = context_p->module_context_p->exports_p->module_names_p; + parser_module_add_names_to_node (context_p, import_name_p, local_name_p); + ecma_deref_ecma_string (local_name_p); + ecma_deref_ecma_string (import_name_p); - for (uint16_t i = 0; i < module_context_p->imports_p->module_request_count; ++i) - { - bool request_is_found_in_module = false; - parser_module_names_t *export_iterator_p = current_exports_p; - - for (uint16_t j = 0; j < context_p->module_context_p->exports_p->module_request_count; - ++j, export_iterator_p = export_iterator_p->next_p) + if (context_p->token.type != LEXER_COMMA + && (context_p->token.type != LEXER_RIGHT_BRACE)) { - if (ecma_compare_ecma_strings (import_name_p->local_name_p, export_iterator_p->import_name_p)) - { - request_is_found_in_module = true; - break; - } + parser_raise_error (context_p, PARSER_ERR_RIGHT_BRACE_COMMA_EXPECTED); } - - if (!request_is_found_in_module) + else if (context_p->token.type == LEXER_COMMA) { - parser_module_free_saved_names (context_p->module_context_p->exports_p); - throw_error = true; - break; + lexer_next_token (context_p); } - import_name_p = import_name_p->next_p; - } - - *module_context_p->exports_p = *context_p->module_context_p->exports_p; - parser_free (context_p->module_context_p->exports_p, sizeof (parser_module_node_t)); - - if (throw_error) - { - parser_raise_error (context_p, PARSER_ERR_MODULE_REQUEST_NOT_FOUND); + if (context_p->token.type == LEXER_LITERAL + && lexer_compare_raw_identifier_to_current (context_p, "from", 4)) + { + parser_raise_error (context_p, PARSER_ERR_RIGHT_BRACE_EXPECTED); + } } -} /* parser_module_handle_requests */ +} /* parser_module_parse_import_clause */ /** * Raises parser error if the import or export statement is not in the global scope. @@ -569,35 +477,37 @@ parser_module_check_request_place (parser_context_t *context_p) /**< parser cont { if (context_p->last_context_p != NULL || context_p->stack_top_uint8 != 0 - || (JERRY_CONTEXT (status_flags) & ECMA_STATUS_DIRECT_EVAL) != 0) + || (JERRY_CONTEXT (status_flags) & ECMA_STATUS_DIRECT_EVAL) != 0 + || (context_p->status_flags & PARSER_IS_FUNCTION) != 0) { parser_raise_error (context_p, PARSER_ERR_MODULE_UNEXPECTED); } } /* parser_module_check_request_place */ /** - * Handle from clause at the end of the import / export statement. + * Handle module specifier at the end of the import / export statement. */ void -parser_module_handle_from_clause (parser_context_t *context_p) /**< parser context */ +parser_module_handle_module_specifier (parser_context_t *context_p) /**< parser context */ { - parser_module_node_t *module_node_p = context_p->module_current_node_p; - lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_NO_OPTS); - - if (context_p->lit_object.literal_p->prop.length == 0) + ecma_module_node_t *module_node_p = context_p->module_current_node_p; + if (context_p->token.type != LEXER_LITERAL + || context_p->token.lit_location.type != LEXER_STRING_LITERAL + || context_p->token.lit_location.length == 0) { - parser_raise_error (context_p, PARSER_ERR_PROPERTY_IDENTIFIER_EXPECTED); + parser_raise_error (context_p, PARSER_ERR_STRING_EXPECTED); } - module_node_p->script_path.length = (prop_length_t) (context_p->lit_object.literal_p->prop.length + 1); - module_node_p->script_path.value_p = (uint8_t *) parser_malloc (context_p, - module_node_p->script_path.length * sizeof (uint8_t)); + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_STRING_LITERAL); - memcpy (module_node_p->script_path.value_p, - context_p->lit_object.literal_p->u.char_p, - module_node_p->script_path.length); - module_node_p->script_path.value_p[module_node_p->script_path.length - 1] = '\0'; + ecma_string_t *path_p = ecma_module_create_normalized_path (context_p->lit_object.literal_p->u.char_p, + context_p->lit_object.literal_p->prop.length); + ecma_module_t *module_p = ecma_module_find_or_create_module (path_p); + ecma_deref_ecma_string (path_p); + + module_node_p->module_request_p = module_p; lexer_next_token (context_p); -} /* parser_module_handle_from_clause */ +} /* parser_module_handle_module_specifier */ + #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 7303c448ea..bfc3d4fee0 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -17,6 +17,8 @@ #ifndef JERRY_DISABLE_JS_PARSER #include "jcontext.h" + +#include "ecma-helpers.h" #include "lit-char-helpers.h" /** \addtogroup parser Parser @@ -325,13 +327,9 @@ parser_parse_var_statement (parser_context_t *context_p) /**< context */ context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR; #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - if (context_p->module_context_p != NULL && context_p->module_current_node_p != NULL) + if (JERRY_CONTEXT (module_top_context_p) != NULL && context_p->module_current_node_p != NULL) { - parser_module_add_item_to_node (context_p, - context_p->module_current_node_p, - context_p->lit_object.literal_p, - context_p->lit_object.literal_p, - false); + context_p->module_identifier_lit_p = context_p->lit_object.literal_p; } #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ @@ -401,13 +399,9 @@ parser_parse_function_statement (parser_context_t *context_p) /**< context */ name_p = context_p->lit_object.literal_p; #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - if (context_p->module_context_p != NULL && context_p->module_current_node_p != NULL) + if (JERRY_CONTEXT (module_top_context_p) != NULL && context_p->module_current_node_p != NULL) { - parser_module_add_item_to_node (context_p, - context_p->module_current_node_p, - name_p, - name_p, - false); + context_p->module_identifier_lit_p = context_p->lit_object.literal_p; } #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ @@ -1678,56 +1672,121 @@ parser_parse_continue_statement (parser_context_t *context_p) /**< context */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) /** * Parse import statement. + * Note: See 15.2.2 */ static void -parser_parse_import_statement (parser_context_t *context_p) /**< context */ +parser_parse_import_statement (parser_context_t *context_p) /**< parser context */ { JERRY_ASSERT (context_p->token.type == LEXER_KEYW_IMPORT); parser_module_check_request_place (context_p); parser_module_context_init (context_p); - parser_module_node_t module_node; - memset (&module_node, 0, sizeof (parser_module_node_t)); + ecma_module_node_t module_node; + memset (&module_node, 0, sizeof (ecma_module_node_t)); context_p->module_current_node_p = &module_node; lexer_next_token (context_p); - switch (context_p->token.type) + /* Check for a ModuleSpecifier*/ + if (context_p->token.type != LEXER_LITERAL + || context_p->token.lit_location.type != LEXER_STRING_LITERAL) { - case LEXER_LEFT_BRACE: + if (!(context_p->token.type == LEXER_LEFT_BRACE + || context_p->token.type == LEXER_MULTIPLY + || (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL))) { - lexer_next_token (context_p); - parser_module_parse_import_item_list (context_p); + parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_MULTIPLY_LITERAL_EXPECTED); + } + + if (context_p->token.type == LEXER_LITERAL) + { + /* Handle ImportedDefaultBinding */ + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL); - if (context_p->token.type != LEXER_RIGHT_BRACE) + ecma_string_t *local_name_p = ecma_new_ecma_string_from_utf8 (context_p->lit_object.literal_p->u.char_p, + context_p->lit_object.literal_p->prop.length); + + if (parser_module_check_duplicate_import (context_p, local_name_p)) { - parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED); + ecma_deref_ecma_string (local_name_p); + parser_raise_error (context_p, PARSER_ERR_DUPLICATED_IMPORT_BINDING); } + ecma_string_t *import_name_p = ecma_get_magic_string (LIT_MAGIC_STRING_DEFAULT); + parser_module_add_names_to_node (context_p, import_name_p, local_name_p); + + ecma_deref_ecma_string (local_name_p); + ecma_deref_ecma_string (import_name_p); + lexer_next_token (context_p); - break; + + if (context_p->token.type != LEXER_COMMA + && !lexer_compare_raw_identifier_to_current (context_p, "from", 4)) + { + parser_raise_error (context_p, PARSER_ERR_FROM_COMMA_EXPECTED); + } + + if (context_p->token.type == LEXER_COMMA) + { + lexer_next_token (context_p); + if (context_p->token.type != LEXER_MULTIPLY + && context_p->token.type != LEXER_LEFT_BRACE) + { + parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_MULTIPLY_EXPECTED); + } + } } - case LEXER_MULTIPLY: - case LEXER_LITERAL: + if (context_p->token.type == LEXER_MULTIPLY) { - parser_module_parse_import_item_list (context_p); - break; - } + /* NameSpaceImport*/ + lexer_next_token (context_p); + if (context_p->token.type != LEXER_LITERAL + || !lexer_compare_raw_identifier_to_current (context_p, "as", 2)) + { + parser_raise_error (context_p, PARSER_ERR_AS_EXPECTED); + } - default: + lexer_next_token (context_p); + if (context_p->token.type != LEXER_LITERAL) + { + parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED); + } + + lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_IDENT_LITERAL); + + ecma_string_t *local_name_p = ecma_new_ecma_string_from_utf8 (context_p->lit_object.literal_p->u.char_p, + context_p->lit_object.literal_p->prop.length); + + if (parser_module_check_duplicate_import (context_p, local_name_p)) + { + ecma_deref_ecma_string (local_name_p); + parser_raise_error (context_p, PARSER_ERR_DUPLICATED_IMPORT_BINDING); + } + + ecma_string_t *import_name_p = ecma_get_magic_string (LIT_MAGIC_STRING_ASTERIX_CHAR); + + parser_module_add_names_to_node (context_p, import_name_p, local_name_p); + ecma_deref_ecma_string (local_name_p); + ecma_deref_ecma_string (import_name_p); + + lexer_next_token (context_p); + } + else if (context_p->token.type == LEXER_LEFT_BRACE) { - parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_MULTIPLY_LITERAL_EXPECTED); + /* Handle NamedImports */ + parser_module_parse_import_clause (context_p); } - } - if (context_p->token.type != LEXER_LITERAL ||!lexer_compare_raw_identifier_to_current (context_p, "from", 4)) - { - parser_raise_error (context_p, PARSER_ERR_FROM_EXPECTED); + if (context_p->token.type != LEXER_LITERAL || !lexer_compare_raw_identifier_to_current (context_p, "from", 4)) + { + parser_raise_error (context_p, PARSER_ERR_FROM_EXPECTED); + } + lexer_next_token (context_p); } - parser_module_handle_from_clause (context_p); + parser_module_handle_module_specifier (context_p); parser_module_add_import_node_to_context (context_p); context_p->module_current_node_p = NULL; @@ -1744,77 +1803,158 @@ parser_parse_export_statement (parser_context_t *context_p) /**< context */ parser_module_check_request_place (context_p); parser_module_context_init (context_p); - parser_module_node_t module_node; - memset (&module_node, 0, sizeof (parser_module_node_t)); + ecma_module_node_t module_node; + memset (&module_node, 0, sizeof (ecma_module_node_t)); context_p->module_current_node_p = &module_node; lexer_next_token (context_p); - switch (context_p->token.type) { - case LEXER_LEFT_BRACE: + case LEXER_KEYW_DEFAULT: { + lexer_range_t range; + parser_save_range (context_p, &range, context_p->source_end_p); + lexer_next_token (context_p); - parser_module_parse_export_item_list (context_p); + if (context_p->token.type == LEXER_KEYW_CLASS) + { + context_p->status_flags |= PARSER_MODULE_DEFAULT_CLASS_OR_FUNC; + parser_parse_class (context_p, true); + } + else if (context_p->token.type == LEXER_KEYW_FUNCTION) + { + context_p->status_flags |= PARSER_MODULE_DEFAULT_CLASS_OR_FUNC; + parser_parse_function_statement (context_p); + } + else + { + /* Assignment expression */ + context_p->status_flags |= PARSER_MODULE_DEFAULT_EXPR; + parser_set_range (context_p, &range); + + /* 15.2.3.5 Use the synthetic name '*default*' as the identifier. */ + lexer_construct_literal_object (context_p, + (lexer_lit_location_t *) &lexer_default_literal, + lexer_default_literal.type); + context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_VAR; + + context_p->token.lit_location.type = LEXER_IDENT_LITERAL; + parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_LITERAL); + + context_p->module_identifier_lit_p = context_p->lit_object.literal_p; + + /* Fake an assignment to the default identifier */ + context_p->token.type = LEXER_ASSIGN; - if (context_p->token.type != LEXER_RIGHT_BRACE) + parser_parse_expression (context_p, + PARSE_EXPR_STATEMENT | PARSE_EXPR_NO_COMMA | PARSE_EXPR_HAS_LITERAL); + } + + ecma_string_t *name_p = ecma_new_ecma_string_from_utf8 (context_p->module_identifier_lit_p->u.char_p, + context_p->module_identifier_lit_p->prop.length); + ecma_string_t *export_name_p = ecma_get_magic_string (LIT_MAGIC_STRING_DEFAULT); + + if (parser_module_check_duplicate_export (context_p, export_name_p)) { - parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED); + ecma_deref_ecma_string (name_p); + ecma_deref_ecma_string (export_name_p); + parser_raise_error (context_p, PARSER_ERR_DUPLICATED_EXPORT_IDENTIFIER); } - lexer_next_token (context_p); + parser_module_add_names_to_node (context_p, + export_name_p, + name_p); + ecma_deref_ecma_string (name_p); + ecma_deref_ecma_string (export_name_p); + context_p->status_flags &= (uint32_t) ~(PARSER_MODULE_DEFAULT_CLASS_OR_FUNC | PARSER_MODULE_DEFAULT_EXPR); break; } - - case LEXER_KEYW_DEFAULT: + case LEXER_MULTIPLY: { - /* TODO: This part is going to be implemented in the next part of the patch. */ - parser_raise_error (context_p, PARSER_ERR_NOT_IMPLEMENTED); + lexer_next_token (context_p); + if (!(context_p->token.type == LEXER_LITERAL + && lexer_compare_raw_identifier_to_current (context_p, "from", 4))) + { + parser_raise_error (context_p, PARSER_ERR_FROM_EXPECTED); + } + + lexer_next_token (context_p); + parser_module_handle_module_specifier (context_p); break; } - - case LEXER_MULTIPLY: - case LEXER_LITERAL: + case LEXER_KEYW_VAR: { - parser_module_parse_export_item_list (context_p); + parser_parse_var_statement (context_p); + ecma_string_t *name_p = ecma_new_ecma_string_from_utf8 (context_p->module_identifier_lit_p->u.char_p, + context_p->module_identifier_lit_p->prop.length); + + if (parser_module_check_duplicate_export (context_p, name_p)) + { + ecma_deref_ecma_string (name_p); + parser_raise_error (context_p, PARSER_ERR_DUPLICATED_EXPORT_IDENTIFIER); + } + + parser_module_add_names_to_node (context_p, + name_p, + name_p); + ecma_deref_ecma_string (name_p); break; } + case LEXER_KEYW_CLASS: + { + parser_parse_class (context_p, true); + ecma_string_t *name_p = ecma_new_ecma_string_from_utf8 (context_p->module_identifier_lit_p->u.char_p, + context_p->module_identifier_lit_p->prop.length); + if (parser_module_check_duplicate_export (context_p, name_p)) + { + ecma_deref_ecma_string (name_p); + parser_raise_error (context_p, PARSER_ERR_DUPLICATED_EXPORT_IDENTIFIER); + } + + parser_module_add_names_to_node (context_p, + name_p, + name_p); + ecma_deref_ecma_string (name_p); + break; + } case LEXER_KEYW_FUNCTION: { parser_parse_function_statement (context_p); - break; - } + ecma_string_t *name_p = ecma_new_ecma_string_from_utf8 (context_p->module_identifier_lit_p->u.char_p, + context_p->module_identifier_lit_p->prop.length); - case LEXER_KEYW_VAR: - { - parser_parse_var_statement (context_p); + if (parser_module_check_duplicate_export (context_p, name_p)) + { + ecma_deref_ecma_string (name_p); + parser_raise_error (context_p, PARSER_ERR_DUPLICATED_EXPORT_IDENTIFIER); + } + + parser_module_add_names_to_node (context_p, + name_p, + name_p); + ecma_deref_ecma_string (name_p); break; } - - case LEXER_KEYW_CLASS: + case LEXER_LEFT_BRACE: { - /* TODO: This part is going to be implemented in the next part of the patch. */ - parser_raise_error (context_p, PARSER_ERR_NOT_IMPLEMENTED); + parser_module_parse_export_clause (context_p); + + if (context_p->token.type == LEXER_LITERAL + && lexer_compare_raw_identifier_to_current (context_p, "from", 4)) + { + lexer_next_token (context_p); + parser_module_handle_module_specifier (context_p); + } break; } - default: { - parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_MULTIPLY_LITERAL_EXPECTED); + parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_MULTIPLY_LITERAL_EXPECTED); break; } } - if (context_p->token.type == LEXER_LITERAL - && lexer_compare_raw_identifier_to_current (context_p, "from", 4)) - { - /* TODO: Import the requested properties from the given script and export - them from the current to make a redirection. - This part is going to be implemented in the next part of the patch. */ - parser_raise_error (context_p, PARSER_ERR_NOT_IMPLEMENTED); - } - parser_module_add_export_node_to_context (context_p); context_p->module_current_node_p = NULL; } /* parser_parse_export_statement */ diff --git a/jerry-core/parser/js/js-parser-util.c b/jerry-core/parser/js/js-parser-util.c index 7102cc3af9..6ca59d47f6 100644 --- a/jerry-core/parser/js/js-parser-util.c +++ b/jerry-core/parser/js/js-parser-util.c @@ -1066,41 +1066,49 @@ parser_error_to_string (parser_error_t error) /**< error code */ } #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - case PARSER_ERR_MODULE_REQUEST_NOT_FOUND: - { - return "Import request not found in the module."; - } case PARSER_ERR_FILE_NOT_FOUND: { return "Requested module not found."; } - case PARSER_ERR_NOT_IMPLEMENTED: + case PARSER_ERR_FROM_EXPECTED: { - return "Requested feature is not implemented yet."; + return "Expected 'from' token."; } - case PARSER_ERR_LEFT_PAREN_MULTIPLY_LITERAL_EXPECTED: + case PARSER_ERR_FROM_COMMA_EXPECTED: { - return "Expected '{' or '*' or literal token."; + return "Expected 'from' or ',' token."; } - case PARSER_ERR_RIGHT_PAREN_COMMA_FROM_EXPECTED: + case PARSER_ERR_AS_EXPECTED: { - return "Expected '}' or 'as' or 'from' literal token."; + return "Expected 'as' token."; } - case PARSER_ERR_FROM_EXPECTED: + case PARSER_ERR_STRING_EXPECTED: { - return "Expected 'from' token."; + return "Expected a string literal."; } - case PARSER_ERR_STRING_EXPECTED: + case PARSER_ERR_MODULE_UNEXPECTED: { - return "Expected a string."; + return "Import and export statements must be in the global context."; } - case PARSER_ERR_MODULE_REQUEST_LIMIT_REACHED: + case PARSER_ERR_LEFT_BRACE_MULTIPLY_EXPECTED: { - return "Maximum module request count reached."; + return "Expected '{' or '*' token."; } - case PARSER_ERR_MODULE_UNEXPECTED: + case PARSER_ERR_LEFT_BRACE_MULTIPLY_LITERAL_EXPECTED: { - return "Import and export statements must be in the global context."; + return "Expected '{' or '*' or literal token."; + } + case PARSER_ERR_RIGHT_BRACE_COMMA_EXPECTED: + { + return "Expected '}' or ',' token."; + } + case PARSER_ERR_DUPLICATED_EXPORT_IDENTIFIER: + { + return "Duplicate exported identifier."; + } + case PARSER_ERR_DUPLICATED_IMPORT_BINDING: + { + return "Duplicated imported binding name."; } #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ diff --git a/jerry-core/parser/js/js-parser.c b/jerry-core/parser/js/js-parser.c index 734de42ce3..36383900c8 100644 --- a/jerry-core/parser/js/js-parser.c +++ b/jerry-core/parser/js/js-parser.c @@ -17,9 +17,9 @@ #include "ecma-exceptions.h" #include "ecma-helpers.h" #include "ecma-literal-storage.h" +#include "ecma-module.h" #include "jcontext.h" #include "js-parser-internal.h" -#include "ecma-module.h" #ifndef JERRY_DISABLE_JS_PARSER @@ -2399,7 +2399,7 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ context.status_flags |= parse_opts & PARSER_STRICT_MODE_MASK; #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - context.module_context_p = NULL; + context.module_current_node_p = NULL; #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ #if ENABLED (JERRY_ES2015_CLASS) @@ -2479,14 +2479,6 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ JERRY_ASSERT (context.last_cbc_opcode == PARSER_CBC_UNAVAILABLE); JERRY_ASSERT (context.allocated_buffer_p == NULL); -#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - if (context.module_context_p != NULL) - { - parser_module_handle_requests (&context); - ecma_module_load_modules (&context); - } -#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ - compiled_code_p = parser_post_processing (&context); parser_list_free (&context.literal_pool); @@ -2513,6 +2505,14 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ context.allocated_buffer_size); } +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + if (context.module_current_node_p != NULL + && context.module_current_node_p->module_names_p != NULL) + { + ecma_module_release_module_names (context.module_current_node_p->module_names_p); + } +#endif + if (error_location_p != NULL) { error_location_p->error = context.error; @@ -2535,9 +2535,6 @@ parser_parse_source (const uint8_t *arg_list_p, /**< function argument list */ } #endif /* PARSER_DUMP_BYTE_CODE */ -#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - parser_module_context_cleanup (&context); -#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ parser_stack_free (&context); return compiled_code_p; @@ -2866,13 +2863,6 @@ void parser_raise_error (parser_context_t *context_p, /**< context */ parser_error_t error) /**< error code */ { -#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - if (context_p->module_context_p != NULL) - { - parser_module_free_saved_names (context_p->module_current_node_p); - } -#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ - parser_saved_context_t *saved_context_p = context_p->last_context_p; while (saved_context_p != NULL) @@ -2943,6 +2933,12 @@ parser_parse_script (const uint8_t *arg_list_p, /**< function argument list */ if (!*bytecode_data_p) { +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + if (JERRY_CONTEXT (module_top_context_p) != NULL) + { + ecma_module_cleanup (); + } +#endif #ifdef JERRY_DEBUGGER if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) { @@ -2983,6 +2979,22 @@ parser_parse_script (const uint8_t *arg_list_p, /**< function argument list */ #endif /* JERRY_ENABLE_ERROR_MESSAGES */ } +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + if (JERRY_CONTEXT (module_top_context_p) != NULL) + { + ecma_value_t ret_value = ecma_module_parse_modules (); + + if (ECMA_IS_VALUE_ERROR (ret_value)) + { + ecma_bytecode_deref (*bytecode_data_p); + *bytecode_data_p = NULL; + ecma_module_cleanup (); + + return ret_value; + } + } +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + #ifdef JERRY_DEBUGGER if ((JERRY_CONTEXT (debugger_flags) & (JERRY_DEBUGGER_CONNECTED | JERRY_DEBUGGER_PARSER_WAIT)) == (JERRY_DEBUGGER_CONNECTED | JERRY_DEBUGGER_PARSER_WAIT)) diff --git a/jerry-core/parser/js/js-parser.h b/jerry-core/parser/js/js-parser.h index a50ed6450f..af3f21455c 100644 --- a/jerry-core/parser/js/js-parser.h +++ b/jerry-core/parser/js/js-parser.h @@ -130,18 +130,20 @@ typedef enum PARSER_ERR_OBJECT_PROPERTY_REDEFINED, /**< property of object literal redefined */ #if ENABLED (JERRY_ES2015_MODULE_SYSTEM) - PARSER_ERR_RIGHT_PAREN_COMMA_FROM_EXPECTED, /**< rigth paren or comma or from expected */ + PARSER_ERR_FILE_NOT_FOUND, /**< file not found*/ PARSER_ERR_FROM_EXPECTED, /**< from expected */ + PARSER_ERR_FROM_COMMA_EXPECTED, /**< from or comma expected */ + PARSER_ERR_AS_EXPECTED, /**< as expected */ PARSER_ERR_STRING_EXPECTED, /**< string literal expected */ - PARSER_ERR_MODULE_REQUEST_NOT_FOUND, /**< not found imported variable in module */ - PARSER_ERR_FILE_NOT_FOUND, /**< not found given file in the import statement */ - PARSER_ERR_NOT_IMPLEMENTED, /**< feature not implemented yet */ - PARSER_ERR_MODULE_REQUEST_LIMIT_REACHED, /**< maximum number of requests reached */ PARSER_ERR_MODULE_UNEXPECTED, /**< unexpected import or export statement */ - PARSER_ERR_LEFT_PAREN_MULTIPLY_LITERAL_EXPECTED, /**< left paren or multiply or literal expected */ + PARSER_ERR_LEFT_BRACE_MULTIPLY_LITERAL_EXPECTED, /**< left brace or multiply or literal expected */ + PARSER_ERR_LEFT_BRACE_MULTIPLY_EXPECTED, /**< left brace or multiply expected */ + PARSER_ERR_RIGHT_BRACE_COMMA_EXPECTED, /**< right brace or comma expected */ + PARSER_ERR_DUPLICATED_EXPORT_IDENTIFIER, /**< duplicated export identifier name */ + PARSER_ERR_DUPLICATED_IMPORT_BINDING, /**< duplicated import binding name */ #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ - PARSER_ERR_NON_STRICT_ARG_DEFINITION /**< non-strict argument definition */ + PARSER_ERR_NON_STRICT_ARG_DEFINITION /**< non-strict argument definition */ } parser_error_t; /** diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index bb4c96f853..25e3ece1f9 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -239,21 +239,14 @@ ecma_value_t vm_run_module (const ecma_compiled_code_t *bytecode_p, /**< pointer to bytecode to run */ ecma_object_t *lex_env_p) /**< pointer to the specified lexenv to run in */ { - ecma_object_t *glob_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_GLOBAL); - - ecma_value_t ret_value = vm_run (bytecode_p, - ecma_make_object_value (glob_obj_p), - lex_env_p, - false, - NULL, - 0); - - if (ECMA_IS_VALUE_ERROR (ret_value)) - { - ret_value = ecma_create_error_reference_from_context (); - } + ecma_object_t *glob_obj_p = ecma_builtin_get_global (); - return ret_value; + return vm_run (bytecode_p, + ecma_make_object_value (glob_obj_p), + lex_env_p, + false, + NULL, + 0); } /* vm_run_module */ #endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ @@ -3592,6 +3585,25 @@ vm_run (const ecma_compiled_code_t *bytecode_header_p, /**< byte-code data heade JERRY_VLA (ecma_value_t, stack, JERRY_MAX (call_stack_size, 1)); frame_ctx.registers_p = stack; +#if ENABLED (JERRY_ES2015_MODULE_SYSTEM) + if (JERRY_CONTEXT (module_top_context_p) != NULL) + { + ecma_value_t ret_value = ecma_module_connect_imports (); + + if (ecma_is_value_empty (ret_value)) + { + ret_value = ecma_module_check_indirect_exports (); + } + + ecma_module_cleanup (); + + if (!ecma_is_value_empty (ret_value)) + { + return ret_value; + } + } +#endif /* ENABLED (JERRY_ES2015_MODULE_SYSTEM) */ + return vm_execute (&frame_ctx, arg_list_p, arg_list_len); } /* vm_run */ diff --git a/jerry-port/default/default-io.c b/jerry-port/default/default-io.c index 5719a3455e..61dcf27b85 100644 --- a/jerry-port/default/default-io.c +++ b/jerry-port/default/default-io.c @@ -15,6 +15,7 @@ #include #include +#include #include "jerryscript-port.h" #include "jerryscript-port-default.h" @@ -194,3 +195,24 @@ jerry_port_release_source (uint8_t *buffer_p) /**< buffer to free */ { free (buffer_p); } /* jerry_port_release_source */ + +/** + * Normalize a file path + * + * @return length of the path written to the output buffer + */ +size_t +jerry_port_normalize_path (const char *in_path_p, /**< input file path */ + char *out_buf_p, /**< output buffer */ + size_t out_buf_size) /**< size of output buffer */ +{ + /* TODO: implement path normalization */ + size_t len = strlen (in_path_p); + if (len + 1 > out_buf_size) + { + return 0; + } + + strcpy (out_buf_p, in_path_p); + return len; +} /* jerry_port_normalize_path */ diff --git a/targets/nuttx-stm32f4/jerry_main.c b/targets/nuttx-stm32f4/jerry_main.c index 1b264ae9ac..a2c1e1cdca 100644 --- a/targets/nuttx-stm32f4/jerry_main.c +++ b/targets/nuttx-stm32f4/jerry_main.c @@ -558,6 +558,27 @@ jerry_port_release_source (uint8_t *buffer_p) /**< buffer to free */ free (buffer_p); } /* jerry_port_release_source */ +/** + * Normalize a file path + * + * @return length of the path written to the output buffer + */ +size_t +jerry_port_normalize_path (const char *in_path_p, /**< input file path */ + char *out_buf_p, /**< output buffer */ + size_t out_buf_size) /**< size of output buffer */ +{ + size_t len = strlen (in_path_p); + if (len + 1 > out_buf_size) + { + return 0; + } + + /* Return the original string. */ + strcpy (out_buf_p, in_path_p); + return len; +} /* jerry_port_normalize_path */ + /** * Dummy function to get the time zone adjustment. * diff --git a/targets/tizenrt-artik053/apps/jerryscript/jerry_main.c b/targets/tizenrt-artik053/apps/jerryscript/jerry_main.c index e4d6ade6ec..3967dba8de 100644 --- a/targets/tizenrt-artik053/apps/jerryscript/jerry_main.c +++ b/targets/tizenrt-artik053/apps/jerryscript/jerry_main.c @@ -573,6 +573,27 @@ jerry_port_release_source (uint8_t *buffer_p) /**< buffer to free */ free (buffer_p); } /* jerry_port_release_source */ +/** + * Normalize a file path + * + * @return length of the path written to the output buffer + */ +size_t +jerry_port_normalize_path (const char *in_path_p, /**< input file path */ + char *out_buf_p, /**< output buffer */ + size_t out_buf_size) /**< size of output buffer */ +{ + size_t len = strlen (in_path_p); + if (len + 1 > out_buf_size) + { + return 0; + } + + /* Return the original string. */ + strcpy (out_buf_p, in_path_p); + return len; +} /* jerry_port_normalize_path */ + /** * Main program. * diff --git a/tests/jerry/es2015/module-export-01.js b/tests/jerry/es2015/module-export-01.js new file mode 100644 index 0000000000..90bfff549a --- /dev/null +++ b/tests/jerry/es2015/module-export-01.js @@ -0,0 +1,41 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {}; +export {a as aa,}; +export {b as bb, c as cc}; +export {d}; +export var x = 42; +export function f(a) {return a;}; +export class Dog { + constructor (name) { + this.name = name; + } + + speak() { + return this.name + " barks." + } +}; +export default "default"; + +var a = "a"; +var b = 5; +var c = function(a) { return 2 * a;} +var d = [1,2,3]; + +assert (x === 42); +assert (f(1) === 1); +var dog = new Dog("Pluto") +assert(dog.speak() === "Pluto barks.") diff --git a/tests/jerry/es2015/module-export-02.js b/tests/jerry/es2015/module-export-02.js new file mode 100644 index 0000000000..584b761268 --- /dev/null +++ b/tests/jerry/es2015/module-export-02.js @@ -0,0 +1,20 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {} from "tests/jerry/es2015/module-export-01.js"; +export {aa,} from "tests/jerry/es2015/module-export-01.js"; +export {bb as b_, cc as c_} from "tests/jerry/es2015/module-export-01.js"; +export * from "tests/jerry/es2015/module-export-01.js"; +export default function () {return "default"}; diff --git a/tests/jerry/es2015/module-imported-2.js b/tests/jerry/es2015/module-export-03.js similarity index 68% rename from tests/jerry/es2015/module-imported-2.js rename to tests/jerry/es2015/module-export-03.js index 6c0258ad3b..afdd70b6fb 100644 --- a/tests/jerry/es2015/module-imported-2.js +++ b/tests/jerry/es2015/module-export-03.js @@ -13,19 +13,14 @@ * limitations under the License. */ -export function getString (prefix) { - return prefix + "String"; -} +export default class { + constructor(num) { + this.num = num + } -function getAreaOfCircle (radius) { - return radius * radius * pi; + incr() { + return ++(this.num); + } } -export getAreaOfCircle as getArea; - -import { pi } from "tests/jerry/es2015/module-imported-3.js"; -assert (pi === 3.14); - -export pi as b; - -assert (true); +export * from "tests/jerry/es2015/module-export-02.js" diff --git a/tests/jerry/es2015/module-imported.js b/tests/jerry/es2015/module-export-04.js similarity index 79% rename from tests/jerry/es2015/module-imported.js rename to tests/jerry/es2015/module-export-04.js index 4720855fb8..39d7caecd0 100644 --- a/tests/jerry/es2015/module-imported.js +++ b/tests/jerry/es2015/module-export-04.js @@ -13,19 +13,5 @@ * limitations under the License. */ -var a = 1; - -function b () { - return 2; -} - -export var c = 3; - -export function d () { - return 4; -} - -export { a as e, b } -export var f = "str"; - -assert (true); +export var x = 41 +export default a = "str" diff --git a/tests/jerry/es2015/module-export-05.js b/tests/jerry/es2015/module-export-05.js new file mode 100644 index 0000000000..2184128e05 --- /dev/null +++ b/tests/jerry/es2015/module-export-05.js @@ -0,0 +1,18 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from "tests/jerry/es2015/module-export-01.js"; +export * from "tests/jerry/es2015/module-export-04.js"; +export default a = "str" diff --git a/tests/jerry/es2015/module-export-06.js b/tests/jerry/es2015/module-export-06.js new file mode 100644 index 0000000000..06d3d7db4f --- /dev/null +++ b/tests/jerry/es2015/module-export-06.js @@ -0,0 +1,19 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export {} +export {} from "tests/jerry/es2015/module-export-01.js"; +export {}; +export {} from "tests/jerry/es2015/module-export-04.js" diff --git a/tests/jerry/es2015/module-imported-3.js b/tests/jerry/es2015/module-export-07.js similarity index 94% rename from tests/jerry/es2015/module-imported-3.js rename to tests/jerry/es2015/module-export-07.js index 3343e10c89..c8bab81a59 100644 --- a/tests/jerry/es2015/module-imported-3.js +++ b/tests/jerry/es2015/module-export-07.js @@ -13,6 +13,4 @@ * limitations under the License. */ -export var pi = 3.14; - -assert (true); +export default x = y = z = "default"; diff --git a/tests/jerry/es2015/module-import-01.js b/tests/jerry/es2015/module-import-01.js new file mode 100644 index 0000000000..21762995ab --- /dev/null +++ b/tests/jerry/es2015/module-import-01.js @@ -0,0 +1,33 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import "tests/jerry/es2015/module-export-01.js"; +import def from "tests/jerry/es2015/module-export-01.js"; +import {} from "tests/jerry/es2015/module-export-01.js"; +import {aa as a,} from "tests/jerry/es2015/module-export-01.js"; +import {bb as b, cc as c} from "tests/jerry/es2015/module-export-01.js"; +import {x} from "tests/jerry/es2015/module-export-01.js"; +import * as mod from "tests/jerry/es2015/module-export-01.js"; + +assert (def === "default"); +assert (a === "a"); +assert (b === 5); +assert (c(b) === 10); +assert (Array.isArray(mod.d)) +assert (x === 42) +assert (mod.f("str") === "str") + +dog = new mod.Dog("Oddie") +assert (dog.speak() === "Oddie barks.") diff --git a/tests/jerry/es2015/module.js b/tests/jerry/es2015/module-import-02.js similarity index 62% rename from tests/jerry/es2015/module.js rename to tests/jerry/es2015/module-import-02.js index be6e4a5387..67fe0d3f5e 100644 --- a/tests/jerry/es2015/module.js +++ b/tests/jerry/es2015/module-import-02.js @@ -13,23 +13,12 @@ * limitations under the License. */ -import { b, c, d, e, f as g } from "tests/jerry/es2015/module-imported.js" +import def, * as mod from "tests/jerry/es2015/module-export-02.js"; +import {b_, c_,} from "tests/jerry/es2015/module-export-02.js"; -import -{ - b as pi, - getString, - getArea -} from "tests/jerry/es2015/module-imported-2.js" - -var str = "str"; - -assert (b () === 2); -assert (c === 3); -assert (d () === 4); -assert (e === 1); -assert (g === str); - -assert (pi === 3.14); -assert (getArea (2) == 12.56); -assert (getString (str) === "strString") +assert (def() === "default") +assert (mod.aa === "a") +assert (b_ === 5) +assert (c_(b_) === 10) +assert (mod.x === 42) +assert (Array.isArray(mod.d)) diff --git a/tests/jerry/es2015/module-import-03.js b/tests/jerry/es2015/module-import-03.js new file mode 100644 index 0000000000..b874983ba1 --- /dev/null +++ b/tests/jerry/es2015/module-import-03.js @@ -0,0 +1,24 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import incrementer, {aa, c_, x,} from "tests/jerry/es2015/module-export-03.js" +var i = new incrementer(3); +assert(i.incr() === 4); +assert(i.incr() === 5); +assert(i.incr() === 6); + +assert (aa === "a"); +assert (x === 42); +assert (c_(x) == 84); diff --git a/tests/jerry/fail/module-002.js b/tests/jerry/fail/module-002.js index 7ff9db72c0..6b407bd537 100644 --- a/tests/jerry/fail/module-002.js +++ b/tests/jerry/fail/module-002.js @@ -13,4 +13,4 @@ * limitations under the License. */ -import { , as b } from "tests/jerry/es2015/module-imported.js"; +import { , as b } from "tests/jerry/es2015/module-export-01.js"; diff --git a/tests/jerry/fail/module-003.js b/tests/jerry/fail/module-003.js index 843b09cfbb..eadde5efa4 100644 --- a/tests/jerry/fail/module-003.js +++ b/tests/jerry/fail/module-003.js @@ -13,4 +13,4 @@ * limitations under the License. */ -import , as b from "tests/jerry/es2015/module-imported.js"; +import , as b from "tests/jerry/es2015/module-export-01.js"; diff --git a/tests/jerry/fail/module-004.js b/tests/jerry/fail/module-004.js index 3a6f29b6a0..6786d051ab 100644 --- a/tests/jerry/fail/module-004.js +++ b/tests/jerry/fail/module-004.js @@ -13,4 +13,4 @@ * limitations under the License. */ -import { b as , } from "tests/jerry/es2015/module-imported.js"; +import { b as , } from "tests/jerry/es2015/module-export-01.js"; diff --git a/tests/jerry/fail/module-005.js b/tests/jerry/fail/module-005.js index f76f57cfbc..62fbe501a7 100644 --- a/tests/jerry/fail/module-005.js +++ b/tests/jerry/fail/module-005.js @@ -13,4 +13,5 @@ * limitations under the License. */ -import b as , from "tests/jerry/es2015/module-imported.js"; +/* Named imports must be in a NamedImports block. */ +import b as , from "tests/jerry/es2015/module-export-01.js"; diff --git a/tests/jerry/fail/module-006.js b/tests/jerry/fail/module-006.js index e02d2affa7..0079f6c56d 100644 --- a/tests/jerry/fail/module-006.js +++ b/tests/jerry/fail/module-006.js @@ -13,4 +13,5 @@ * limitations under the License. */ -import { as as as } from "tests/jerry/es2015/module-imported.js"; +/* Can't have reserved words for the referenced bindings. */ +export { yield as y }; diff --git a/tests/jerry/fail/module-007.js b/tests/jerry/fail/module-007.js index 75ee37891f..77c36fd437 100644 --- a/tests/jerry/fail/module-007.js +++ b/tests/jerry/fail/module-007.js @@ -13,4 +13,5 @@ * limitations under the License. */ -import { from as as } from "tests/jerry/es2015/module-imported.js"; +/* Module requests must always be evaluated. */ +import "tests/jerry/fail/module-sideeffect.js" diff --git a/tests/jerry/fail/module-008.js b/tests/jerry/fail/module-008.js index c09e83e842..f57828b0d9 100644 --- a/tests/jerry/fail/module-008.js +++ b/tests/jerry/fail/module-008.js @@ -13,4 +13,5 @@ * limitations under the License. */ - import { b } from +/* A string literal must always follow the 'from' keyword. */ +import { b } from diff --git a/tests/jerry/fail/module-009.js b/tests/jerry/fail/module-009.js index 96fffefabf..1d564c1e0a 100644 --- a/tests/jerry/fail/module-009.js +++ b/tests/jerry/fail/module-009.js @@ -13,4 +13,5 @@ * limitations under the License. */ +/* A string literal must always follow the 'from' keyword. */ import { b } from 3 diff --git a/tests/jerry/fail/module-010.js b/tests/jerry/fail/module-010.js index ddeb94b953..ef3b923ce2 100644 --- a/tests/jerry/fail/module-010.js +++ b/tests/jerry/fail/module-010.js @@ -13,4 +13,5 @@ * limitations under the License. */ -import { c as a, d as a } from "tests/jerry/es2015/module-imported.js"; +/* Can't have duplicate local bindings */ +import { c as a, d as a } from "tests/jerry/es2015/module-export-01.js"; diff --git a/tests/jerry/fail/module-014.js b/tests/jerry/fail/module-014.js index 85d2b6d351..f422fab970 100644 --- a/tests/jerry/fail/module-014.js +++ b/tests/jerry/fail/module-014.js @@ -13,6 +13,7 @@ * limitations under the License. */ +/* Import/export statements must be in the global scope. */ if (true) { - import { c } from "tests/jerry/es2015/module-imported.js"; + import { c } from "tests/jerry/es2015/module-export-01.js"; } diff --git a/tests/jerry/fail/module-015.js b/tests/jerry/fail/module-015.js index 116161459a..e176eda700 100644 --- a/tests/jerry/fail/module-015.js +++ b/tests/jerry/fail/module-015.js @@ -13,6 +13,7 @@ * limitations under the License. */ +/* Import/export statements must be in the global scope. */ function someFunction() { - import { c } from "tests/jerry/es2015/module-imported.js"; + import { c } from "tests/jerry/es2015/module-export-01.js"; } diff --git a/tests/jerry/fail/module-016.js b/tests/jerry/fail/module-016.js index a363fef319..1e2a84876d 100644 --- a/tests/jerry/fail/module-016.js +++ b/tests/jerry/fail/module-016.js @@ -13,4 +13,5 @@ * limitations under the License. */ -eval ("import { c } from 'tests/jerry/es2015/module-imported.js';"); +/* Import/export statements must be in the global scope. */ +eval ('import { c } from "tests/jerry/es2015/module-export-01.js";'); diff --git a/tests/jerry/fail/module-017.js b/tests/jerry/fail/module-017.js index 5a5e0f87d4..f873d3a45f 100644 --- a/tests/jerry/fail/module-017.js +++ b/tests/jerry/fail/module-017.js @@ -13,5 +13,5 @@ * limitations under the License. */ -// File does not exist. -import { a } from "tests/jerry/fail/module-exports.js" +/* NamedImports must always be followed by a FromClause. */ +import { b }, from "tests/jerry/es2015/module-export-01.js" diff --git a/tests/jerry/fail/module-018.js b/tests/jerry/fail/module-018.js index b41b095807..1ccfd1cd55 100644 --- a/tests/jerry/fail/module-018.js +++ b/tests/jerry/fail/module-018.js @@ -13,8 +13,5 @@ * limitations under the License. */ -export function getString () { - return prefix; -} - -assert (getString()); +/* An import statement can have either a NameSpaceImport or NamedIpmorts */ +import * as mod, { b } from "tests/jerry/es2015/module-export-01.js" diff --git a/tests/jerry/fail/module-019.js b/tests/jerry/fail/module-019.js index f314355755..1d83ba9350 100644 --- a/tests/jerry/fail/module-019.js +++ b/tests/jerry/fail/module-019.js @@ -13,4 +13,5 @@ * limitations under the License. */ +/* An ImportClause must be followed by a FromClause. */ import { c } diff --git a/tests/jerry/fail/module-020.js b/tests/jerry/fail/module-020.js new file mode 100644 index 0000000000..241b2b6426 --- /dev/null +++ b/tests/jerry/fail/module-020.js @@ -0,0 +1,17 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* '*' is not valid inside NamedImports. */ +import { *, d } from "tests/jerry/es2015/module-imported-01.js" diff --git a/tests/jerry/fail/module-021.js b/tests/jerry/fail/module-021.js new file mode 100644 index 0000000000..2b44e962a2 --- /dev/null +++ b/tests/jerry/fail/module-021.js @@ -0,0 +1,18 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Can't have duplicated local bindings. */ +import { b } from "tests/jerry/es2015/module-export-01.js" +import { b } from "tests/jerry/es2015/module-export-02.js" diff --git a/tests/jerry/fail/module-022.js b/tests/jerry/fail/module-022.js new file mode 100644 index 0000000000..afc7ff43b7 --- /dev/null +++ b/tests/jerry/fail/module-022.js @@ -0,0 +1,17 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* FromClause must follow an ImportClause. */ +import from "tests/jerry/es2015/module-export-02.js" diff --git a/tests/jerry/fail/module-023.js b/tests/jerry/fail/module-023.js new file mode 100644 index 0000000000..4d09473df7 --- /dev/null +++ b/tests/jerry/fail/module-023.js @@ -0,0 +1,17 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Namespace imports must have a local name. */ +import * from "tests/jerry/es2015/module-export-01.js" diff --git a/tests/jerry/fail/module-024.js b/tests/jerry/fail/module-024.js new file mode 100644 index 0000000000..7bfb069c90 --- /dev/null +++ b/tests/jerry/fail/module-024.js @@ -0,0 +1,17 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Star exports can't have an export name. */ +export * as star from "tests/jerry/es2015/module-export-01.js" diff --git a/tests/jerry/fail/module-025.js b/tests/jerry/fail/module-025.js new file mode 100644 index 0000000000..7095030c32 --- /dev/null +++ b/tests/jerry/fail/module-025.js @@ -0,0 +1,17 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Indirect exports must be checked if they are resolvable. */ +export { l } from "tests/jerry/es2015/module-export-01.js" diff --git a/tests/jerry/fail/module-026.js b/tests/jerry/fail/module-026.js new file mode 100644 index 0000000000..2e3e2c87fd --- /dev/null +++ b/tests/jerry/fail/module-026.js @@ -0,0 +1,17 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Can't have circular imports/exports. */ +export { b } from "tests/jerry/fail/module-027.js" diff --git a/tests/jerry/fail/module-027.js b/tests/jerry/fail/module-027.js new file mode 100644 index 0000000000..88083813a7 --- /dev/null +++ b/tests/jerry/fail/module-027.js @@ -0,0 +1,17 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Can't have circular imports/exports. */ +export { b } from "tests/jerry/fail/module-026.js" diff --git a/tests/jerry/fail/module-028.js b/tests/jerry/fail/module-028.js new file mode 100644 index 0000000000..4eb2ae1c11 --- /dev/null +++ b/tests/jerry/fail/module-028.js @@ -0,0 +1,17 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Ambiguous import */ +import { x } from "tests/jerry/es2015/module-export-05.js" diff --git a/tests/jerry/fail/module-029.js b/tests/jerry/fail/module-029.js new file mode 100644 index 0000000000..0e22465f4c --- /dev/null +++ b/tests/jerry/fail/module-029.js @@ -0,0 +1,17 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Import/export statements must be in the global scope. */ +Function('','import { c } from "tests/jerry/es2015/module-export-01.js";') diff --git a/tests/jerry/fail/module-030.js b/tests/jerry/fail/module-030.js new file mode 100644 index 0000000000..961513f27e --- /dev/null +++ b/tests/jerry/fail/module-030.js @@ -0,0 +1,17 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* No default export found. */ +import def from "tests/jerry/es2015/module-export-06.js" diff --git a/tests/jerry/fail/module-sideeffect.js b/tests/jerry/fail/module-sideeffect.js new file mode 100644 index 0000000000..9be895a7e0 --- /dev/null +++ b/tests/jerry/fail/module-sideeffect.js @@ -0,0 +1,16 @@ +/* Copyright JS Foundation and other contributors, http://js.foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +throw new Error("side-effect")