]> git.kaiwu.me - njs.git/commitdiff
Refactoring of user modules importing.
authorDmitry Volyntsev <xeioex@nginx.com>
Mon, 21 Feb 2022 14:49:38 +0000 (14:49 +0000)
committerDmitry Volyntsev <xeioex@nginx.com>
Mon, 21 Feb 2022 14:49:38 +0000 (14:49 +0000)
Previously, user modules were compiled as as anonymous functions in a
global scope.  This is incorrect, because modules should be compiled
in their own scope.

In addition, this patch introduces HostResolveImportedModule support.
When vm->options.ops->module_loader is provided, a module lookup
and compilation is delegated to this callback.

This closes #443 issue on Github.

43 files changed:
external/njs_crypto_module.c
external/njs_fs_module.c
external/njs_query_string_module.c
nginx/ngx_http_js_module.c
nginx/ngx_stream_js_module.c
src/njs.h
src/njs_buffer.c
src/njs_builtin.c
src/njs_disassembler.c
src/njs_function.c
src/njs_generator.c
src/njs_generator.h
src/njs_module.c
src/njs_module.h
src/njs_parser.c
src/njs_parser.h
src/njs_shell.c
src/njs_variable.c
src/njs_vm.c
src/njs_vm.h
src/njs_vmcode.c
src/njs_vmcode.h
test/js/import_cyclic.t.js [new file with mode: 0644]
test/js/import_expression.t.js
test/js/import_global_ref.t.js [new file with mode: 0644]
test/js/import_global_ref_var.t.js [new file with mode: 0644]
test/js/import_order.t.js [new file with mode: 0644]
test/js/import_recursive.t.js
test/js/import_recursive_early_access.t.js [new file with mode: 0644]
test/js/import_recursive_relative.t.js [new file with mode: 0644]
test/js/import_sinking_export_default.t.js [new file with mode: 0644]
test/js/module/cyclic_a.js [new file with mode: 0644]
test/js/module/cyclic_b.js [new file with mode: 0644]
test/js/module/export_global_a.js [new file with mode: 0644]
test/js/module/http.js [new file with mode: 0644]
test/js/module/jwt.js [new file with mode: 0644]
test/js/module/lib1.js
test/js/module/order.js [new file with mode: 0644]
test/js/module/order2.js [new file with mode: 0644]
test/js/module/recursive.js [new file with mode: 0644]
test/js/module/recursive_early_access.js [new file with mode: 0644]
test/js/module/recursive_relative.js [new file with mode: 0644]
test/js/module/sinking_export_default.js [new file with mode: 0644]

index a602828995c026793d839f9ee6cbfec09b04b508..fbef019ff595b110c65e645de1d23e3d47e43ca1 100644 (file)
@@ -646,7 +646,7 @@ njs_crypto_init(njs_vm_t *vm)
         return NJS_ERROR;
     }
 
-    module = njs_module_add(vm, &njs_str_value("crypto"), 1);
+    module = njs_module_add(vm, &njs_str_value("crypto"));
     if (njs_slow_path(module == NULL)) {
         return NJS_ERROR;
     }
index a586af0a232d941dc4b49583acda12520abc3f47..71a1d27e9fe37bd162f59f13a6639a7d52ec5283 100644 (file)
@@ -3090,7 +3090,7 @@ njs_fs_init(njs_vm_t *vm)
         return NJS_ERROR;
     }
 
-    module = njs_module_add(vm, &njs_str_value("fs"), 1);
+    module = njs_module_add(vm, &njs_str_value("fs"));
     if (njs_slow_path(module == NULL)) {
         return NJS_ERROR;
     }
index ae0327e54ebf33f6009c696fc74db65c152ffd52..dedc5d8211066f3c3867673b36c89a753f6d3fc4 100644 (file)
@@ -967,7 +967,7 @@ njs_query_string_init(njs_vm_t *vm)
         return NJS_ERROR;
     }
 
-    module = njs_module_add(vm, &njs_str_value("querystring"), 1);
+    module = njs_module_add(vm, &njs_str_value("querystring"));
     if (njs_slow_path(module == NULL)) {
         return NJS_ERROR;
     }
index 40ee8491f4aba16c4e8269c42042f3cd04bc8f6d..84e5ae8e8182c0918373c2e9059bcfc40d11ab97 100644 (file)
@@ -704,7 +704,8 @@ static njs_external_t  ngx_http_js_ext_request[] = {
 
 static njs_vm_ops_t ngx_http_js_ops = {
     ngx_http_js_set_timer,
-    ngx_http_js_clear_timer
+    ngx_http_js_clear_timer,
+    NULL,
 };
 
 
@@ -3490,8 +3491,12 @@ ngx_http_js_init_main_conf(ngx_conf_t *cf, void *conf)
 
     import = jmcf->imports->elts;
     for (i = 0; i < jmcf->imports->nelts; i++) {
-        size += sizeof("import  from '';\n") - 1 + import[i].name.len
-                + import[i].path.len;
+
+        /* import <name> from '<path>'; globalThis.<name> = <name>; */
+
+        size += sizeof("import  from '';") - 1 + import[i].name.len * 3
+                + import[i].path.len
+                + sizeof(" globalThis. = ;\n") - 1;
     }
 
     start = ngx_pnalloc(cf->pool, size);
@@ -3502,11 +3507,18 @@ ngx_http_js_init_main_conf(ngx_conf_t *cf, void *conf)
     p = start;
     import = jmcf->imports->elts;
     for (i = 0; i < jmcf->imports->nelts; i++) {
+
+        /* import <name> from '<path>'; globalThis.<name> = <name>; */
+
         p = ngx_cpymem(p, "import ", sizeof("import ") - 1);
         p = ngx_cpymem(p, import[i].name.data, import[i].name.len);
         p = ngx_cpymem(p, " from '", sizeof(" from '") - 1);
         p = ngx_cpymem(p, import[i].path.data, import[i].path.len);
-        p = ngx_cpymem(p, "';\n", sizeof("';\n") - 1);
+        p = ngx_cpymem(p, "'; globalThis.", sizeof("'; globalThis.") - 1);
+        p = ngx_cpymem(p, import[i].name.data, import[i].name.len);
+        p = ngx_cpymem(p, " = ", sizeof(" = ") - 1);
+        p = ngx_cpymem(p, import[i].name.data, import[i].name.len);
+        p = ngx_cpymem(p, ";\n", sizeof(";\n") - 1);
     }
 
     njs_vm_opt_init(&options);
index b2b30907c702af63e7b0c723fb98eb3a66ae7585..ab3368da3bac00d95523b7baff62cf998fc6a93a 100644 (file)
@@ -456,7 +456,8 @@ static njs_external_t  ngx_stream_js_ext_session[] = {
 
 static njs_vm_ops_t ngx_stream_js_ops = {
     ngx_stream_js_set_timer,
-    ngx_stream_js_clear_timer
+    ngx_stream_js_clear_timer,
+    NULL,
 };
 
 
@@ -1512,8 +1513,11 @@ ngx_stream_js_init_main_conf(ngx_conf_t *cf, void *conf)
 
     import = jmcf->imports->elts;
     for (i = 0; i < jmcf->imports->nelts; i++) {
-        size += sizeof("import  from '';\n") - 1 + import[i].name.len
-                + import[i].path.len;
+        /* import <name> from '<path>'; globalThis.<name> = <name>; */
+
+        size += sizeof("import  from '';") - 1 + import[i].name.len * 3
+                + import[i].path.len
+                + sizeof(" globalThis. = ;\n") - 1;
     }
 
     start = ngx_pnalloc(cf->pool, size);
@@ -1524,11 +1528,18 @@ ngx_stream_js_init_main_conf(ngx_conf_t *cf, void *conf)
     p = start;
     import = jmcf->imports->elts;
     for (i = 0; i < jmcf->imports->nelts; i++) {
+
+        /* import <name> from '<path>'; globalThis.<name> = <name>; */
+
         p = ngx_cpymem(p, "import ", sizeof("import ") - 1);
         p = ngx_cpymem(p, import[i].name.data, import[i].name.len);
         p = ngx_cpymem(p, " from '", sizeof(" from '") - 1);
         p = ngx_cpymem(p, import[i].path.data, import[i].path.len);
-        p = ngx_cpymem(p, "';\n", sizeof("';\n") - 1);
+        p = ngx_cpymem(p, "'; globalThis.", sizeof("'; globalThis.") - 1);
+        p = ngx_cpymem(p, import[i].name.data, import[i].name.len);
+        p = ngx_cpymem(p, " = ", sizeof(" = ") - 1);
+        p = ngx_cpymem(p, import[i].name.data, import[i].name.len);
+        p = ngx_cpymem(p, ";\n", sizeof(";\n") - 1);
     }
 
     njs_vm_opt_init(&options);
index d6805be02d097b4d57778970fdcf266984eecd7b..fa37d071b5c001a25adaff65aab9e698de4a211f 100644 (file)
--- a/src/njs.h
+++ b/src/njs.h
@@ -28,6 +28,7 @@
 
 typedef uintptr_t                   njs_index_t;
 typedef struct njs_vm_s             njs_vm_t;
+typedef struct njs_mod_s            njs_mod_t;
 typedef union  njs_value_s          njs_value_t;
 typedef struct njs_function_s       njs_function_t;
 typedef struct njs_vm_shared_s      njs_vm_shared_t;
@@ -183,11 +184,14 @@ typedef njs_host_event_t (*njs_set_timer_t)(njs_external_ptr_t external,
     uint64_t delay, njs_vm_event_t vm_event);
 typedef void (*njs_event_destructor_t)(njs_external_ptr_t external,
     njs_host_event_t event);
+typedef njs_mod_t *(*njs_module_loader_t)(njs_vm_t *vm,
+    njs_external_ptr_t external, njs_str_t *name);
 
 
 typedef struct {
     njs_set_timer_t                 set_timer;
     njs_event_destructor_t          clear_timer;
+    njs_module_loader_t             module_loader;
 } njs_vm_ops_t;
 
 
@@ -254,6 +258,8 @@ NJS_EXPORT njs_vm_t *njs_vm_create(njs_vm_opt_t *options);
 NJS_EXPORT void njs_vm_destroy(njs_vm_t *vm);
 
 NJS_EXPORT njs_int_t njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end);
+NJS_EXPORT njs_mod_t *njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name,
+    u_char **start, u_char *end);
 NJS_EXPORT njs_vm_t *njs_vm_clone(njs_vm_t *vm, njs_external_ptr_t external);
 
 NJS_EXPORT njs_vm_event_t njs_vm_add_event(njs_vm_t *vm,
index 0473bcaf1d2c11ce41468b280ae38326171d28e0..5daf73769fa14efe38117a2f53f1fd48c5d3b701 100644 (file)
@@ -3015,7 +3015,7 @@ njs_buffer_init(njs_vm_t *vm)
         return NJS_ERROR;
     }
 
