Skip to content

Commit f10ef29

Browse files
author
Fabrice Bellard
committed
added JSON modules and import attributes
1 parent 8381245 commit f10ef29

File tree

10 files changed

+424
-100
lines changed

10 files changed

+424
-100
lines changed

TODO

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,5 @@ Optimization ideas:
6262
Test262o: 0/11262 errors, 463 excluded
6363
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
6464

65-
Result: 58/79202 errors, 1610 excluded, 6738 skipped
65+
Result: 58/79349 errors, 1610 excluded, 6649 skipped
6666
Test262 commit: 27622d764767dcb3778784884022c2c7de5769b8

qjs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ int main(int argc, char **argv)
465465
}
466466

467467
/* loader for ES6 modules */
468-
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
468+
JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);
469469

470470
if (dump_unhandled_promise_rejection) {
471471
JS_SetHostPromiseRejectionTracker(rt, js_std_promise_rejection_tracker,

qjsc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,7 @@ int main(int argc, char **argv)
788788

789789
/* add the module loader if necessary */
790790
if (feature_bitmap & (1 << FE_MODULE_LOADER)) {
791-
fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n");
791+
fprintf(fo, " JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);\n");
792792
}
793793

794794
fprintf(fo,

quickjs-libc.c

Lines changed: 97 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -591,8 +591,72 @@ int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
591591
return 0;
592592
}
593593

594+
static int json_module_init(JSContext *ctx, JSModuleDef *m)
595+
{
596+
JSValue val;
597+
val = JS_GetModulePrivateValue(ctx, m);
598+
JS_SetModuleExport(ctx, m, "default", val);
599+
return 0;
600+
}
601+
602+
/* in order to conform with the specification, only the keys should be
603+
tested and not the associated values. */
604+
int js_module_check_attributes(JSContext *ctx, void *opaque,
605+
JSValueConst attributes)
606+
{
607+
JSPropertyEnum *tab;
608+
uint32_t i, len;
609+
int ret;
610+
const char *cstr;
611+
size_t cstr_len;
612+
613+
if (JS_GetOwnPropertyNames(ctx, &tab, &len, attributes, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK))
614+
return -1;
615+
ret = 0;
616+
for(i = 0; i < len; i++) {
617+
cstr = JS_AtomToCStringLen(ctx, &cstr_len, tab[i].atom);
618+
if (!cstr) {
619+
ret = -1;
620+
break;
621+
}
622+
if (!(cstr_len == 4 && !memcmp(cstr, "type", cstr_len))) {
623+
JS_ThrowTypeError(ctx, "import attribute '%s' is not supported", cstr);
624+
ret = -1;
625+
}
626+
JS_FreeCString(ctx, cstr);
627+
if (ret)
628+
break;
629+
}
630+
JS_FreePropertyEnum(ctx, tab, len);
631+
return ret;
632+
}
633+
634+
/* return TRUE if the attributes indicate a JSON module */
635+
JS_BOOL js_module_test_json(JSContext *ctx, JSValueConst attributes)
636+
{
637+
JSValue str;
638+
const char *cstr;
639+
size_t len;
640+
BOOL res;
641+
642+
if (JS_IsUndefined(attributes))
643+
return FALSE;
644+
str = JS_GetPropertyStr(ctx, attributes, "type");
645+
if (!JS_IsString(str))
646+
return FALSE;
647+
cstr = JS_ToCStringLen(ctx, &len, str);
648+
JS_FreeValue(ctx, str);
649+
if (!cstr)
650+
return FALSE;
651+
/* XXX: raise an error if unknown type ? */
652+
res = (len == 4 && !memcmp(cstr, "json", len));
653+
JS_FreeCString(ctx, cstr);
654+
return res;
655+
}
656+
594657
JSModuleDef *js_module_loader(JSContext *ctx,
595-
const char *module_name, void *opaque)
658+
const char *module_name, void *opaque,
659+
JSValueConst attributes)
596660
{
597661
JSModuleDef *m;
598662

@@ -601,26 +665,44 @@ JSModuleDef *js_module_loader(JSContext *ctx,
601665
} else {
602666
size_t buf_len;
603667
uint8_t *buf;
604-
JSValue func_val;
605668

606669
buf = js_load_file(ctx, &buf_len, module_name);
607670
if (!buf) {
608671
JS_ThrowReferenceError(ctx, "could not load module filename '%s'",
609672
module_name);
610673
return NULL;
611674
}
612-
613-
/* compile the module */
614-
func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
615-
JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
616-
js_free(ctx, buf);
617-
if (JS_IsException(func_val))
618-
return NULL;
619-
/* XXX: could propagate the exception */
620-
js_module_set_import_meta(ctx, func_val, TRUE, FALSE);
621-
/* the module is already referenced, so we must free it */
622-
m = JS_VALUE_GET_PTR(func_val);
623-
JS_FreeValue(ctx, func_val);
675+
676+
if (has_suffix(module_name, ".json") ||
677+
js_module_test_json(ctx, attributes)) {
678+
/* compile as JSON */
679+
JSValue val;
680+
val = JS_ParseJSON(ctx, (char *)buf, buf_len, module_name);
681+
js_free(ctx, buf);
682+
if (JS_IsException(val))
683+
return NULL;
684+
m = JS_NewCModule(ctx, module_name, json_module_init);
685+
if (!m) {
686+
JS_FreeValue(ctx, val);
687+
return NULL;
688+
}
689+
/* only export the "default" symbol which will contain the JSON object */
690+
JS_AddModuleExport(ctx, m, "default");
691+
JS_SetModulePrivateValue(ctx, m, val);
692+
} else {
693+
JSValue func_val;
694+
/* compile the module */
695+
func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
696+
JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
697+
js_free(ctx, buf);
698+
if (JS_IsException(func_val))
699+
return NULL;
700+
/* XXX: could propagate the exception */
701+
js_module_set_import_meta(ctx, func_val, TRUE, FALSE);
702+
/* the module is already referenced, so we must free it */
703+
m = JS_VALUE_GET_PTR(func_val);
704+
JS_FreeValue(ctx, func_val);
705+
}
624706
}
625707
return m;
626708
}
@@ -3478,7 +3560,7 @@ static void *worker_func(void *opaque)
34783560
JS_SetStripInfo(rt, args->strip_flags);
34793561
js_std_init_handlers(rt);
34803562

3481-
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
3563+
JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);
34823564

