diff --git a/api-test.c b/api-test.c index 8cbf8fac5..ebdb2a77c 100644 --- a/api-test.c +++ b/api-test.c @@ -7,6 +7,60 @@ #include "quickjs.h" #include "cutils.h" +static JSValue eval(JSContext *ctx, const char *code) +{ + return JS_Eval(ctx, code, strlen(code), "", JS_EVAL_TYPE_GLOBAL); +} + +static void cfunctions(void) +{ + uint32_t length; + const char *s; + JSValue ret; + + JSRuntime *rt = JS_NewRuntime(); + JSContext *ctx = JS_NewContext(rt); + JSValue cfunc = JS_NewCFunction(ctx, NULL, "cfunc", 42); + JSValue cfuncdata = + JS_NewCFunctionData2(ctx, NULL, "cfuncdata", /*length*/1337, /*magic*/0, + /*data_len*/0, NULL); + JSValue global = JS_GetGlobalObject(ctx); + JS_SetPropertyStr(ctx, global, "cfunc", cfunc); + JS_SetPropertyStr(ctx, global, "cfuncdata", cfuncdata); + JS_FreeValue(ctx, global); + + ret = eval(ctx, "cfunc.name"); + assert(!JS_IsException(ret)); + assert(JS_IsString(ret)); + s = JS_ToCString(ctx, ret); + JS_FreeValue(ctx, ret); + assert(s); + assert(!strcmp(s, "cfunc")); + JS_FreeCString(ctx, s); + ret = eval(ctx, "cfunc.length"); + assert(!JS_IsException(ret)); + assert(JS_IsNumber(ret)); + assert(0 == JS_ToUint32(ctx, &length, ret)); + assert(length == 42); + + ret = eval(ctx, "cfuncdata.name"); + assert(!JS_IsException(ret)); + assert(JS_IsString(ret)); + s = JS_ToCString(ctx, ret); + JS_FreeValue(ctx, ret); + assert(s); + assert(!strcmp(s, "cfuncdata")); + JS_FreeCString(ctx, s); + ret = eval(ctx, "cfuncdata.length"); + assert(!JS_IsException(ret)); + assert(JS_IsNumber(ret)); + assert(0 == JS_ToUint32(ctx, &length, ret)); + assert(length == 1337); + + JS_FreeContext(ctx); + JS_FreeRuntime(rt); +} + #define MAX_TIME 10 static int timeout_interrupt_handler(JSRuntime *rt, void *opaque) @@ -30,7 +84,7 @@ static void sync_call(void) JSContext *ctx = JS_NewContext(rt); int time = 0; JS_SetInterruptHandler(rt, timeout_interrupt_handler, &time); - JSValue ret = JS_Eval(ctx, code, strlen(code), "", JS_EVAL_TYPE_GLOBAL); + JSValue ret = eval(ctx, code); assert(time > MAX_TIME); assert(JS_IsException(ret)); JS_FreeValue(ctx, ret); @@ -57,7 +111,7 @@ static void async_call(void) JSContext *ctx = JS_NewContext(rt); int time = 0; JS_SetInterruptHandler(rt, timeout_interrupt_handler, &time); - JSValue ret = JS_Eval(ctx, code, strlen(code), "", JS_EVAL_TYPE_GLOBAL); + JSValue ret = eval(ctx, code); assert(!JS_IsException(ret)); JS_FreeValue(ctx, ret); assert(JS_IsJobPending(rt)); @@ -104,7 +158,7 @@ static void async_call_stack_overflow(void) JSValue global = JS_GetGlobalObject(ctx); JS_SetPropertyStr(ctx, global, "save_value", JS_NewCFunction(ctx, save_value, "save_value", 1)); JS_FreeValue(ctx, global); - JSValue ret = JS_Eval(ctx, code, strlen(code), "", JS_EVAL_TYPE_GLOBAL); + JSValue ret = eval(ctx, code); assert(!JS_IsException(ret)); JS_FreeValue(ctx, ret); assert(JS_IsJobPending(rt)); @@ -127,20 +181,17 @@ static void raw_context_global_var(void) JSContext *ctx = JS_NewContextRaw(rt); JS_AddIntrinsicEval(ctx); { - static const char code[] = "globalThis"; - JSValue ret = JS_Eval(ctx, code, strlen(code), "*", JS_EVAL_TYPE_GLOBAL); + JSValue ret = eval(ctx, "globalThis"); assert(JS_IsException(ret)); JS_FreeValue(ctx, ret); } { - static const char code[] = "var x = 42"; - JSValue ret = JS_Eval(ctx, code, strlen(code), "*", JS_EVAL_TYPE_GLOBAL); + JSValue ret = eval(ctx, "var x = 42"); assert(JS_IsUndefined(ret)); JS_FreeValue(ctx, ret); } { - static const char code[] = "function f() {}"; - JSValue ret = JS_Eval(ctx, code, strlen(code), "*", JS_EVAL_TYPE_GLOBAL); + JSValue ret = eval(ctx, "function f() {}"); assert(JS_IsUndefined(ret)); JS_FreeValue(ctx, ret); } @@ -153,15 +204,13 @@ static void is_array(void) JSRuntime *rt = JS_NewRuntime(); JSContext *ctx = JS_NewContext(rt); { - static const char code[] = "[]"; - JSValue ret = JS_Eval(ctx, code, strlen(code), "*", JS_EVAL_TYPE_GLOBAL); + JSValue ret = eval(ctx, "[]"); assert(!JS_IsException(ret)); assert(JS_IsArray(ret)); JS_FreeValue(ctx, ret); } { - static const char code[] = "new Proxy([], {})"; - JSValue ret = JS_Eval(ctx, code, strlen(code), "*", JS_EVAL_TYPE_GLOBAL); + JSValue ret = eval(ctx, "new Proxy([], {})"); assert(!JS_IsException(ret)); assert(!JS_IsArray(ret)); assert(JS_IsProxy(ret)); @@ -285,17 +334,17 @@ function addItem() { \ JSRuntime *rt = JS_NewRuntime(); JSContext *ctx = JS_NewContext(rt); - JSValue ret = JS_Eval(ctx, init_code, strlen(init_code), "", JS_EVAL_TYPE_GLOBAL); + JSValue ret = eval(ctx, init_code); assert(!JS_IsException(ret)); - JSValue ret_test = JS_Eval(ctx, test_code, strlen(test_code), "", JS_EVAL_TYPE_GLOBAL); + JSValue ret_test = eval(ctx, test_code); assert(!JS_IsException(ret_test)); JS_RunGC(rt); JSMemoryUsage memory_usage; JS_ComputeMemoryUsage(rt, &memory_usage); for (int i = 0; i < 3; i++) { - JSValue ret_test2 = JS_Eval(ctx, test_code, strlen(test_code), "", JS_EVAL_TYPE_GLOBAL); + JSValue ret_test2 = eval(ctx, test_code); assert(!JS_IsException(ret_test2)); JS_RunGC(rt); JSMemoryUsage memory_usage2; @@ -588,7 +637,7 @@ static void global_object_prototype(void) assert(res == true); JS_FreeValue(ctx, global_object); JS_FreeValue(ctx, proto); - ret = JS_Eval(ctx, code, strlen(code), "*", JS_EVAL_TYPE_GLOBAL); + ret = eval(ctx, code); assert(!JS_IsException(ret)); assert(JS_IsNumber(ret)); res = JS_ToInt32(ctx, &answer, ret); @@ -619,7 +668,7 @@ static void global_object_prototype(void) assert(res == true); JS_FreeValue(ctx, global_object); JS_FreeValue(ctx, proto); - ret = JS_Eval(ctx, code, strlen(code), "*", JS_EVAL_TYPE_GLOBAL); + ret = eval(ctx, code); assert(!JS_IsException(ret)); assert(JS_IsNumber(ret)); res = JS_ToInt32(ctx, &answer, ret); @@ -636,8 +685,7 @@ static void slice_string_tocstring(void) { JSRuntime *rt = JS_NewRuntime(); JSContext *ctx = JS_NewContext(rt); - static const char code[] = "'.'.repeat(16384).slice(1, -1)"; - JSValue ret = JS_Eval(ctx, code, strlen(code), "*", JS_EVAL_TYPE_GLOBAL); + JSValue ret = eval(ctx, "'.'.repeat(16384).slice(1, -1)"); assert(!JS_IsException(ret)); assert(JS_IsString(ret)); const char *str = JS_ToCString(ctx, ret); @@ -650,6 +698,7 @@ static void slice_string_tocstring(void) int main(void) { + cfunctions(); sync_call(); async_call(); async_call_stack_overflow(); diff --git a/quickjs.c b/quickjs.c index 793a13e9f..e0b38c7a3 100644 --- a/quickjs.c +++ b/quickjs.c @@ -5377,12 +5377,13 @@ JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func, cproto == JS_CFUNC_constructor_magic || cproto == JS_CFUNC_constructor_or_func || cproto == JS_CFUNC_constructor_or_func_magic); - if (!name) - name = ""; - name_atom = JS_NewAtom(ctx, name); - if (name_atom == JS_ATOM_NULL) { - JS_FreeValue(ctx, func_obj); - return JS_EXCEPTION; + name_atom = JS_ATOM_empty_string; + if (name && *name) { + name_atom = JS_NewAtom(ctx, name); + if (name_atom == JS_ATOM_NULL) { + JS_FreeValue(ctx, func_obj); + return JS_EXCEPTION; + } } js_function_set_properties(ctx, func_obj, name_atom, length); JS_FreeAtom(ctx, name_atom); @@ -5454,11 +5455,13 @@ static JSValue js_c_function_data_call(JSContext *ctx, JSValueConst func_obj, return s->func(ctx, this_val, argc, arg_buf, s->magic, vc(s->data)); } -JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, - int length, int magic, int data_len, - JSValueConst *data) +JSValue JS_NewCFunctionData2(JSContext *ctx, JSCFunctionData *func, + const char *name, + int length, int magic, int data_len, + JSValueConst *data) { JSCFunctionDataRecord *s; + JSAtom name_atom; JSValue func_obj; int i; @@ -5478,11 +5481,26 @@ JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, for(i = 0; i < data_len; i++) s->data[i] = js_dup(data[i]); JS_SetOpaqueInternal(func_obj, s); - js_function_set_properties(ctx, func_obj, - JS_ATOM_empty_string, length); + name_atom = JS_ATOM_empty_string; + if (name && *name) { + name_atom = JS_NewAtom(ctx, name); + if (name_atom == JS_ATOM_NULL) { + JS_FreeValue(ctx, func_obj); + return JS_EXCEPTION; + } + } + js_function_set_properties(ctx, func_obj, name_atom, length); + JS_FreeAtom(ctx, name_atom); return func_obj; } +JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, + int length, int magic, int data_len, + JSValueConst *data) +{ + return JS_NewCFunctionData2(ctx, func, NULL, length, magic, data_len, data); +} + static JSContext *js_autoinit_get_realm(JSProperty *pr) { return (JSContext *)(pr->u.init.realm_and_id & ~3); diff --git a/quickjs.h b/quickjs.h index dadd8d059..1359a07e9 100644 --- a/quickjs.h +++ b/quickjs.h @@ -1159,6 +1159,10 @@ JS_EXTERN JSValue JS_NewCFunction3(JSContext *ctx, JSCFunction *func, JS_EXTERN JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, int length, int magic, int data_len, JSValueConst *data); +JS_EXTERN JSValue JS_NewCFunctionData2(JSContext *ctx, JSCFunctionData *func, + const char *name, + int length, int magic, int data_len, + JSValueConst *data); static inline JSValue JS_NewCFunction(JSContext *ctx, JSCFunction *func, const char *name, int length)