-    module = njs_module_add(vm, &njs_str_value("buffer"), 1);
+    module = njs_module_add(vm, &njs_str_value("buffer"));
     if (njs_slow_path(module == NULL)) {
         return NJS_ERROR;
     }
index 03fac9c95f48d58f0e3d0a9512f9617b6c059258..d23551b1cd7bfb43a8eb207f942f69bdb41164b9 100644 (file)
@@ -761,7 +761,9 @@ njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function,
             break;
         }
 
-        if (njs_is_object(&module->value)) {
+        if (njs_is_object(&module->value)
+            && !njs_object(&module->value)->shared)
+        {
             ctx.match = module->name;
 
             ret = njs_object_traverse(vm, njs_object(&module->value), &ctx,
index 4c93a04fa37a747cc9f1c119275ae1e1cf16ec58..1fccd058f5547e3f2989dafc70c0c95916331869 100644 (file)
@@ -171,15 +171,6 @@ njs_disassembler(njs_vm_t *vm)
     code = vm->codes->start;
     n = vm->codes->items;
 
-    while (n != 0) {
-        if (code->start == vm->start) {
-            break;
-        }
-
-        code++;
-        n--;
-    }
-
     while (n != 0) {
         njs_printf("%V:%V\n", &code->file, &code->name);
         njs_disassemble(code);
@@ -207,6 +198,7 @@ njs_disassemble(njs_vm_code_t *code)
     njs_vmcode_3addr_t           *code3;
     njs_vmcode_array_t           *array;
     njs_vmcode_catch_t           *catch;
+    njs_vmcode_import_t          *import;
     njs_vmcode_finally_t         *finally;
     njs_vmcode_try_end_t         *try_end;
     njs_vmcode_move_arg_t        *move_arg;
@@ -398,6 +390,18 @@ njs_disassemble(njs_vm_code_t *code)
             continue;
         }
 
+        if (operation == NJS_VMCODE_IMPORT) {
+            import = (njs_vmcode_import_t *) p;
+
+            njs_printf("%5uD | %05uz IMPORT            %04Xz %V\n",
+                       line, p - start, (size_t) import->retval,
+                       &import->module->name);
+
+            p += sizeof(njs_vmcode_import_t);
+
+            continue;
+        }
+
         if (operation == NJS_VMCODE_TRY_START) {
             try_start = (njs_vmcode_try_start_t *) p;
 
index c07f55c4cdf04d1bac0eaa14b52d8bbe6c7b8789..c9d4d9732fd262af1636cb63fcaa3b4327caaa6a 100644 (file)
@@ -1209,7 +1209,7 @@ njs_function_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
         }
     }
 
-    ret = njs_generator_init(&generator, 0, 1);
+    ret = njs_generator_init(&generator, &file, 0, 1);
     if (njs_slow_path(ret != NJS_OK)) {
         njs_internal_error(vm, "njs_generator_init() failed");
         return NJS_ERROR;
index 22f1bf8254380f010e9df8e178a5fc6d7151bd7d..4d803e712df020016c3dcecbbea39767d6e22c03 100644 (file)
@@ -319,8 +319,6 @@ static njs_int_t njs_generate_throw_end(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_import_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
-static njs_int_t njs_generate_import_statement_end(njs_vm_t *vm,
-    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_export_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_export_statement_end(njs_vm_t *vm,
@@ -424,8 +422,8 @@ static njs_int_t njs_generate_index_release(njs_vm_t *vm,
         njs_code_offset_diff(generator, patch->jump_offset)
 
 
-#define njs_generate_syntax_error(vm, node, fmt, ...)                         \
-    njs_parser_node_error(vm, node, NJS_OBJ_TYPE_SYNTAX_ERROR, fmt,           \
+#define njs_generate_syntax_error(vm, node, file, fmt, ...)                   \
+    njs_parser_node_error(vm, NJS_OBJ_TYPE_SYNTAX_ERROR, node, file, fmt,     \
                           ##__VA_ARGS__)
 
 
@@ -436,13 +434,14 @@ static const njs_str_t  undef_label  = { 0xffffffff, (u_char *) "" };
 
 
 njs_int_t
-njs_generator_init(njs_generator_t *generator, njs_int_t depth,
-    njs_bool_t runtime)
+njs_generator_init(njs_generator_t *generator, njs_str_t *file,
+    njs_int_t depth, njs_bool_t runtime)
 {
     njs_memzero(generator, sizeof(njs_generator_t));
 
     njs_queue_init(&generator->stack);
 
+    generator->file = *file;
     generator->depth = depth;
     generator->runtime = runtime;
 
@@ -2312,7 +2311,8 @@ njs_generate_continue_statement(njs_vm_t *vm, njs_generator_t *generator,
 
 syntax_error:
 
-    njs_generate_syntax_error(vm, node, "Illegal continue statement");
+    njs_generate_syntax_error(vm, node, &generator->file,
+                              "Illegal continue statement");
 
     return NJS_ERROR;
 }
@@ -2357,7 +2357,8 @@ njs_generate_break_statement(njs_vm_t *vm, njs_generator_t *generator,
 
 syntax_error:
 
-    njs_generate_syntax_error(vm, node, "Illegal break statement");
+    njs_generate_syntax_error(vm, node, &generator->file,
+                              "Illegal break statement");
 
     return NJS_ERROR;
 }
@@ -3102,17 +3103,13 @@ njs_generate_function(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
     njs_int_t              ret;
-    njs_bool_t             module;
-    const njs_str_t        *name;
     njs_function_lambda_t  *lambda;
     njs_vmcode_function_t  *function;
 
     lambda = node->u.value.data.u.lambda;
-    module = node->right->scope->module;
-
-    name = module ? &njs_entry_module : &njs_entry_anonymous;
 
-    ret = njs_generate_function_scope(vm, generator, lambda, node, name);
+    ret = njs_generate_function_scope(vm, generator, lambda, node,
+                                      &njs_entry_anonymous);
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
@@ -3641,13 +3638,11 @@ njs_generate_function_scope(njs_vm_t *vm, njs_generator_t *prev,
     njs_function_lambda_t *lambda, njs_parser_node_t *node,
     const njs_str_t *name)
 {
-    njs_int_t          ret;
-    njs_arr_t          *arr;
-    njs_bool_t         module;
-    njs_uint_t         depth;
-    njs_vm_code_t      *code;
-    njs_generator_t    generator;
-    njs_parser_node_t  *file_node;
+    njs_int_t        ret;
+    njs_arr_t        *arr;
+    njs_uint_t       depth;
+    njs_vm_code_t    *code;
+    njs_generator_t  generator;
 
     depth = prev->depth;
 
@@ -3656,7 +3651,7 @@ njs_generate_function_scope(njs_vm_t *vm, njs_generator_t *prev,
         return NJS_ERROR;
     }
 
-    ret = njs_generator_init(&generator, depth, prev->runtime);
+    ret = njs_generator_init(&generator, &prev->file, depth, prev->runtime);
     if (njs_slow_path(ret != NJS_OK)) {
         njs_internal_error(vm, "njs_generator_init() failed");
         return NJS_ERROR;
@@ -3673,11 +3668,6 @@ njs_generate_function_scope(njs_vm_t *vm, njs_generator_t *prev,
         return NJS_ERROR;
     }
 
-    module = node->right->scope->module;
-    file_node = module ? node->right : node;
-
-    code->file = file_node->scope->file;
-
     lambda->start = generator.code_start;
     lambda->closures = generator.closures->start;
     lambda->nclosures = generator.closures->items;
@@ -3774,7 +3764,7 @@ njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator,
     code = njs_arr_item(vm->codes, index);
     code->start = generator->code_start;
     code->end = generator->code_end;
-    code->file = scope->file;
+    code->file = generator->file;
     code->name = *name;
 
     generator->code_size = generator->code_end - generator->code_start;
@@ -4620,45 +4610,22 @@ static njs_int_t
 njs_generate_import_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_variable_t     *var;
-    njs_parser_node_t  *lvalue, *expr;
+    njs_variable_t       *var;
+    njs_parser_node_t    *lvalue;
+    njs_vmcode_import_t  *import;
 
     lvalue = node->left;
-    expr = node->right;
 
     var = njs_variable_reference(vm, lvalue);
     if (njs_slow_path(var == NULL)) {
         return NJS_ERROR;
     }
 
-    if (expr->left != NULL) {
-        njs_generator_next(generator, njs_generate, expr->left);
-
-        return njs_generator_after(vm, generator,
-                                   njs_queue_first(&generator->stack), node,
-                                   njs_generate_import_statement_end, NULL, 0);
-    }
-
-    return njs_generate_import_statement_end(vm, generator, node);
-}
-
-
-static njs_int_t
-njs_generate_import_statement_end(njs_vm_t *vm, njs_generator_t *generator,
-    njs_parser_node_t *node)
-{
-    njs_mod_t                 *module;
-    njs_parser_node_t         *expr;
-    njs_vmcode_object_copy_t  *copy;
-
-    expr = node->right;
-
-    module = (njs_mod_t *) expr->index;
+    njs_generate_code(generator, njs_vmcode_import_t, import,
+                      NJS_VMCODE_IMPORT, 1, node);
 
-    njs_generate_code(generator, njs_vmcode_object_copy_t, copy,
-                      NJS_VMCODE_OBJECT_COPY, 2, node);
-    copy->retval = node->left->index;
-    copy->object = module->index;
+    import->module = node->u.module;
+    import->retval = lvalue->index;
 
     return njs_generator_stack_pop(vm, generator, NULL);
 }
index b5d8db636811eb79c9cb03bb2b9eeb5c83977a43..045d598dd576160c78d0893bc2d2b49739bfb8db 100644 (file)
@@ -27,6 +27,7 @@ struct njs_generator_s {
     njs_arr_t                       *index_cache;
     njs_arr_t                       *closures;
 
+    njs_str_t                       file;
     njs_arr_t                       *lines;
 
     size_t                          code_size;
@@ -40,8 +41,8 @@ struct njs_generator_s {
 };
 
 
-njs_int_t njs_generator_init(njs_generator_t *generator, njs_int_t depth,
-    njs_bool_t runtime);
+njs_int_t njs_generator_init(njs_generator_t *generator, njs_str_t *file,
+    njs_int_t depth, njs_bool_t runtime);
 njs_vm_code_t *njs_generate_scope(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_scope_t *scope, const njs_str_t *name);
 uint32_t njs_lookup_line(njs_vm_code_t *code, uint32_t offset);
index 5257efede3d8aee7d651f25933648433629e3cc5..16e29a57b327406acc29a4876d0280a3ae191bf7 100644 (file)
@@ -12,286 +12,60 @@ typedef struct {
     int                 fd;
     njs_str_t           name;
     njs_str_t           file;
+    char                path[NJS_MAX_PATH + 1];
 } njs_module_info_t;
 
 
-typedef struct {
-    njs_str_t           text;
-    njs_module_info_t   info;
-    njs_lexer_t         *prev;
-    njs_lexer_t         lexer;
-} njs_module_temp_t;
-
-
-static njs_int_t njs_parser_module_lambda_after(njs_parser_t *parser,
-    njs_lexer_token_t *token, njs_queue_link_t *current);
-static njs_int_t njs_parser_module_after(njs_parser_t *parser,
-    njs_lexer_token_t *token, njs_queue_link_t *current);
-
 static njs_int_t njs_module_lookup(njs_vm_t *vm, const njs_str_t *cwd,
     njs_module_info_t *info);
-static njs_int_t njs_module_relative_path(njs_vm_t *vm,
-    const njs_str_t *dir, njs_module_info_t *info);
-static njs_int_t njs_module_absolute_path(njs_vm_t *vm,
+static njs_int_t njs_module_path(njs_vm_t *vm, const njs_str_t *dir,
     njs_module_info_t *info);
-static njs_bool_t njs_module_realpath_equal(const njs_str_t *path1,
-    const njs_str_t *path2);
 static njs_int_t njs_module_read(njs_vm_t *vm, int fd, njs_str_t *body);
-static njs_mod_t *njs_module_find(njs_vm_t *vm, njs_str_t *name,
-    njs_bool_t local);
-static njs_int_t njs_module_insert(njs_parser_t *parser, njs_mod_t *module);
-
-
-njs_int_t
-njs_module_load(njs_vm_t *vm)
-{
-    njs_int_t     ret;
-    njs_mod_t     **item, *module;
-    njs_uint_t    i;
-    njs_value_t   *value;
-    njs_object_t  *object;
-
-    if (vm->modules == NULL) {
-        return NJS_OK;
-    }
-
-    item = vm->modules->start;
-
-    for (i = 0; i < vm->modules->items; i++) {
-        module = *item;
+static njs_mod_t *njs_default_module_loader(njs_vm_t *vm,
+    njs_external_ptr_t external, njs_str_t *name);
 
-        if (module->function.native) {
-            value = njs_scope_valid_value(vm, module->index);
-            njs_value_assign(value, &module->value);
 
-            object = njs_object_value_copy(vm, value);
-            if (njs_slow_path(object == NULL)) {
-                return NJS_ERROR;
-            }
-
-        } else {
-            ret = njs_vm_invoke(vm, &module->function, NULL, 0,
-                                njs_scope_valid_value(vm, module->index));
-            if (ret == NJS_ERROR) {
-                return ret;
-            }
-        }
-
-        item++;
-    }
-
-    return NJS_OK;
-}
-
-
-void
-njs_module_reset(njs_vm_t *vm)
-{
-    njs_mod_t           **item, *module;
-    njs_uint_t          i;
-    njs_lvlhsh_query_t  lhq;
-
-    if (vm->modules == NULL) {
-        return;
-    }
-
-    item = vm->modules->start;
-
-    for (i = 0; i < vm->modules->items; i++) {
-        module = *item;
-
-        if (!module->function.native) {
-            lhq.key = module->name;
-            lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length);
-            lhq.proto = &njs_modules_hash_proto;
-            lhq.pool = vm->mem_pool;
-
-            (void) njs_lvlhsh_delete(&vm->modules_hash, &lhq);
-        }
-
-        item++;
-    }
-
-    njs_arr_reset(vm->modules);
-}
-
-
-njs_int_t
-njs_parser_module(njs_parser_t *parser, njs_lexer_token_t *token,
-    njs_queue_link_t *current)
+njs_mod_t *
+njs_parser_module(njs_parser_t *parser, njs_str_t *name)
 {
-    njs_int_t          ret;
-    njs_str_t          name, text;
-    njs_mod_t          *module;
-    njs_module_temp_t  *temp;
-    njs_module_info_t  info;
-
-    name = token->text;
-
-    parser->node = NULL;
-
-    module = njs_module_find(parser->vm, &name, 1);
-    if (module != NULL && module->function.native) {
-        njs_lexer_consume_token(parser->lexer, 1);
+    njs_mod_t            *module;
+    njs_vm_t             *vm;
+    njs_external_ptr_t   external;
+    njs_module_loader_t  loader;
 
-        parser->target = (njs_parser_node_t *) module;
-
-        return njs_parser_module_after(parser, token, current);
-    }
-
-    njs_memzero(&text, sizeof(njs_str_t));
-
-    if (parser->vm->options.sandbox || name.length == 0) {
-        njs_parser_syntax_error(parser, "Cannot find module \"%V\"", &name);
-        goto fail;
-    }
-
-    /* Non-native module. */
-
-    njs_memzero(&info, sizeof(njs_module_info_t));
-
-    info.name = name;
+    vm = parser->vm;
 
-    ret = njs_module_lookup(parser->vm, &parser->scope->cwd, &info);
-    if (njs_slow_path(ret != NJS_OK)) {
-        njs_parser_syntax_error(parser, "Cannot find module \"%V\"", &name);
-        goto fail;
+    if (name->length == 0) {
+        njs_parser_syntax_error(parser, "Cannot find module \"%V\"", name);
+        return NULL;
     }
 
-    module = njs_module_find(parser->vm, &info.file, 1);
+    module = njs_module_find(vm, name, 1);
     if (module != NULL) {
-        (void) close(info.fd);
-        njs_lexer_consume_token(parser->lexer, 1);
-
-        parser->target = (njs_parser_node_t *) module;
-
-        return njs_parser_module_after(parser, token, current);
-    }
-
-    ret = njs_module_read(parser->vm, info.fd, &text);
-
-    (void) close(info.fd);
-
-    if (njs_slow_path(ret != NJS_OK)) {
-        njs_internal_error(parser->vm, "while reading \"%V\" module",
-                           &info.file);
-        goto fail;
-    }
-
-    if (njs_module_realpath_equal(&parser->lexer->file, &info.file)) {
-        njs_parser_syntax_error(parser, "Cannot import itself \"%V\"",
-                                &info.file);
-        goto fail;
-    }
-
-    temp = njs_mp_alloc(parser->vm->mem_pool, sizeof(njs_module_temp_t));
-    if (njs_slow_path(temp == NULL)) {
-        return NJS_ERROR;
-    }
-
-    ret = njs_lexer_init(parser->vm, &temp->lexer, &info.file, text.start,
-                         text.start + text.length, 0);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return NJS_ERROR;
-    }
-
-    njs_lexer_consume_token(parser->lexer, 1);
-
-    temp->prev = parser->lexer;
-    temp->info = info;
-    temp->text = text;
-
-    parser->lexer = &temp->lexer;
-
-    njs_parser_next(parser, njs_parser_module_lambda);
-
-    return njs_parser_after(parser, current, temp, 0,
-                            njs_parser_module_lambda_after);
-
-fail:
-
-    if (text.start != NULL) {
-        njs_mp_free(parser->vm->mem_pool, text.start);
-    }
-
-    return NJS_ERROR;
-}
-
-
-static njs_int_t
-njs_parser_module_lambda_after(njs_parser_t *parser, njs_lexer_token_t *token,
-    njs_queue_link_t *current)
-{
-    njs_mod_t          *module;
-    njs_module_temp_t  *temp;
-
-    temp = (njs_module_temp_t *) parser->target;
-
-    if (parser->ret != NJS_OK) {
-        njs_mp_free(parser->vm->mem_pool, temp->text.start);
-        njs_mp_free(parser->vm->mem_pool, temp);
-
-        if (token->type == NJS_TOKEN_END) {
-            return njs_parser_stack_pop(parser);
-        }
-
-        return njs_parser_failed(parser);
+        goto done;
     }
 
-    module = njs_module_add(parser->vm, &temp->info.file, 0);
-    if (njs_slow_path(module == NULL)) {
-        parser->lexer = temp->prev;
-
-        if (temp->text.start != NULL) {
-            njs_mp_free(parser->vm->mem_pool, temp->text.start);
-        }
+    external = parser;
+    loader = njs_default_module_loader;
 
-        return njs_parser_failed(parser);
+    if (vm->options.ops != NULL && vm->options.ops->module_loader != NULL) {
+        loader = vm->options.ops->module_loader;
+        external = vm->external;
     }
 
-    module->function.args_offset = 1;
-    module->function.u.lambda = parser->node->u.value.data.u.lambda;
-
-    njs_mp_free(parser->vm->mem_pool, temp->text.start);
-
-    parser->lexer = temp->prev;
-    parser->target = (njs_parser_node_t *) module;
-
-    njs_mp_free(parser->vm->mem_pool, temp);
-
-    return njs_parser_module_after(parser, token, current);
-}
-
-
-static njs_int_t
-njs_parser_module_after(njs_parser_t *parser, njs_lexer_token_t *token,
-    njs_queue_link_t *current)
-{
-    njs_int_t          ret;
-    njs_mod_t          *module;
-    njs_parser_node_t  *node;
-
-    node = njs_parser_node_new(parser, 0);
-    if (njs_slow_path(node == NULL)) {
-       return NJS_ERROR;
+    module = loader(vm, external, name);
+    if (module == NULL) {
+        njs_parser_syntax_error(parser, "Cannot find module \"%V\"", name);
+        return NULL;
     }
 
-    node->left = parser->node;
-
-    module = (njs_mod_t *) parser->target;
+done:
 
     if (module->index == 0) {
-        ret = njs_module_insert(parser, module);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return NJS_ERROR;
-        }
+        module->index = vm->shared->module_items++;
     }
 
-    node->index = (njs_index_t) module;
-
-    parser->node = node;
-
-    return njs_parser_stack_pop(parser);
+    return module;
 }
 
 
@@ -303,10 +77,10 @@ njs_module_lookup(njs_vm_t *vm, const njs_str_t *cwd, njs_module_info_t *info)
     njs_uint_t  i;
 
     if (info->name.start[0] == '/') {
-        return njs_module_absolute_path(vm, info);
+        return njs_module_path(vm, NULL, info);
     }
 
-    ret = njs_module_relative_path(vm, cwd, info);
+    ret = njs_module_path(vm, cwd, info);
 
     if (ret != NJS_DECLINED) {
         return ret;
@@ -319,7 +93,7 @@ njs_module_lookup(njs_vm_t *vm, const njs_str_t *cwd, njs_module_info_t *info)
     path = vm->paths->start;
 
     for (i = 0; i < vm->paths->items; i++) {
-        ret = njs_module_relative_path(vm, path, info);
+        ret = njs_module_path(vm, path, info);
 
         if (ret != NJS_DECLINED) {
             return ret;
@@ -333,74 +107,60 @@ njs_module_lookup(njs_vm_t *vm, const njs_str_t *cwd, njs_module_info_t *info)
 
 
 static njs_int_t
-njs_module_absolute_path(njs_vm_t *vm, njs_module_info_t *info)
+njs_module_path(njs_vm_t *vm, const njs_str_t *dir, njs_module_info_t *info)
 {
-    njs_str_t  file;
-
-    file.length = info->name.length;
-    file.start = njs_mp_alloc(vm->mem_pool, file.length + 1);
-    if (njs_slow_path(file.start == NULL)) {
-        return NJS_ERROR;
-    }
-
-    memcpy(file.start, info->name.start, file.length);
-    file.start[file.length] = '\0';
-
-    info->fd = open((char *) file.start, O_RDONLY);
-    if (info->fd < 0) {
-        njs_mp_free(vm->mem_pool, file.start);
-        return NJS_DECLINED;
-    }
-
-    info->file = file;
-
-    return NJS_OK;
-}
-
-
-static njs_int_t
-njs_module_relative_path(njs_vm_t *vm, const njs_str_t *dir,
-    njs_module_info_t *info)
-{
-    u_char      *p;
-    njs_str_t   file;
+    char        *p;
+    size_t      length;
     njs_bool_t  trail;
+    char        src[NJS_MAX_PATH + 1];
 
-    file.length = dir->length;
+    trail = 0;
+    length = info->name.length;
 
-    if (file.length == 0) {
-        return NJS_DECLINED;
-    }
+    if (dir != NULL) {
+        length = dir->length;
 
-    trail = (dir->start[dir->length - 1] != '/');
+        if (length == 0) {
+            return NJS_DECLINED;
+        }
 
-    if (trail) {
-        file.length++;
-    }
+        trail = (dir->start[dir->length - 1] != '/');
 
-    file.length += info->name.length;
+        if (trail) {
+            length++;
+        }
+    }
 
-    file.start = njs_mp_alloc(vm->mem_pool, file.length + 1);
-    if (njs_slow_path(file.start == NULL)) {
+    if (njs_slow_path(length > NJS_MAX_PATH)) {
         return NJS_ERROR;
     }
 
-    p = njs_cpymem(file.start, dir->start, dir->length);
+    p = &src[0];
 
-    if (trail) {
-        *p++ = '/';
+    if (dir != NULL) {
+        p = (char *) njs_cpymem(p, dir->start, dir->length);
+
+        if (trail) {
+            *p++ = '/';
+        }
     }
 
-    p = njs_cpymem(p, info->name.start, info->name.length);
+    p = (char *) njs_cpymem(p, info->name.start, info->name.length);
     *p = '\0';
 
-    info->fd = open((char *) file.start, O_RDONLY);
+    p = realpath(&src[0], &info->path[0]);
+    if (p == NULL) {
+        return NJS_DECLINED;
+    }
+
+    info->fd = open(&info->path[0], O_RDONLY);
     if (info->fd < 0) {
-        njs_mp_free(vm->mem_pool, file.start);
         return NJS_DECLINED;
     }
 
-    info->file = file;
+
+    info->file.start = (u_char *) &info->path[0];
+    info->file.length = njs_strlen(info->file.start);
 
     return NJS_OK;
 }
@@ -412,6 +172,8 @@ njs_module_read(njs_vm_t *vm, int fd, njs_str_t *text)
     ssize_t      n;
     struct stat  sb;
 
+    text->start = NULL;
+
     if (fstat(fd, &sb) == -1) {
         goto fail;
     }
@@ -445,18 +207,6 @@ fail:
 }
 
 
-static njs_bool_t
-njs_module_realpath_equal(const njs_str_t *path1, const njs_str_t *path2)
-{
-    char  rpath1[MAXPATHLEN], rpath2[MAXPATHLEN];
-
-    realpath((char *) path1->start, rpath1);
-    realpath((char *) path2->start, rpath2);
-
-    return (strcmp(rpath1, rpath2) == 0);
-}
-
-
 static njs_int_t
 njs_module_hash_test(njs_lvlhsh_query_t *lhq, void *data)
 {
@@ -482,7 +232,7 @@ const njs_lvlhsh_proto_t  njs_modules_hash_proto
 };
 
 
-static njs_mod_t *
+njs_mod_t *
 njs_module_find(njs_vm_t *vm, njs_str_t *name, njs_bool_t shared)
 {
     njs_int_t           ret;
@@ -533,11 +283,10 @@ njs_module_find(njs_vm_t *vm, njs_str_t *name, njs_bool_t shared)
 
 
 njs_mod_t *
-njs_module_add(njs_vm_t *vm, njs_str_t *name, njs_bool_t shared)
+njs_module_add(njs_vm_t *vm, njs_str_t *name)
 {
     njs_int_t           ret;
     njs_mod_t           *module;
-    njs_lvlhsh_t        *hash;
     njs_lvlhsh_query_t  lhq;
 
     module = njs_mp_zalloc(vm->mem_pool, sizeof(njs_mod_t));
@@ -559,9 +308,7 @@ njs_module_add(njs_vm_t *vm, njs_str_t *name, njs_bool_t shared)
     lhq.pool = vm->mem_pool;
     lhq.proto = &njs_modules_hash_proto;
 
-    hash = shared ? &vm->shared->modules_hash : &vm->modules_hash;
-
-    ret = njs_lvlhsh_insert(hash, &lhq);
+    ret = njs_lvlhsh_insert(&vm->shared->modules_hash, &lhq);
     if (njs_fast_path(ret == NJS_OK)) {
         return module;
     }
@@ -575,38 +322,6 @@ njs_module_add(njs_vm_t *vm, njs_str_t *name, njs_bool_t shared)
 }
 
 
-static njs_int_t
-njs_module_insert(njs_parser_t *parser, njs_mod_t *module)
-{
-    njs_vm_t            *vm;
-    njs_mod_t           **value;
-    njs_parser_scope_t  *scope;
-
-    scope = njs_parser_global_scope(parser);
-    vm = parser->vm;
-
-    module->index = njs_scope_index(scope->type, scope->items, NJS_LEVEL_LOCAL,
-                                    NJS_VARIABLE_VAR);
-    scope->items++;
-
-    if (vm->modules == NULL) {
-        vm->modules = njs_arr_create(vm->mem_pool, 4, sizeof(njs_mod_t *));
-        if (njs_slow_path(vm->modules == NULL)) {
-            return NJS_ERROR;
-        }
-    }
-
-    value = njs_arr_add(vm->modules);
-    if (njs_slow_path(value == NULL)) {
-        return NJS_ERROR;
-    }
-
-    *value = module;
-
-    return NJS_OK;
-}
-
-
 njs_int_t
 njs_module_require(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
@@ -640,3 +355,43 @@ njs_module_require(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 
     return NJS_OK;
 }
+
+
+static njs_mod_t *
+njs_default_module_loader(njs_vm_t *vm, njs_external_ptr_t external,
+    njs_str_t *name)
+{
+    njs_int_t          ret;
+    njs_str_t          cwd, text;
+    njs_parser_t       *prev;
+    njs_mod_t          *module;
+    njs_module_info_t  info;
+
+    prev = external;
+
+    njs_memzero(&info, sizeof(njs_module_info_t));
+
+    info.name = *name;
+    njs_file_dirname(&prev->lexer->file, &cwd);
+
+    ret = njs_module_lookup(vm, &cwd, &info);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NULL;
+    }
+
+    ret = njs_module_read(vm, info.fd, &text);
+
+    (void) close(info.fd);
+
+    if (njs_slow_path(ret != NJS_OK)) {
+        njs_internal_error(vm, "while reading \"%V\" module", &info.file);
+        return NULL;
+    }
+
+    module = njs_vm_compile_module(vm, &info.file, &text.start,
+                                   &text.start[text.length]);
+
+    njs_mp_free(vm->mem_pool, text.start);
+
+    return module;
+}
index 210f37cf1a979551ff68d765ffc6d69a2bfe9d9a..deb5635942e11623b1a934e7a02e9c0f1c6c0ac8 100644 (file)
@@ -8,19 +8,18 @@
 #define _NJS_MODULE_H_INCLUDED_
 
 
-typedef struct {
+struct njs_mod_s {
     njs_str_t                   name;
     njs_value_t                 value;
     njs_index_t                 index;
     njs_function_t              function;
-} njs_mod_t;
+};
 
 
-njs_int_t njs_module_load(njs_vm_t *vm);
-void njs_module_reset(njs_vm_t *vm);
-njs_mod_t *njs_module_add(njs_vm_t *vm, njs_str_t *name, njs_bool_t shared);
-njs_int_t njs_parser_module(njs_parser_t *parser, njs_lexer_token_t *token,
-    njs_queue_link_t *current);
+njs_mod_t *njs_module_add(njs_vm_t *vm, njs_str_t *name);
+njs_mod_t *njs_module_find(njs_vm_t *vm, njs_str_t *name,
+    njs_bool_t shared);
+njs_mod_t *njs_parser_module(njs_parser_t *parser, njs_str_t *name);
 njs_int_t njs_module_require(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused);
 
index bfd0e9e71002740568e9bde43cb743967cb9721b..13c03b00ef9ad4def7289b4b3600b1b3c8b4fe35 100644 (file)
@@ -433,10 +433,6 @@ static njs_int_t njs_parser_export_after(njs_parser_t *parser,
 
 static njs_int_t njs_parser_import(njs_parser_t *parser,
     njs_lexer_token_t *token, njs_queue_link_t *current);
-static njs_int_t njs_parser_import_after(njs_parser_t *parser,
-    njs_lexer_token_t *token, njs_queue_link_t *current);
-static njs_int_t njs_parser_module_lambda_after(njs_parser_t *parser,
-    njs_lexer_token_t *token, njs_queue_link_t *current);
 static njs_int_t njs_parser_export_sink(njs_parser_t *parser);
 
 static njs_parser_node_t *njs_parser_return_set(njs_parser_t *parser,
@@ -558,7 +554,9 @@ njs_parser(njs_vm_t *vm, njs_parser_t *parser)
     njs_set_undefined(&vm->retval);
 
     if (parser->scope == NULL) {
-        ret = njs_parser_scope_begin(parser, NJS_SCOPE_GLOBAL, 1);
+        ret = njs_parser_scope_begin(parser,
+                                     parser->module ? NJS_SCOPE_FUNCTION
+                                                    : NJS_SCOPE_GLOBAL, 1);
         if (njs_slow_path(ret != NJS_OK)) {
             return NJS_ERROR;
         }
@@ -619,10 +617,18 @@ njs_parser(njs_vm_t *vm, njs_parser_t *parser)
         }
     }
 
-    parser->node->token_type = NJS_TOKEN_END;
-    parser->node->token_line = parser->lexer->line;
+    if (parser->module) {
+        ret = njs_parser_export_sink(parser);
+        if (ret != NJS_OK) {
+            return NJS_ERROR;
+        }
+
+    } else {
+        parser->node->token_type = NJS_TOKEN_END;
+        parser->node->token_line = parser->lexer->line;
 
-    njs_parser_chain_top_set(parser, parser->node);
+        njs_parser_chain_top_set(parser, parser->node);
+    }
 
     return NJS_OK;
 }
@@ -655,7 +661,6 @@ static njs_int_t
 njs_parser_scope_begin(njs_parser_t *parser, njs_scope_t type,
     njs_bool_t init_this)
 {
-    njs_lexer_t                      *lexer;
     njs_variable_t                   *var;
     njs_parser_scope_t               *scope, *parent;
     const njs_lexer_keyword_entry_t  *keyword;
@@ -673,13 +678,6 @@ njs_parser_scope_begin(njs_parser_t *parser, njs_scope_t type,
     njs_rbtree_init(&scope->labels, njs_parser_scope_rbtree_compare);
     njs_rbtree_init(&scope->references, njs_parser_scope_rbtree_compare);
 
-    lexer = parser->lexer;
-
-    if (lexer->file.length != 0) {
-        njs_file_basename(&lexer->file, &scope->file);
-        njs_file_dirname(&lexer->file, &scope->cwd);
-    }
-
     parent = parser->scope;
     scope->parent = parent;
     parser->scope = scope;
@@ -4681,19 +4679,47 @@ static njs_int_t
 njs_parser_statement_after(njs_parser_t *parser, njs_lexer_token_t *token,
     njs_queue_link_t *current)
 {
-    njs_parser_node_t  *stmt;
+    njs_parser_node_t  *stmt, *last, *new_node, **child;
+    njs_parser_node_t  *node, *top;
+
+    child = &parser->target;
+    last = *child;
+
+    new_node = parser->node;
+
+    if (new_node->hoist) {
+        child = &njs_parser_chain_top(parser);
+
+        while (*child != NULL) {
+            node = *child;
+
+            if (node->hoist) {
+                break;
+            }
+
+            child = &node->left;
+        }
+
+        last = *child;
+    }
 
     stmt = njs_parser_node_new(parser, NJS_TOKEN_STATEMENT);
     if (njs_slow_path(stmt == NULL)) {
         return NJS_ERROR;
     }
 
-    stmt->left = parser->target;
-    stmt->right = parser->node;
+    stmt->hoist = new_node->hoist;
+    stmt->left = last;
+    stmt->right = new_node;
 
-    parser->node = stmt;
+    *child = stmt;
 
-    njs_parser_chain_top_set(parser, stmt);
+    top = (child != &parser->target) ? njs_parser_chain_top(parser)
+                                     : stmt;
+
+    parser->node = top;
+
+    njs_parser_chain_top_set(parser, top);
 
     return njs_parser_stack_pop(parser);
 }
@@ -5978,11 +6004,11 @@ njs_parser_return_statement(njs_parser_t *parser, njs_lexer_token_t *token,
          scope != NULL;
          scope = scope->parent)
     {
-        if (scope->type == NJS_SCOPE_FUNCTION && !scope->module) {
+        if (scope->type == NJS_SCOPE_FUNCTION) {
             break;
         }
 
-        if (scope->type == NJS_SCOPE_GLOBAL) {
+        if (scope->parent == NULL) {
             njs_parser_syntax_error(parser, "Illegal return statement");
             return NJS_ERROR;
         }
@@ -7665,7 +7691,7 @@ njs_parser_export(njs_parser_t *parser, njs_lexer_token_t *token,
 {
     njs_parser_node_t  *node;
 
-    if (!parser->scope->module) {
+    if (!parser->module) {
         njs_parser_syntax_error(parser, "Illegal export statement");
         return NJS_DONE;
     }
@@ -7710,9 +7736,10 @@ static njs_int_t
 njs_parser_import(njs_parser_t *parser, njs_lexer_token_t *token,
     njs_queue_link_t *current)
 {
+    njs_variable_t     *var;
     njs_parser_node_t  *name, *import;
 
-    if (parser->scope->type != NJS_SCOPE_GLOBAL && !parser->scope->module) {
+    if (parser->scope->parent != NULL) {
         njs_parser_syntax_error(parser, "Illegal import statement");
         return NJS_DONE;
     }
@@ -7722,12 +7749,14 @@ njs_parser_import(njs_parser_t *parser, njs_lexer_token_t *token,
         return NJS_DONE;
     }
 
-    name = njs_parser_variable_node(parser, token->unique_id, NJS_VARIABLE_VAR,
-                                    NULL);
+    name = njs_parser_variable_node(parser, token->unique_id, NJS_VARIABLE_LET,
+                                    &var);
     if (name == NULL) {
         return NJS_ERROR;
     }
 
+    var->init = 1;
+
     name->token_line = token->line;
 
     njs_lexer_consume_token(parser->lexer, 1);
@@ -7757,129 +7786,27 @@ njs_parser_import(njs_parser_t *parser, njs_lexer_token_t *token,
         return NJS_ERROR;
     }
 
+    import->hoist = 1;
     import->token_line = parser->line;
     import->left = name;
 
-    njs_parser_next(parser, njs_parser_module);
-
-    return njs_parser_after(parser, current, import, 1,
-                            njs_parser_import_after);
-}
-
-
-static njs_int_t
-njs_parser_import_after(njs_parser_t *parser, njs_lexer_token_t *token,
-    njs_queue_link_t *current)
-{
-    if (njs_parser_expect_semicolon(parser, token) != NJS_OK) {
-        return njs_parser_failed(parser);
-    }
-
-    parser->target->right = parser->node;
-
-    parser->node = parser->target;
-
-    return njs_parser_stack_pop(parser);
-}
-
-
-static const njs_lexer_entry_t njs_parser_module_entry =
-{
-    .name = njs_str("module")
-};
-
-
-njs_int_t
-njs_parser_module_lambda(njs_parser_t *parser, njs_lexer_token_t *token,
-    njs_queue_link_t *current)
-{
-    njs_int_t              ret;
-    uintptr_t              unique_id;
-    njs_variable_t         *var;
-    njs_parser_node_t      *node, *parent;
-    njs_function_lambda_t  *lambda;
-
-    node = njs_parser_node_new(parser, NJS_TOKEN_FUNCTION_EXPRESSION);
-    if (node == NULL) {
-        return NJS_ERROR;
-    }
-
-    ret = njs_parser_scope_begin(parser, NJS_SCOPE_FUNCTION, 0);
-    if (ret != NJS_OK) {
-        return NJS_ERROR;
-    }
-
-    node->left = njs_parser_node_new(parser, NJS_TOKEN_NAME);
-    if (node->left == NULL) {
-        return NJS_ERROR;
-    }
-
-    unique_id = (uintptr_t) &njs_parser_module_entry;
-
-    var = njs_variable_scope_add(parser, parser->scope, parser->scope,
-                                 unique_id, NJS_VARIABLE_FUNCTION, 1);
-    if (var == NULL) {
-        return NJS_ERROR;
-    }
-
-    ret = njs_parser_variable_reference(parser, parser->scope, node->left,
-                                        unique_id, NJS_DECLARATION);
-    if (ret != NJS_OK) {
+    import->u.module = njs_parser_module(parser, &token->text);
+    if (njs_slow_path(import->u.module == NULL)) {
         return NJS_ERROR;
     }
 
-    node->left->u.reference.variable = var;
+    njs_lexer_consume_token(parser->lexer, 1);
 
-    lambda = njs_function_lambda_alloc(parser->vm, 1);
-    if (lambda == NULL) {
+    token = njs_lexer_token(parser->lexer, 0);
+    if (token == NULL) {
         return NJS_ERROR;
     }
 
-    node->token_line = token->line;
-    node->u.value.data.u.lambda = lambda;
-
-    parser->node = node;
-
-    parser->scope->module = 1;
-
-    parent = parser->node;
-    parser->node = NULL;
-
-    njs_parser_next(parser, njs_parser_statement_list);
-
-    return njs_parser_after(parser, current, parent, 0,
-                            njs_parser_module_lambda_after);
-}
-
-
-static njs_int_t
-njs_parser_module_lambda_after(njs_parser_t *parser, njs_lexer_token_t *token,
-    njs_queue_link_t *current)
-{
-    njs_int_t       ret;
-    njs_variable_t  *var, **vv;
-
-    ret = njs_parser_export_sink(parser);
-    if (ret != NJS_OK) {
-        return NJS_ERROR;
+    if (njs_parser_expect_semicolon(parser, token) != NJS_OK) {
+        return njs_parser_failed(parser);
     }
 
-    parser->target->right = njs_parser_chain_top(parser);
-
-    parser->node = parser->target;
-
-    vv = &parser->target->left->u.reference.variable;
-
-    var = *vv;
-    *vv = NULL;
-
-    var->index = njs_scope_index(var->scope->type, var->scope->items,
-                                 NJS_LEVEL_LOCAL, NJS_VARIABLE_VAR);
-    var->scope->items++;
-
-    parser->node->u.value.data.u.lambda->self = var->index;
-
-    njs_parser_scope_end(parser);
+    parser->node = import;
 
     return njs_parser_stack_pop(parser);
 }
@@ -8074,7 +8001,7 @@ njs_parser_reference(njs_parser_t *parser, njs_lexer_token_t *token)
             scope = njs_function_scope(scope->parent);
         }
 
-        if (scope->type == NJS_SCOPE_GLOBAL) {
+        if (scope->parent == NULL) {
             njs_parser_syntax_error(parser, "\"%V\" object in global scope",
                                     &token->text);
             return NULL;
@@ -8818,21 +8745,18 @@ njs_parser_unexpected_token(njs_vm_t *vm, njs_parser_t *parser,
 
 
 static void
-njs_parser_scope_error(njs_vm_t *vm, njs_parser_scope_t *scope,
-    njs_object_type_t type, uint32_t line, const char *fmt, va_list args)
+njs_parser_error(njs_vm_t *vm, njs_object_type_t type, njs_str_t *file,
+    uint32_t line, const char *fmt, va_list args)
 {
     size_t       width;
     u_char       msg[NJS_MAX_ERROR_STR];
     u_char       *p, *end;
-    njs_str_t    *file;
     njs_int_t    ret;
     njs_value_t  value;
 
     static const njs_value_t  file_name = njs_string("fileName");
     static const njs_value_t  line_number = njs_string("lineNumber");
 
-    file = &scope->file;
-
     p = msg;
     end = msg + NJS_MAX_ERROR_STR;
 
@@ -8878,20 +8802,20 @@ njs_parser_lexer_error(njs_parser_t *parser, njs_object_type_t type,
     }
 
     va_start(args, fmt);
-    njs_parser_scope_error(parser->vm, parser->scope, type,
-                           parser->lexer->line, fmt, args);
+    njs_parser_error(parser->vm, type, &parser->lexer->file,
+                     parser->lexer->line, fmt, args);
     va_end(args);
 }
 
 
 void
-njs_parser_node_error(njs_vm_t *vm, njs_parser_node_t *node,
-    njs_object_type_t type, const char *fmt, ...)
+njs_parser_node_error(njs_vm_t *vm, njs_object_type_t type,
+    njs_parser_node_t *node, njs_str_t *file, const char *fmt, ...)
 {
     va_list  args;
 
     va_start(args, fmt);
-    njs_parser_scope_error(vm, node->scope, type, node->token_line, fmt, args);
+    njs_parser_error(vm, type, file, node->token_line, fmt, args);
     va_end(args);
 }
 
index 15c01c7e17352d4baaabcef9a268716d290e7ee4..d4d188de8068e1c87fbf151de054e766a2d13175 100644 (file)
@@ -23,11 +23,7 @@ struct njs_parser_scope_s {
     uint32_t                        temp;
     uint32_t                        items;
 
-    njs_str_t                       cwd;
-    njs_str_t                       file;
-
     njs_scope_t                     type:8;
-    uint8_t                         module;
     uint8_t                         arrow_function;
     uint8_t                         dest_disable;
     uint8_t                         async;
@@ -38,6 +34,7 @@ struct njs_parser_scope_s {
 struct njs_parser_node_s {
     njs_token_type_t                token_type:16;
     uint8_t                         ctor:1;
+    uint8_t                         hoist:1;
     uint8_t                         temporary;    /* 1 bit  */
     uint32_t                        token_line;
 
@@ -47,6 +44,7 @@ struct njs_parser_node_s {
         njs_value_t                 value;
         njs_vmcode_operation_t      operation;
         njs_parser_node_t           *object;
+        njs_mod_t                   *module;
     } u;
 
     njs_str_t                       name;
@@ -83,7 +81,11 @@ struct njs_parser_s {
     njs_variable_type_t             var_type;
     njs_int_t                       ret;
     uintptr_t                       undefined_id;
+
+    uint8_t                         module;
     njs_bool_t                      strict_semicolon;
+
+    njs_str_t                       file;
     uint32_t                        line;
 };
 
@@ -125,8 +127,6 @@ njs_int_t njs_parser_init(njs_vm_t *vm, njs_parser_t *parser,
     njs_uint_t runtime);
 njs_int_t njs_parser(njs_vm_t *vm, njs_parser_t *parser);
 
-njs_int_t njs_parser_module_lambda(njs_parser_t *parser,
-    njs_lexer_token_t *token, njs_queue_link_t *current);
 njs_bool_t njs_variable_closure_test(njs_parser_scope_t *root,
     njs_parser_scope_t *scope);
 njs_variable_t *njs_variable_resolve(njs_vm_t *vm, njs_parser_node_t *node);
@@ -141,8 +141,8 @@ njs_int_t njs_parser_string_create(njs_vm_t *vm, njs_lexer_token_t *token,
     njs_value_t *value);
 void njs_parser_lexer_error(njs_parser_t *parser,
     njs_object_type_t type, const char *fmt, ...);
-void njs_parser_node_error(njs_vm_t *vm, njs_parser_node_t *node,
-    njs_object_type_t type, const char *fmt, ...);
+void njs_parser_node_error(njs_vm_t *vm, njs_object_type_t type,
+    njs_parser_node_t *node, njs_str_t *file, const char *fmt, ...);
 
 njs_int_t njs_parser_traverse(njs_vm_t *vm, njs_parser_node_t *root,
     void *ctx, njs_parser_traverse_cb_t cb);
@@ -214,21 +214,6 @@ njs_parser_node_string(njs_vm_t *vm, njs_lexer_token_t *token,
 }
 
 
-njs_inline njs_parser_scope_t *
-njs_parser_global_scope(njs_parser_t *parser)
-{
-    njs_parser_scope_t  *scope;
-
-    scope = parser->scope;
-
-    while (scope->type != NJS_SCOPE_GLOBAL) {
-        scope = scope->parent;
-    }
-
-    return scope;
-}
-
-
 njs_inline njs_parser_scope_t *
 njs_function_scope(njs_parser_scope_t *scope)
 {
index 257591de38ebd91d851a810af082559b12417ede..237d6bae88d0afddf90501b0da15da291153e4b5 100644 (file)
@@ -203,7 +203,8 @@ static const njs_lvlhsh_proto_t  njs_timelabel_hash_proto njs_aligned(64) = {
 
 static njs_vm_ops_t njs_console_ops = {
     njs_console_set_timer,
-    njs_console_clear_timer
+    njs_console_clear_timer,
+    NULL,
 };
 
 
@@ -230,7 +231,6 @@ static njs_console_t  njs_console;
 int
 main(int argc, char **argv)
 {
-    char          path[MAXPATHLEN], *p;
     njs_vm_t      *vm;
     njs_int_t     ret;
     njs_opts_t    opts;
@@ -257,21 +257,8 @@ main(int argc, char **argv)
     njs_vm_opt_init(&vm_options);
 
     if (opts.file == NULL) {
-        p = getcwd(path, sizeof(path));
-        if (p == NULL) {
-            njs_stderror("getcwd() failed:%s\n", strerror(errno));
-            ret = NJS_ERROR;
-            goto done;
-        }
-
-        if (opts.command == NULL) {
-            memcpy(path + njs_strlen(path), "/shell", sizeof("/shell"));
-
-        } else {
-            memcpy(path + njs_strlen(path), "/string", sizeof("/string"));
-        }
-
-        opts.file = path;
+        opts.file = (opts.command == NULL) ? (char *) "shell"
+                                           : (char *) "string";
     }
 
     vm_options.file.start = (u_char *) opts.file;
index d3a3fd813b28d29bf96a88c7413bb357044177d4..9ea34237bc77b0cc9a2468222bd2e84f5279a7ec 100644 (file)
@@ -222,7 +222,7 @@ njs_variable_scope_find(njs_parser_t *parser, njs_parser_scope_t *scope,
         return root;
     }
 
-    module = parser->vm->options.module || scope->module;
+    module = parser->vm->options.module || parser->module;
 
     if (module) {
         if (type == NJS_VARIABLE_FUNCTION
index 86bce1a86317ec7a5af136e50f091588889c46a7..dadec63cdb4e1b4c586e0d4fe7b6f48c0f1d95e6 100644 (file)
@@ -148,9 +148,7 @@ njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end)
     njs_generator_t     generator;
     njs_parser_scope_t  *scope;
 
-    if (vm->modules != NULL) {
-        njs_module_reset(vm);
-    }
+    vm->codes = NULL;
 
     ret = njs_parser_init(vm, &parser, vm->global_scope, &vm->options.file,
                           *start, end, 0);
@@ -183,7 +181,7 @@ njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end)
     *start = parser.lexer->start;
     scope = parser.scope;
 
-    ret = njs_generator_init(&generator, 0, 0);
+    ret = njs_generator_init(&generator, &vm->options.file, 0, 0);
     if (njs_slow_path(ret != NJS_OK)) {
         njs_internal_error(vm, "njs_generator_init() failed");
         return NJS_ERROR;
@@ -247,6 +245,79 @@ njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end)
 }
 
 
+njs_mod_t *
+njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name, u_char **start,
+    u_char *end)
+{
+    njs_int_t              ret;
+    njs_arr_t              *arr;
+    njs_mod_t              *module;
+    njs_parser_t           parser;
+    njs_vm_code_t          *code;
+    njs_generator_t        generator;
+    njs_parser_scope_t     *scope;
+    njs_function_lambda_t  *lambda;
+
+    module = njs_module_find(vm, name, 1);
+    if (module != NULL) {
+        return module;
+    }
+
+    module = njs_module_add(vm, name);
+    if (njs_slow_path(module == NULL)) {
+        return NULL;
+    }
+
+    ret = njs_parser_init(vm, &parser, NULL, name, *start, end, 1);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NULL;
+    }
+
+    parser.module = 1;
+
+    ret = njs_parser(vm, &parser);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NULL;
+    }
+
+    *start = parser.lexer->start;
+
+    ret = njs_generator_init(&generator, &module->name, 0, 0);
+    if (njs_slow_path(ret != NJS_OK)) {
+        njs_internal_error(vm, "njs_generator_init() failed");
+        return NULL;
+    }
+
+    code = njs_generate_scope(vm, &generator, parser.scope, &njs_entry_module);
+    if (njs_slow_path(code == NULL)) {
+        njs_internal_error(vm, "njs_generate_scope() failed");
+
+        return NULL;
+    }
+
+    lambda = njs_mp_zalloc(vm->mem_pool, sizeof(njs_function_lambda_t));
+    if (njs_fast_path(lambda == NULL)) {
+        njs_memory_error(vm);
+        return NULL;
+    }
+
+    scope = parser.scope;
+
+    lambda->start = generator.code_start;
+    lambda->nlocal = scope->items;
+    lambda->temp = scope->temp;
+
+    arr = scope->declarations;
+    lambda->declarations = (arr != NULL) ? arr->start : NULL;
+    lambda->ndeclarations = (arr != NULL) ? arr->items : 0;
+
+    module->function.args_offset = 1;
+    module->function.u.lambda = lambda;
+
+    return module;
+}
+
+
 njs_vm_t *
 njs_vm_clone(njs_vm_t *vm, njs_external_ptr_t external)
 {
@@ -479,11 +550,6 @@ njs_vm_start(njs_vm_t *vm)
 {
     njs_int_t  ret;
 
-    ret = njs_module_load(vm);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return ret;
-    }
-
     ret = njs_vmcode_interpreter(vm, vm->start, NULL, NULL);
 
     return (ret == NJS_ERROR) ? NJS_ERROR : NJS_OK;
index b8f09b56490761d263c1c8bfdae575175f54a373..f49a3022b93250c60fcf9243e5aec1f7551947da 100644 (file)
@@ -229,6 +229,7 @@ struct njs_vm_shared_s {
     njs_lvlhsh_t             arguments_object_instance_hash;
     njs_lvlhsh_t             regexp_instance_hash;
 
+    size_t                   module_items;
     njs_lvlhsh_t             modules_hash;
 
     njs_lvlhsh_t             env_hash;
index 3039642cb9a3ee75fc878bd87980eecc5937c3c2..ef0beb5e0b19e62de3fdf92a51762e40becdff3b 100644 (file)
@@ -41,6 +41,8 @@ static njs_jump_off_t njs_vmcode_debugger(njs_vm_t *vm);
 
 static njs_jump_off_t njs_vmcode_return(njs_vm_t *vm, njs_value_t *invld,
     njs_value_t *retval);
+static njs_jump_off_t njs_vmcode_import(njs_vm_t *vm, njs_mod_t *module,
+    njs_value_t *retval);
 
 static njs_jump_off_t njs_vmcode_await(njs_vm_t *vm, njs_vmcode_await_t *await,
     njs_promise_capability_t *pcap, njs_async_ctx_t *actx);
@@ -97,6 +99,7 @@ njs_vmcode_interpreter(njs_vm_t *vm, u_char *pc, void *promise_cap,
     njs_vmcode_await_t           *await;
     njs_native_frame_t           *previous, *native;
     njs_property_next_t          *next;
+    njs_vmcode_import_t          *import;
     njs_vmcode_finally_t         *finally;
     njs_vmcode_generic_t         *vmcode;
     njs_vmcode_variable_t        *var;
@@ -826,6 +829,16 @@ next:
 
                 break;
 
+            case NJS_VMCODE_IMPORT:
+                import = (njs_vmcode_import_t *) pc;
+                retval = njs_scope_value(vm, import->retval);
+                ret = njs_vmcode_import(vm, import->module, retval);
+                if (njs_slow_path(ret == NJS_ERROR)) {
+                    goto error;
+                }
+
+                break;
+
             case NJS_VMCODE_AWAIT:
                 await = (njs_vmcode_await_t *) pc;
                 return njs_vmcode_await(vm, await, promise_cap, async_ctx);
@@ -1813,6 +1826,61 @@ njs_vmcode_return(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval)
 }
 
 
+static njs_jump_off_t
+njs_vmcode_import(njs_vm_t *vm, njs_mod_t *module, njs_value_t *retval)
+{
+    njs_int_t     ret;
+    njs_arr_t     *m;
+    njs_value_t   *value;
+    njs_object_t  *object;
+
+    if (vm->modules == NULL) {
+        vm->modules = njs_arr_create(vm->mem_pool, 4, sizeof(njs_value_t));
+        if (njs_slow_path(vm->modules == NULL)) {
+            njs_memory_error(vm);
+            return NJS_ERROR;
+        }
+
+        m = vm->modules;
+
+        value = njs_arr_add_multiple(m, vm->shared->module_items);
+        if (njs_slow_path(value == NULL)) {
+            njs_memory_error(vm);
+            return NJS_ERROR;
+        }
+
+        njs_memzero(m->start, m->items * sizeof(njs_value_t));
+    }
+
+    value = njs_arr_item(vm->modules, module->index);
+
+    if (!njs_is_null(value)) {
+        njs_value_assign(retval, value);
+        return sizeof(njs_vmcode_import_t);
+    }
+
+    if (module->function.native) {
+        njs_value_assign(value, &module->value);
+
+        object = njs_object_value_copy(vm, value);
+        if (njs_slow_path(object == NULL)) {
+            return NJS_ERROR;
+        }
+
+    } else {
+        njs_set_invalid(value);
+        ret = njs_vm_invoke(vm, &module->function, NULL, 0, value);
+        if (ret == NJS_ERROR) {
+            return ret;
+        }
+    }
+
+    njs_value_assign(retval, value);
+
+    return sizeof(njs_vmcode_import_t);
+}
+
+
 static njs_jump_off_t
 njs_vmcode_await(njs_vm_t *vm, njs_vmcode_await_t *await,
     njs_promise_capability_t *pcap, njs_async_ctx_t *ctx)
index 6b8f65582baab4d1eb9d52e730523c83eccdc2c1..3bf146ccaa5c399aed66eadf325c76bf32e98fa2 100644 (file)
@@ -49,6 +49,7 @@ enum {
     NJS_VMCODE_THIS,
     NJS_VMCODE_ARGUMENTS,
     NJS_VMCODE_PROTO_INIT,
+    NJS_VMCODE_IMPORT,
 
     NJS_VMCODE_AWAIT,
 
@@ -419,6 +420,13 @@ typedef struct {
 } njs_vmcode_function_copy_t;
 
 
+typedef struct {
+    njs_vmcode_t               code;
+    njs_index_t                retval;
+    njs_mod_t                  *module;
+} njs_vmcode_import_t;
+
+
 typedef struct {
     njs_vmcode_t               code;
     njs_index_t                dst;
diff --git a/test/js/import_cyclic.t.js b/test/js/import_cyclic.t.js
new file mode 100644 (file)
index 0000000..ef965d6
--- /dev/null
@@ -0,0 +1,11 @@
+/*---
+includes: []
+flags: []
+paths: [test/js/module/]
+---*/
+
+import a from 'cyclic_a.js';
+import b from 'cyclic_b.js';
+
+assert.sameValue(a, 10);
+assert.sameValue(b, 11);
index bf6fd5fbd3fe271b1dcf95011b2bcbd4c1eb819b..85e4eb2111b6c96d968745cd42b582db2d8ea5f7 100644 (file)
@@ -6,4 +6,5 @@ paths: [test/js/module]
 
 import m from 'export_expression.js';
 
+assert.sameValue(typeof m, 'object');
 assert.sameValue(m.sum(3,4), 7);
diff --git a/test/js/import_global_ref.t.js b/test/js/import_global_ref.t.js
new file mode 100644 (file)
index 0000000..c90288e
--- /dev/null
@@ -0,0 +1,13 @@
+/*---
+includes: []
+flags: []
+paths: [test/js/module/]
+---*/
+
+import http from 'http.js';
+import jwt  from 'jwt.js';
+
+globalThis.http = http;
+globalThis.jwt = jwt;
+
+assert.sameValue(http.check(), "JWT-OK");
diff --git a/test/js/import_global_ref_var.t.js b/test/js/import_global_ref_var.t.js
new file mode 100644 (file)
index 0000000..0aae6e0
--- /dev/null
@@ -0,0 +1,10 @@
+/*---
+includes: []
+flags: []
+paths: [test/js/module/]
+---*/
+
+var a = 42;
+import m from 'export_global_a.js';
+
+assert.sameValue(m.f(), 42);
diff --git a/test/js/import_order.t.js b/test/js/import_order.t.js
new file mode 100644 (file)
index 0000000..05de705
--- /dev/null
@@ -0,0 +1,18 @@
+/*---
+includes: [compareArray.js]
+flags: []
+paths: [test/js/module/]
+---*/
+
+if (!globalThis.stages) {
+    globalThis.stages = [];
+}
+
+globalThis.stages.push('main1');
+
+import _ from 'order.js';
+import __ from 'order2.js';
+
+globalThis.stages.push('main2');
+
+assert.compareArray(globalThis.stages, ["order", "order2", "main1", "main2"]);
index 976e23d3a691a8f10f6b7dc722ed211aab525532..e68ff01396d77a5d623d83af4c568ced8630104f 100644 (file)
@@ -2,8 +2,8 @@
 includes: []
 flags: []
 paths: [test/js/module/]
-negative:
-  phase: runtime
 ---*/
 
-import lib from 'import_recursive.t.js';
+import m from 'recursive.js';
+
+assert.sameValue(m, 42);
diff --git a/test/js/import_recursive_early_access.t.js b/test/js/import_recursive_early_access.t.js
new file mode 100644 (file)
index 0000000..a16f48f
--- /dev/null
@@ -0,0 +1,9 @@
+/*---
+includes: []
+flags: []
+paths: [test/js/module/]
+negative:
+  phase: runtime
+---*/
+
+import _ from 'recursive_early_access.js';
diff --git a/test/js/import_recursive_relative.t.js b/test/js/import_recursive_relative.t.js
new file mode 100644 (file)
index 0000000..2b7bc74
--- /dev/null
@@ -0,0 +1,9 @@
+/*---
+includes: []
+flags: []
+paths: [test/js/module/]
+---*/
+
+import m from './recursive_relative.js';
+
+assert.sameValue(m, 42);
diff --git a/test/js/import_sinking_export_default.t.js b/test/js/import_sinking_export_default.t.js
new file mode 100644 (file)
index 0000000..0aa2b99
--- /dev/null
@@ -0,0 +1,10 @@
+/*---
+includes: []
+flags: []
+paths: [test/js/module]
+---*/
+
+import m from 'sinking_export_default.js';
+
+assert.sameValue(typeof m, 'object');
+assert.sameValue(m.a, 42);
diff --git a/test/js/module/cyclic_a.js b/test/js/module/cyclic_a.js
new file mode 100644 (file)
index 0000000..c4ef312
--- /dev/null
@@ -0,0 +1,2 @@
+import _ from 'cyclic_b.js';
+export default 10;
diff --git a/test/js/module/cyclic_b.js b/test/js/module/cyclic_b.js
new file mode 100644 (file)
index 0000000..5a1bce0
--- /dev/null
@@ -0,0 +1,2 @@
+import _ from 'cyclic_a.js';
+export default 11;
diff --git a/test/js/module/export_global_a.js b/test/js/module/export_global_a.js
new file mode 100644 (file)
index 0000000..827c149
--- /dev/null
@@ -0,0 +1,5 @@
+function f() {
+    return a;
+}
+
+export default {f};
diff --git a/test/js/module/http.js b/test/js/module/http.js
new file mode 100644 (file)
index 0000000..5a677f1
--- /dev/null
@@ -0,0 +1,7 @@
+var http = {};
+
+http.check = function() {
+    return jwt.verify();
+}
+
+export default http;
diff --git a/test/js/module/jwt.js b/test/js/module/jwt.js
new file mode 100644 (file)
index 0000000..a5bfe3e
--- /dev/null
@@ -0,0 +1,7 @@
+var jwt = {};
+
+jwt.verify = function() {
+    return "JWT-OK";
+}
+
+export default jwt;
index 4b249b739cca6d232f7e1ea6774fd582a6b1212f..67dd2cf8f86bc114f6007284a6131ea7b35330b9 100644 (file)
@@ -8,4 +8,9 @@ function get() {
     return state.count;
 }
 
+if (globalThis.lib1_is_loaded) {
+    throw Error("lib1 already loaded");
+    globalThis.lib1_is_loaded = true;
+}
+
 export default {inc, get}
diff --git a/test/js/module/order.js b/test/js/module/order.js
new file mode 100644 (file)
index 0000000..ce5e53e
--- /dev/null
@@ -0,0 +1,7 @@
+if (!globalThis.stages) {
+    globalThis.stages = [];
+}
+
+globalThis.stages.push('order');
+
+export default 1;
diff --git a/test/js/module/order2.js b/test/js/module/order2.js
new file mode 100644 (file)
index 0000000..54c9575
--- /dev/null
@@ -0,0 +1,7 @@
+if (!globalThis.stages) {
+    globalThis.stages = [];
+}
+
+globalThis.stages.push('order2');
+
+export default 1;
diff --git a/test/js/module/recursive.js b/test/js/module/recursive.js
new file mode 100644 (file)
index 0000000..8e1131a
--- /dev/null
@@ -0,0 +1,2 @@
+import _ from 'recursive.js';
+export default 42;
diff --git a/test/js/module/recursive_early_access.js b/test/js/module/recursive_early_access.js
new file mode 100644 (file)
index 0000000..0bf09ba
--- /dev/null
@@ -0,0 +1,5 @@
+import m from 'recursive_early_access.js';
+
+m.a;
+
+export default 42;
diff --git a/test/js/module/recursive_relative.js b/test/js/module/recursive_relative.js
new file mode 100644 (file)
index 0000000..61a2ba4
--- /dev/null
@@ -0,0 +1,2 @@
+import _ from './recursive_relative.js';
+export default 42;
diff --git a/test/js/module/sinking_export_default.js b/test/js/module/sinking_export_default.js
new file mode 100644 (file)
index 0000000..9699ca2
--- /dev/null
@@ -0,0 +1,5 @@
+let o = {};
+
+export default o;
+
+o.a = 42;