34833565
/* set the pipe to communicate with the parent */
34843566
ts = JS_GetRuntimeOpaque(rt);

quickjs-libc.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,11 @@ void js_std_dump_error(JSContext *ctx);
4444
uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename);
4545
int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
4646
JS_BOOL use_realpath, JS_BOOL is_main);
47+
JS_BOOL js_module_test_json(JSContext *ctx, JSValueConst attributes);
48+
int js_module_check_attributes(JSContext *ctx, void *opaque, JSValueConst attributes);
4749
JSModuleDef *js_module_loader(JSContext *ctx,
48-
const char *module_name, void *opaque);
50+
const char *module_name, void *opaque,
51+
JSValueConst attributes);
4952
void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
5053
int flags);
5154
void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,

quickjs-opcode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ DEF( apply_eval, 3, 2, 1, u16) /* func array -> ret_eval */
121121
DEF( regexp, 1, 2, 1, none) /* create a RegExp object from the pattern and a
122122
bytecode string */
123123
DEF( get_super, 1, 1, 1, none)
124-
DEF( import, 1, 1, 1, none) /* dynamic module import */
124+
DEF( import, 1, 2, 1, none) /* dynamic module import */
125125

126126
DEF( check_var, 5, 0, 1, atom) /* check if a variable exists */
127127
DEF( get_var_undef, 5, 0, 1, atom) /* push undefined if the variable does not exist */

0 commit comments

Comments
 (0)