diff options
Diffstat (limited to 'quickjs.c')
-rw-r--r-- | quickjs.c | 549 |
1 files changed, 437 insertions, 112 deletions
@@ -280,7 +280,12 @@ struct JSRuntime { struct list_head job_list; /* list of JSJobEntry.link */ JSModuleNormalizeFunc *module_normalize_func; - JSModuleLoaderFunc *module_loader_func; + BOOL module_loader_has_attr; + union { + JSModuleLoaderFunc *module_loader_func; + JSModuleLoaderFunc2 *module_loader_func2; + } u; + JSModuleCheckSupportedImportAttributes *module_check_attrs; void *module_loader_opaque; /* timestamp for internal use in module evaluation */ int64_t module_async_evaluation_next_timestamp; @@ -756,6 +761,7 @@ typedef struct { typedef struct JSReqModuleEntry { JSAtom module_name; JSModuleDef *module; /* used using resolution */ + JSValue attributes; /* JS_UNDEFINED or an object contains the attributes as key/value */ } JSReqModuleEntry; typedef enum JSExportTypeEnum { @@ -844,6 +850,7 @@ struct JSModuleDef { BOOL eval_has_exception : 8; JSValue eval_exception; JSValue meta_obj; /* for import.meta */ + JSValue private_value; /* private value for C modules */ }; typedef struct JSJobEntry { @@ -1217,7 +1224,7 @@ static void js_free_module_def(JSContext *ctx, JSModuleDef *m); static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m, JS_MarkFunc *mark_func); static JSValue js_import_meta(JSContext *ctx); -static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier); +static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier, JSValueConst options); static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref); static JSValue js_new_promise_capability(JSContext *ctx, JSValue *resolving_funcs, @@ -3205,15 +3212,18 @@ static BOOL JS_AtomSymbolHasDescription(JSContext *ctx, JSAtom v) } /* free with JS_FreeCString() */ -const char *JS_AtomToCString(JSContext *ctx, JSAtom atom) +const char *JS_AtomToCStringLen(JSContext *ctx, size_t *plen, JSAtom atom) { JSValue str; const char *cstr; str = JS_AtomToString(ctx, atom); - if (JS_IsException(str)) + if (JS_IsException(str)) { + if (plen) + *plen = 0; return NULL; - cstr = JS_ToCString(ctx, str); + } + cstr = JS_ToCStringLen(ctx, plen, str); JS_FreeValue(ctx, str); return cstr; } @@ -7875,7 +7885,7 @@ static int num_keys_cmp(const void *p1, const void *p2, void *opaque) return 1; } -static void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len) +void JS_FreePropertyEnum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len) { uint32_t i; if (tab) { @@ -7969,7 +7979,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, /* set the "is_enumerable" field if necessary */ res = JS_GetOwnPropertyInternal(ctx, &desc, p, atom); if (res < 0) { - js_free_prop_enum(ctx, tab_exotic, exotic_count); + JS_FreePropertyEnum(ctx, tab_exotic, exotic_count); return -1; } if (res) { @@ -8000,7 +8010,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, if (atom_count < exotic_keys_count || atom_count > INT32_MAX) { add_overflow: JS_ThrowOutOfMemory(ctx); - js_free_prop_enum(ctx, tab_exotic, exotic_count); + JS_FreePropertyEnum(ctx, tab_exotic, exotic_count); return -1; } /* XXX: need generic way to test for js_malloc(ctx, a * b) overflow */ @@ -8008,7 +8018,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, /* avoid allocating 0 bytes */ tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1)); if (!tab_atom) { - js_free_prop_enum(ctx, tab_exotic, exotic_count); + JS_FreePropertyEnum(ctx, tab_exotic, exotic_count); return -1; } @@ -8053,7 +8063,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, for(i = 0; i < len; i++) { tab_atom[num_index].atom = __JS_AtomFromUInt32(i); if (tab_atom[num_index].atom == JS_ATOM_NULL) { - js_free_prop_enum(ctx, tab_atom, num_index); + JS_FreePropertyEnum(ctx, tab_atom, num_index); return -1; } tab_atom[num_index].is_enumerable = TRUE; @@ -12127,7 +12137,7 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp, case ATOD_TYPE_FLOAT64: { double d; - d = js_atod(buf,NULL, radix, is_float ? 0 : JS_ATOD_INT_ONLY, + d = js_atod(buf, NULL, radix, is_float ? 0 : JS_ATOD_INT_ONLY, &atod_mem); /* return int or float64 */ val = JS_NewFloat64(ctx, d); @@ -15553,7 +15563,7 @@ static __exception int js_for_in_prepare_prototype_chain_enum(JSContext *ctx, JS_FreeValue(ctx, obj1); goto fail; } - js_free_prop_enum(ctx, tab_atom, tab_atom_count); + JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count); if (tab_atom_count != 0) { JS_FreeValue(ctx, obj1); goto slow_path; @@ -15637,7 +15647,7 @@ static __exception int js_for_in_next(JSContext *ctx, JSValue *sp) JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) { return -1; } - js_free_prop_enum(ctx, it->tab_atom, it->atom_count); + JS_FreePropertyEnum(ctx, it->tab_atom, it->atom_count); it->tab_atom = tab_atom; it->atom_count = tab_atom_count; it->idx = 0; @@ -16160,10 +16170,10 @@ static __exception int JS_CopyDataProperties(JSContext *ctx, if (ret < 0) goto exception; } - js_free_prop_enum(ctx, tab_atom, tab_atom_count); + JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count); return 0; exception: - js_free_prop_enum(ctx, tab_atom, tab_atom_count); + JS_FreePropertyEnum(ctx, tab_atom, tab_atom_count); return -1; } @@ -17380,10 +17390,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, { JSValue val; sf->cur_pc = pc; - val = js_dynamic_import(ctx, sp[-1]); + val = js_dynamic_import(ctx, sp[-2], sp[-1]); if (JS_IsException(val)) goto exception; + JS_FreeValue(ctx, sp[-2]); JS_FreeValue(ctx, sp[-1]); + sp--; sp[-1] = val; } BREAK; @@ -21031,11 +21043,6 @@ static __exception int js_parse_string(JSParseState *s, int sep, goto invalid_char; c = *p; if (c < 0x20) { - if (!s->cur_func) { - if (do_throw) - js_parse_error_pos(s, p, "invalid character in a JSON string"); - goto fail; - } if (sep == '`') { if (c == '\r') { if (p[1] == '\n') @@ -21081,8 +21088,6 @@ static __exception int js_parse_string(JSParseState *s, int sep, continue; default: if (c >= '0' && c <= '9') { - if (!s->cur_func) - goto invalid_escape; /* JSON case */ if (!(s->cur_func->js_mode & JS_MODE_STRICT) && sep != '`') goto parse_escape; if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) { @@ -21851,6 +21856,150 @@ static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c) return atom; } +static int json_parse_string(JSParseState *s, const uint8_t **pp, int sep) +{ + const uint8_t *p, *p_next; + int i; + uint32_t c; + StringBuffer b_s, *b = &b_s; + + if (string_buffer_init(s->ctx, b, 32)) + goto fail; + + p = *pp; + for(;;) { + if (p >= s->buf_end) { + goto end_of_input; + } + c = *p++; + if (c == sep) + break; + if (c < 0x20) { + js_parse_error_pos(s, p - 1, "Bad control character in string literal"); + goto fail; + } + if (c == '\\') { + c = *p++; + switch(c) { + case 'b': c = '\b'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case '\\': break; + case '/': break; + case 'u': + c = 0; + for(i = 0; i < 4; i++) { + int h = from_hex(*p++); + if (h < 0) { + js_parse_error_pos(s, p - 1, "Bad Unicode escape"); + goto fail; + } + c = (c << 4) | h; + } + break; + default: + if (c == sep) + break; + if (p > s->buf_end) + goto end_of_input; + js_parse_error_pos(s, p - 1, "Bad escaped character"); + goto fail; + } + } else + if (c >= 0x80) { + c = unicode_from_utf8(p - 1, UTF8_CHAR_LEN_MAX, &p_next); + if (c > 0x10FFFF) { + js_parse_error_pos(s, p - 1, "Bad UTF-8 sequence"); + goto fail; + } + p = p_next; + } + if (string_buffer_putc(b, c)) + goto fail; + } + s->token.val = TOK_STRING; + s->token.u.str.sep = sep; + s->token.u.str.str = string_buffer_end(b); + *pp = p; + return 0; + + end_of_input: + js_parse_error(s, "Unexpected end of JSON input"); + fail: + string_buffer_free(b); + return -1; +} + +static int json_parse_number(JSParseState *s, const uint8_t **pp) +{ + const uint8_t *p = *pp; + const uint8_t *p_start = p; + int radix; + double d; + JSATODTempMem atod_mem; + + if (*p == '+' || *p == '-') + p++; + + if (!is_digit(*p)) + return js_parse_error_pos(s, p, "Unexpected token '%c'", *p_start); + + if (p[0] == '0') { + if (s->ext_json) { + /* also accepts base 16, 8 and 2 prefix for integers */ + radix = 10; + if (p[1] == 'x' || p[1] == 'X') { + p += 2; + radix = 16; + } else if ((p[1] == 'o' || p[1] == 'O')) { + p += 2; + radix = 8; + } else if ((p[1] == 'b' || p[1] == 'B')) { + p += 2; + radix = 2; + } + if (radix != 10) { + /* prefix is present */ + if (to_digit(*p) >= radix) + return js_parse_error_pos(s, p, "Unexpected token '%c'", *p); + d = js_atod((const char *)p_start, (const char **)&p, 0, + JS_ATOD_INT_ONLY | JS_ATOD_ACCEPT_BIN_OCT, &atod_mem); + goto done; + } + } + if (is_digit(p[1])) + return js_parse_error_pos(s, p, "Unexpected number"); + } + + while (is_digit(*p)) + p++; + + if (*p == '.') { + p++; + if (!is_digit(*p)) + return js_parse_error_pos(s, p, "Unterminated fractional number"); + while (is_digit(*p)) + p++; + } + if (*p == 'e' || *p == 'E') { + p++; + if (*p == '+' || *p == '-') + p++; + if (!is_digit(*p)) + return js_parse_error_pos(s, p, "Exponent part is missing a number"); + while (is_digit(*p)) + p++; + } + d = js_atod((const char *)p_start, NULL, 10, 0, &atod_mem); + done: + s->token.val = TOK_NUMBER; + s->token.u.num.val = JS_NewFloat64(s->ctx, d); + *pp = p; + return 0; +} + static __exception int json_next_token(JSParseState *s) { const uint8_t *p; @@ -21882,7 +22031,8 @@ static __exception int json_next_token(JSParseState *s) } /* fall through */ case '\"': - if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p)) + p++; + if (json_parse_string(s, &p, c)) goto fail; break; case '\r': /* accept DOS and MAC newline sequences */ @@ -21999,23 +22149,8 @@ static __exception int json_next_token(JSParseState *s) case '9': /* number */ parse_number: - { - JSValue ret; - int flags, radix; - if (!s->ext_json) { - flags = 0; - radix = 10; - } else { - flags = ATOD_ACCEPT_BIN_OCT; - radix = 0; - } - ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix, - flags); - if (JS_IsException(ret)) - goto fail; - s->token.val = TOK_NUMBER; - s->token.u.num.val = ret; - } + if (json_parse_number(s, &p)) + goto fail; break; default: if (c >= 128) { @@ -25412,6 +25547,23 @@ static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags) return js_parse_error(s, "invalid use of 'import()'"); if (js_parse_assign_expr(s)) return -1; + if (s->token.val == ',') { + if (next_token(s)) + return -1; + if (s->token.val != ')') { + if (js_parse_assign_expr(s)) + return -1; + /* accept a trailing comma */ + if (s->token.val == ',') { + if (next_token(s)) + return -1; + } + } else { + emit_op(s, OP_undefined); + } + } else { + emit_op(s, OP_undefined); + } if (js_parse_expect(s, ')')) return -1; emit_op(s, OP_import); @@ -27989,6 +28141,7 @@ static JSModuleDef *js_new_module_def(JSContext *ctx, JSAtom name) m->promise = JS_UNDEFINED; m->resolving_funcs[0] = JS_UNDEFINED; m->resolving_funcs[1] = JS_UNDEFINED; + m->private_value = JS_UNDEFINED; list_add_tail(&m->link, &ctx->loaded_modules); return m; } @@ -27998,6 +28151,11 @@ static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m, { int i; + for(i = 0; i < m->req_module_entries_count; i++) { + JSReqModuleEntry *rme = &m->req_module_entries[i]; + JS_MarkValue(rt, rme->attributes, mark_func); + } + for(i = 0; i < m->export_entries_count; i++) { JSExportEntry *me = &m->export_entries[i]; if (me->export_type == JS_EXPORT_TYPE_LOCAL && @@ -28013,6 +28171,7 @@ static void js_mark_module_def(JSRuntime *rt, JSModuleDef *m, JS_MarkValue(rt, m->promise, mark_func); JS_MarkValue(rt, m->resolving_funcs[0], mark_func); JS_MarkValue(rt, m->resolving_funcs[1], mark_func); + JS_MarkValue(rt, m->private_value, mark_func); } static void js_free_module_def(JSContext *ctx, JSModuleDef *m) @@ -28024,6 +28183,7 @@ static void js_free_module_def(JSContext *ctx, JSModuleDef *m) for(i = 0; i < m->req_module_entries_count; i++) { JSReqModuleEntry *rme = &m->req_module_entries[i]; JS_FreeAtom(ctx, rme->module_name); + JS_FreeValue(ctx, rme->attributes); } js_free(ctx, m->req_module_entries); @@ -28052,6 +28212,7 @@ static void js_free_module_def(JSContext *ctx, JSModuleDef *m) JS_FreeValue(ctx, m->promise); JS_FreeValue(ctx, m->resolving_funcs[0]); JS_FreeValue(ctx, m->resolving_funcs[1]); + JS_FreeValue(ctx, m->private_value); list_del(&m->link); js_free(ctx, m); } @@ -28060,14 +28221,6 @@ static int add_req_module_entry(JSContext *ctx, JSModuleDef *m, JSAtom module_name) { JSReqModuleEntry *rme; - int i; - - /* no need to add the module request if it is already present */ - for(i = 0; i < m->req_module_entries_count; i++) { - rme = &m->req_module_entries[i]; - if (rme->module_name == module_name) - return i; - } if (js_resize_array(ctx, (void **)&m->req_module_entries, sizeof(JSReqModuleEntry), @@ -28077,7 +28230,8 @@ static int add_req_module_entry(JSContext *ctx, JSModuleDef *m, rme = &m->req_module_entries[m->req_module_entries_count++]; rme->module_name = JS_DupAtom(ctx, module_name); rme->module = NULL; - return i; + rme->attributes = JS_UNDEFINED; + return m->req_module_entries_count - 1; } static JSExportEntry *find_export_entry(JSContext *ctx, JSModuleDef *m, @@ -28196,12 +28350,38 @@ int JS_SetModuleExport(JSContext *ctx, JSModuleDef *m, const char *export_name, return -1; } +int JS_SetModulePrivateValue(JSContext *ctx, JSModuleDef *m, JSValue val) +{ + set_value(ctx, &m->private_value, val); + return 0; +} + +JSValue JS_GetModulePrivateValue(JSContext *ctx, JSModuleDef *m) +{ + return JS_DupValue(ctx, m->private_value); +} + void JS_SetModuleLoaderFunc(JSRuntime *rt, JSModuleNormalizeFunc *module_normalize, JSModuleLoaderFunc *module_loader, void *opaque) { rt->module_normalize_func = module_normalize; - rt->module_loader_func = module_loader; + rt->module_loader_has_attr = FALSE; + rt->u.module_loader_func = module_loader; + rt->module_check_attrs = NULL; + rt->module_loader_opaque = opaque; +} + +void JS_SetModuleLoaderFunc2(JSRuntime *rt, + JSModuleNormalizeFunc *module_normalize, + JSModuleLoaderFunc2 *module_loader, + JSModuleCheckSupportedImportAttributes *module_check_attrs, + void *opaque) +{ + rt->module_normalize_func = module_normalize; + rt->module_loader_has_attr = TRUE; + rt->u.module_loader_func2 = module_loader; + rt->module_check_attrs = module_check_attrs; rt->module_loader_opaque = opaque; } @@ -28282,7 +28462,8 @@ static JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name) /* return NULL in case of exception (e.g. module could not be loaded) */ static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx, const char *base_cname, - const char *cname1) + const char *cname1, + JSValueConst attributes) { JSRuntime *rt = ctx->rt; JSModuleDef *m; @@ -28315,22 +28496,26 @@ static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx, JS_FreeAtom(ctx, module_name); /* load the module */ - if (!rt->module_loader_func) { + if (!rt->u.module_loader_func) { /* XXX: use a syntax error ? */ JS_ThrowReferenceError(ctx, "could not load module '%s'", cname); js_free(ctx, cname); return NULL; } - - m = rt->module_loader_func(ctx, cname, rt->module_loader_opaque); + if (rt->module_loader_has_attr) { + m = rt->u.module_loader_func2(ctx, cname, rt->module_loader_opaque, attributes); + } else { + m = rt->u.module_loader_func(ctx, cname, rt->module_loader_opaque); + } js_free(ctx, cname); return m; } static JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx, - JSAtom base_module_name, - JSAtom module_name1) + JSAtom base_module_name, + JSAtom module_name1, + JSValueConst attributes) { const char *base_cname, *cname; JSModuleDef *m; @@ -28343,7 +28528,7 @@ static JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx, JS_FreeCString(ctx, base_cname); return NULL; } - m = js_host_resolve_imported_module(ctx, base_cname, cname); + m = js_host_resolve_imported_module(ctx, base_cname, cname, attributes); JS_FreeCString(ctx, base_cname); JS_FreeCString(ctx, cname); return m; @@ -28805,7 +28990,8 @@ static int js_resolve_module(JSContext *ctx, JSModuleDef *m) for(i = 0; i < m->req_module_entries_count; i++) { JSReqModuleEntry *rme = &m->req_module_entries[i]; m1 = js_host_resolve_imported_module_atom(ctx, m->module_name, - rme->module_name); + rme->module_name, + rme->attributes); if (!m1) return -1; rme->module = m1; @@ -29282,14 +29468,15 @@ static JSValue js_load_module_fulfilled(JSContext *ctx, JSValueConst this_val, static void JS_LoadModuleInternal(JSContext *ctx, const char *basename, const char *filename, - JSValueConst *resolving_funcs) + JSValueConst *resolving_funcs, + JSValueConst attributes) { JSValue evaluate_promise; JSModuleDef *m; JSValue ret, err, func_obj, evaluate_resolving_funcs[2]; JSValueConst func_data[3]; - m = js_host_resolve_imported_module(ctx, basename, filename); + m = js_host_resolve_imported_module(ctx, basename, filename, attributes); if (!m) goto fail; @@ -29336,7 +29523,7 @@ JSValue JS_LoadModule(JSContext *ctx, const char *basename, if (JS_IsException(promise)) return JS_EXCEPTION; JS_LoadModuleInternal(ctx, basename, filename, - (JSValueConst *)resolving_funcs); + (JSValueConst *)resolving_funcs, JS_UNDEFINED); JS_FreeValue(ctx, resolving_funcs[0]); JS_FreeValue(ctx, resolving_funcs[1]); return promise; @@ -29348,6 +29535,7 @@ static JSValue js_dynamic_import_job(JSContext *ctx, JSValueConst *resolving_funcs = argv; JSValueConst basename_val = argv[2]; JSValueConst specifier = argv[3]; + JSValueConst attributes = argv[4]; const char *basename = NULL, *filename; JSValue ret, err; @@ -29364,7 +29552,7 @@ static JSValue js_dynamic_import_job(JSContext *ctx, goto exception; JS_LoadModuleInternal(ctx, basename, filename, - resolving_funcs); + resolving_funcs, attributes); JS_FreeCString(ctx, filename); JS_FreeCString(ctx, basename); return JS_UNDEFINED; @@ -29378,11 +29566,12 @@ static JSValue js_dynamic_import_job(JSContext *ctx, return JS_UNDEFINED; } -static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier) +static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier, JSValueConst options) { JSAtom basename; - JSValue promise, resolving_funcs[2], basename_val; - JSValueConst args[4]; + JSValue promise, resolving_funcs[2], basename_val, err, ret; + JSValue specifier_str = JS_UNDEFINED, attributes = JS_UNDEFINED, attributes_obj = JS_UNDEFINED; + JSValueConst args[5]; basename = JS_GetScriptOrModuleName(ctx, 0); if (basename == JS_ATOM_NULL) @@ -29399,19 +29588,82 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier) return promise; } + /* the string conversion must occur here */ + specifier_str = JS_ToString(ctx, specifier); + if (JS_IsException(specifier_str)) + goto exception; + + if (!JS_IsUndefined(options)) { + if (!JS_IsObject(options)) { + JS_ThrowTypeError(ctx, "options must be an object"); + goto exception; + } + attributes_obj = JS_GetProperty(ctx, options, JS_ATOM_with); + if (JS_IsException(attributes_obj)) + goto exception; + if (!JS_IsUndefined(attributes_obj)) { + JSPropertyEnum *atoms; + uint32_t atoms_len, i; + JSValue val; + + if (!JS_IsObject(attributes_obj)) { + JS_ThrowTypeError(ctx, "options.with must be an object"); + goto exception; + } + attributes = JS_NewObjectProto(ctx, JS_NULL); + if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &atoms_len, JS_VALUE_GET_OBJ(attributes_obj), + JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) { + goto exception; + } + for(i = 0; i < atoms_len; i++) { + val = JS_GetProperty(ctx, attributes_obj, atoms[i].atom); + if (JS_IsException(val)) + goto exception1; + if (!JS_IsString(val)) { + JS_FreeValue(ctx, val); + JS_ThrowTypeError(ctx, "module attribute values must be strings"); + goto exception1; + } + if (JS_DefinePropertyValue(ctx, attributes, atoms[i].atom, val, + JS_PROP_C_W_E) < 0) { + exception1: + JS_FreePropertyEnum(ctx, atoms, atoms_len); + goto exception; + } + } + JS_FreePropertyEnum(ctx, atoms, atoms_len); + if (ctx->rt->module_check_attrs && + ctx->rt->module_check_attrs(ctx, ctx->rt->module_loader_opaque, attributes) < 0) { + goto exception; + } + JS_FreeValue(ctx, attributes_obj); + } + } + args[0] = resolving_funcs[0]; args[1] = resolving_funcs[1]; args[2] = basename_val; - args[3] = specifier; - + args[3] = specifier_str; + args[4] = attributes; + /* cannot run JS_LoadModuleInternal synchronously because it would cause an unexpected recursion in js_evaluate_module() */ - JS_EnqueueJob(ctx, js_dynamic_import_job, 4, args); - + JS_EnqueueJob(ctx, js_dynamic_import_job, 5, args); + done: JS_FreeValue(ctx, basename_val); JS_FreeValue(ctx, resolving_funcs[0]); JS_FreeValue(ctx, resolving_funcs[1]); + JS_FreeValue(ctx, specifier_str); + JS_FreeValue(ctx, attributes); return promise; + exception: + JS_FreeValue(ctx, attributes_obj); + err = JS_GetException(ctx); + ret = JS_Call(ctx, resolving_funcs[1], JS_UNDEFINED, + 1, (JSValueConst *)&err); + JS_FreeValue(ctx, ret); + JS_FreeValue(ctx, err); + goto done; } static void js_set_module_evaluated(JSContext *ctx, JSModuleDef *m) @@ -29807,27 +30059,109 @@ static JSValue js_evaluate_module(JSContext *ctx, JSModuleDef *m) return JS_DupValue(ctx, m->promise); } -static __exception JSAtom js_parse_from_clause(JSParseState *s) +static __exception int js_parse_with_clause(JSParseState *s, JSReqModuleEntry *rme) +{ + JSContext *ctx = s->ctx; + JSAtom key; + int ret; + const uint8_t *key_token_ptr; + + if (next_token(s)) + return -1; + if (js_parse_expect(s, '{')) + return -1; + while (s->token.val != '}') { + key_token_ptr = s->token.ptr; + if (s->token.val == TOK_STRING) { + key = JS_ValueToAtom(ctx, s->token.u.str.str); + if (key == JS_ATOM_NULL) + return -1; + } else { + if (!token_is_ident(s->token.val)) { + js_parse_error(s, "identifier expected"); + return -1; + } + key = JS_DupAtom(ctx, s->token.u.ident.atom); + } + if (next_token(s)) + return -1; + if (js_parse_expect(s, ':')) { + JS_FreeAtom(ctx, key); + return -1; + } + if (s->token.val != TOK_STRING) { + js_parse_error_pos(s, key_token_ptr, "string expected"); + return -1; + } + if (JS_IsUndefined(rme->attributes)) { + JSValue attributes = JS_NewObjectProto(ctx, JS_NULL); + if (JS_IsException(attributes)) { + JS_FreeAtom(ctx, key); + return -1; + } + rme->attributes = attributes; + } + ret = JS_HasProperty(ctx, rme->attributes, key); + if (ret != 0) { + JS_FreeAtom(ctx, key); + if (ret < 0) + return -1; + else + return js_parse_error(s, "duplicate with key"); + } + ret = JS_DefinePropertyValue(ctx, rme->attributes, key, + JS_DupValue(ctx, s->token.u.str.str), JS_PROP_C_W_E); + JS_FreeAtom(ctx, key); + if (ret < 0) + return -1; + if (next_token(s)) + return -1; + if (s->token.val != ',') + break; + if (next_token(s)) + return -1; + } + if (!JS_IsUndefined(rme->attributes) && + ctx->rt->module_check_attrs && + ctx->rt->module_check_attrs(ctx, ctx->rt->module_loader_opaque, rme->attributes) < 0) { + return -1; + } + return js_parse_expect(s, '}'); +} + +/* return the module index in m->req_module_entries[] or < 0 if error */ +static __exception int js_parse_from_clause(JSParseState *s, JSModuleDef *m) { JSAtom module_name; + int idx; + if (!token_is_pseudo_keyword(s, JS_ATOM_from)) { js_parse_error(s, "from clause expected"); - return JS_ATOM_NULL; + return -1; } if (next_token(s)) - return JS_ATOM_NULL; + return -1; if (s->token.val != TOK_STRING) { js_parse_error(s, "string expected"); - return JS_ATOM_NULL; + return -1; } module_name = JS_ValueToAtom(s->ctx, s->token.u.str.str); if (module_name == JS_ATOM_NULL) - return JS_ATOM_NULL; + return -1; if (next_token(s)) { JS_FreeAtom(s->ctx, module_name); - return JS_ATOM_NULL; + return -1; + } + + idx = add_req_module_entry(s->ctx, m, module_name); + JS_FreeAtom(s->ctx, module_name); + if (idx < 0) + return -1; + if (s->token.val == TOK_WITH) { + if (js_parse_with_clause(s, &m->req_module_entries[idx])) + return -1; } - return module_name; + return idx; } static __exception int js_parse_export(JSParseState *s) @@ -29836,7 +30170,6 @@ static __exception int js_parse_export(JSParseState *s) JSModuleDef *m = s->cur_func->module; JSAtom local_name, export_name; int first_export, idx, i, tok; - JSAtom module_name; JSExportEntry *me; if (next_token(s)) @@ -29911,11 +30244,7 @@ static __exception int js_parse_export(JSParseState *s) if (js_parse_expect(s, '}')) return -1; if (token_is_pseudo_keyword(s, JS_ATOM_from)) { - module_name = js_parse_from_clause(s); - if (module_name == JS_ATOM_NULL) - return -1; - idx = add_req_module_entry(ctx, m, module_name); - JS_FreeAtom(ctx, module_name); + idx = js_parse_from_clause(s, m); if (idx < 0) return -1; for(i = first_export; i < m->export_entries_count; i++) { @@ -29937,11 +30266,7 @@ static __exception int js_parse_export(JSParseState *s) export_name = JS_DupAtom(ctx, s->token.u.ident.atom); if (next_token(s)) goto fail1; - module_name = js_parse_from_clause(s); - if (module_name == JS_ATOM_NULL) - goto fail1; - idx = add_req_module_entry(ctx, m, module_name); - JS_FreeAtom(ctx, module_name); + idx = js_parse_from_clause(s, m); if (idx < 0) goto fail1; me = add_export_entry(s, m, JS_ATOM__star_, export_name, @@ -29951,11 +30276,7 @@ static __exception int js_parse_export(JSParseState *s) return -1; me->u.req_module_idx = idx; } else { - module_name = js_parse_from_clause(s); - if (module_name == JS_ATOM_NULL) - return -1; - idx = add_req_module_entry(ctx, m, module_name); - JS_FreeAtom(ctx, module_name); + idx = js_parse_from_clause(s, m); if (idx < 0) return -1; if (add_star_export_entry(ctx, m, idx) < 0) @@ -30061,6 +30382,14 @@ static __exception int js_parse_import(JSParseState *s) JS_FreeAtom(ctx, module_name); return -1; } + idx = add_req_module_entry(ctx, m, module_name); + JS_FreeAtom(ctx, module_name); + if (idx < 0) + return -1; + if (s->token.val == TOK_WITH) { + if (js_parse_with_clause(s, &m->req_module_entries[idx])) + return -1; + } } else { if (s->token.val == TOK_IDENT) { if (s->token.u.ident.is_reserved) { @@ -30159,14 +30488,10 @@ static __exception int js_parse_import(JSParseState *s) return -1; } end_import_clause: - module_name = js_parse_from_clause(s); - if (module_name == JS_ATOM_NULL) + idx = js_parse_from_clause(s, m); + if (idx < 0) return -1; } - idx = add_req_module_entry(ctx, m, module_name); - JS_FreeAtom(ctx, module_name); - if (idx < 0) - return -1; for(i = first_import; i < m->import_entries_count; i++) m->import_entries[i].req_module_idx = idx; @@ -37970,7 +38295,7 @@ static __exception int JS_ObjectDefineProperties(JSContext *ctx, ret = 0; exception: - js_free_prop_enum(ctx, atoms, len); + JS_FreePropertyEnum(ctx, atoms, len); JS_FreeValue(ctx, props); JS_FreeValue(ctx, desc); return ret; @@ -38241,12 +38566,12 @@ static JSValue js_object_getOwnPropertyDescriptors(JSContext *ctx, JSValueConst goto exception; } } - js_free_prop_enum(ctx, props, len); + JS_FreePropertyEnum(ctx, props, len); JS_FreeValue(ctx, obj); return r; exception: - js_free_prop_enum(ctx, props, len); + JS_FreePropertyEnum(ctx, props, len); JS_FreeValue(ctx, obj); JS_FreeValue(ctx, r); return JS_EXCEPTION; @@ -38326,7 +38651,7 @@ exception: JS_FreeValue(ctx, r); r = JS_EXCEPTION; done: - js_free_prop_enum(ctx, atoms, len); + JS_FreePropertyEnum(ctx, atoms, len); JS_FreeValue(ctx, obj); return r; } @@ -38587,11 +38912,11 @@ static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val, JS_UNDEFINED, JS_UNDEFINED, desc_flags) < 0) goto exception; } - js_free_prop_enum(ctx, props, len); + JS_FreePropertyEnum(ctx, props, len); return JS_DupValue(ctx, obj); exception: - js_free_prop_enum(ctx, props, len); + JS_FreePropertyEnum(ctx, props, len); return JS_EXCEPTION; } @@ -38633,11 +38958,11 @@ static JSValue js_object_isSealed(JSContext *ctx, JSValueConst this_val, return JS_EXCEPTION; res ^= 1; done: - js_free_prop_enum(ctx, props, len); + JS_FreePropertyEnum(ctx, props, len); return JS_NewBool(ctx, res); exception: - js_free_prop_enum(ctx, props, len); + JS_FreePropertyEnum(ctx, props, len); return JS_EXCEPTION; } @@ -45966,7 +46291,7 @@ static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder, goto fail; } } - js_free_prop_enum(ctx, atoms, len); + JS_FreePropertyEnum(ctx, atoms, len); atoms = NULL; name_val = JS_AtomToValue(ctx, name); if (JS_IsException(name_val)) @@ -45978,7 +46303,7 @@ static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder, JS_FreeValue(ctx, val); return res; fail: - js_free_prop_enum(ctx, atoms, len); + JS_FreePropertyEnum(ctx, atoms, len); JS_FreeValue(ctx, val); return JS_EXCEPTION; } @@ -47352,14 +47677,14 @@ static int js_proxy_get_own_property_names(JSContext *ctx, } } - js_free_prop_enum(ctx, tab2, len2); + JS_FreePropertyEnum(ctx, tab2, len2); JS_FreeValue(ctx, prop_array); *ptab = tab; *plen = len; return 0; fail: - js_free_prop_enum(ctx, tab2, len2); - js_free_prop_enum(ctx, tab, len); + JS_FreePropertyEnum(ctx, tab2, len2); + JS_FreePropertyEnum(ctx, tab, len); JS_FreeValue(ctx, prop_array); return -1; } |