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;
}
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;
}
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;
}
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,
};
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);
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);
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,
};
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);
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);
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;
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;
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,
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;
}
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,
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);
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;
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;
}
}
- 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;
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,
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__)
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;
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;
}
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;
}
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;
}
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;
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;
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;
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;
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);
}
njs_arr_t *index_cache;
njs_arr_t *closures;
+ njs_str_t file;
njs_arr_t *lines;
size_t code_size;
};
-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);
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;
}
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;
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;
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;
}
ssize_t n;
struct stat sb;
+ text->start = NULL;
+
if (fstat(fd, &sb) == -1) {
goto 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)
{
};
-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;
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));
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;
}
}
-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)
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;
+}
#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);
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,
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;
}
}
}
- 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;
}
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;
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;
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);
}
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;
}
{
njs_parser_node_t *node;
- if (!parser->scope->module) {
+ if (!parser->module) {
njs_parser_syntax_error(parser, "Illegal export statement");
return NJS_DONE;
}
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;
}
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);
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);
}
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;
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;
}
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);
}
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;
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;
njs_value_t value;
njs_vmcode_operation_t operation;
njs_parser_node_t *object;
+ njs_mod_t *module;
} u;
njs_str_t name;
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;
};
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);
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);
}
-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)
{
static njs_vm_ops_t njs_console_ops = {
njs_console_set_timer,
- njs_console_clear_timer
+ njs_console_clear_timer,
+ NULL,
};
int
main(int argc, char **argv)
{
- char path[MAXPATHLEN], *p;
njs_vm_t *vm;
njs_int_t ret;
njs_opts_t opts;
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;
return root;
}
- module = parser->vm->options.module || scope->module;
+ module = parser->vm->options.module || parser->module;
if (module) {
if (type == NJS_VARIABLE_FUNCTION
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);
*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;
}
+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)
{
{
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;
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;
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);
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;
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);
}
+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)
NJS_VMCODE_THIS,
NJS_VMCODE_ARGUMENTS,
NJS_VMCODE_PROTO_INIT,
+ NJS_VMCODE_IMPORT,
NJS_VMCODE_AWAIT,
} 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;
--- /dev/null
+/*---
+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);
import m from 'export_expression.js';
+assert.sameValue(typeof m, 'object');
assert.sameValue(m.sum(3,4), 7);
--- /dev/null
+/*---
+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");
--- /dev/null
+/*---
+includes: []
+flags: []
+paths: [test/js/module/]
+---*/
+
+var a = 42;
+import m from 'export_global_a.js';
+
+assert.sameValue(m.f(), 42);
--- /dev/null
+/*---
+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"]);
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);
--- /dev/null
+/*---
+includes: []
+flags: []
+paths: [test/js/module/]
+negative:
+ phase: runtime
+---*/
+
+import _ from 'recursive_early_access.js';
--- /dev/null
+/*---
+includes: []
+flags: []
+paths: [test/js/module/]
+---*/
+
+import m from './recursive_relative.js';
+
+assert.sameValue(m, 42);
--- /dev/null
+/*---
+includes: []
+flags: []
+paths: [test/js/module]
+---*/
+
+import m from 'sinking_export_default.js';
+
+assert.sameValue(typeof m, 'object');
+assert.sameValue(m.a, 42);
--- /dev/null
+import _ from 'cyclic_b.js';
+export default 10;
--- /dev/null
+import _ from 'cyclic_a.js';
+export default 11;
--- /dev/null
+function f() {
+ return a;
+}
+
+export default {f};
--- /dev/null
+var http = {};
+
+http.check = function() {
+ return jwt.verify();
+}
+
+export default http;
--- /dev/null
+var jwt = {};
+
+jwt.verify = function() {
+ return "JWT-OK";
+}
+
+export default jwt;
return state.count;
}
+if (globalThis.lib1_is_loaded) {
+ throw Error("lib1 already loaded");
+ globalThis.lib1_is_loaded = true;
+}
+
export default {inc, get}
--- /dev/null
+if (!globalThis.stages) {
+ globalThis.stages = [];
+}
+
+globalThis.stages.push('order');
+
+export default 1;
--- /dev/null
+if (!globalThis.stages) {
+ globalThis.stages = [];
+}
+
+globalThis.stages.push('order2');
+
+export default 1;
--- /dev/null
+import _ from 'recursive.js';
+export default 42;
--- /dev/null
+import m from 'recursive_early_access.js';
+
+m.a;
+
+export default 42;
--- /dev/null
+import _ from './recursive_relative.js';
+export default 42;
--- /dev/null
+let o = {};
+
+export default o;
+
+o.a = 42;