From c8b1892307d42f169994466b60f1bf89afedc927 Mon Sep 17 00:00:00 2001 From: Alexander Klingenbeck Date: Tue, 23 May 2023 17:45:10 +0200 Subject: [PATCH] remove js stdlib for better compatibility --- CMakeLists.txt | 4 +- examples/js_example.js | 4 +- src/quickjs.c | 208 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 207 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dbd3bc7..4be68b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,13 +11,13 @@ set(quickjs_version 2021-03-27) set(quickjs_sources_root ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/quickjs) set(quickjs_sources ${quickjs_sources_root}/quickjs.h - ${quickjs_sources_root}/quickjs-libc.h + #${quickjs_sources_root}/quickjs-libc.h ${quickjs_sources_root}/quickjs.c ${quickjs_sources_root}/libregexp.c ${quickjs_sources_root}/libunicode.c ${quickjs_sources_root}/libbf.c ${quickjs_sources_root}/cutils.c - ${quickjs_sources_root}/quickjs-libc.c + #${quickjs_sources_root}/quickjs-libc.c ) add_library(quickjs STATIC ${quickjs_sources} diff --git a/examples/js_example.js b/examples/js_example.js index e7e5fe7..1a1b6dc 100644 --- a/examples/js_example.js +++ b/examples/js_example.js @@ -1,8 +1,8 @@ import { Timers } from "./common/timers.js" const timers = new Timers() -console.log(clamp(-1.5,0,5)) -console.log(vector2Distance(new Vector2(0,0), new Vector2(1,0))) +traceLog(LOG_INFO, clamp(-1.5,0,5)) +traceLog(LOG_INFO, vector2Distance(new Vector2(0,0), new Vector2(1,0))) initWindow(640, 480, "Javascript Tests") const pos = new Vector2(getScreenWidth()/2,getScreenHeight()/2) diff --git a/src/quickjs.c b/src/quickjs.c index e5ca3b0..105660d 100644 --- a/src/quickjs.c +++ b/src/quickjs.c @@ -1,5 +1,9 @@ +#include +#include +#include +#include #include -#include +//#include #include @@ -12,6 +16,72 @@ static int eval_buf(JSContext *ctx, const void *buf, int buf_len, static JSRuntime* rt; static JSContext* ctx; +static void pstrcpy(char *buf, int buf_size, const char *str) +{ + int c; + char *q = buf; + + if (buf_size <= 0) + return; + + for(;;) { + c = *str++; + if (c == 0 || q >= buf + buf_size - 1) + break; + *q++ = c; + } + *q = '\0'; +} + +/* strcat and truncate. */ +static char *pstrcat(char *buf, int buf_size, const char *s) +{ + int len; + len = strlen(buf); + if (len < buf_size) + pstrcpy(buf + len, buf_size - len, s); + return buf; +} + +static void js_dump_obj(JSContext *ctx, FILE *f, JSValueConst val) +{ + const char *str; + + str = JS_ToCString(ctx, val); + if (str) { + fprintf(f, "%s\n", str); + JS_FreeCString(ctx, str); + } else { + fprintf(f, "[exception]\n"); + } +} + +static void js_std_dump_error1(JSContext *ctx, JSValueConst exception_val) +{ + JSValue val; + bool is_error; + + is_error = JS_IsError(ctx, exception_val); + js_dump_obj(ctx, stderr, exception_val); + if (is_error) { + val = JS_GetPropertyStr(ctx, exception_val, "stack"); + if (!JS_IsUndefined(val)) { + js_dump_obj(ctx, stderr, val); + } + JS_FreeValue(ctx, val); + } +} + + +static void js_std_dump_error(JSContext *ctx) +{ + JSValue exception_val; + + exception_val = JS_GetException(ctx); + js_std_dump_error1(ctx, exception_val); + JS_FreeValue(ctx, exception_val); +} + int app_update_quickjs(){ JSContext *ctx1; int err; @@ -29,6 +99,104 @@ int app_update_quickjs(){ return 0; } +static int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, + JS_BOOL use_realpath, JS_BOOL is_main) +{ + JSModuleDef *m; + char buf[1024 + 16]; + JSValue meta_obj; + JSAtom module_name_atom; + const char *module_name; + + assert(JS_VALUE_GET_TAG(func_val) == JS_TAG_MODULE); + m = JS_VALUE_GET_PTR(func_val); + + module_name_atom = JS_GetModuleName(ctx, m); + module_name = JS_AtomToCString(ctx, module_name_atom); + JS_FreeAtom(ctx, module_name_atom); + if (!module_name) + return -1; + if (!strchr(module_name, ':')) { + strcpy(buf, "file://"); +#if !defined(_WIN32) + /* realpath() cannot be used with modules compiled with qjsc + because the corresponding module source code is not + necessarily present */ + if (use_realpath) { + char *res = realpath(module_name, buf + strlen(buf)); + if (!res) { + JS_ThrowTypeError(ctx, "realpath failure"); + JS_FreeCString(ctx, module_name); + return -1; + } + } else +#endif + { + pstrcat(buf, sizeof(buf), module_name); + } + } else { + pstrcpy(buf, sizeof(buf), module_name); + } + JS_FreeCString(ctx, module_name); + + meta_obj = JS_GetImportMeta(ctx, m); + if (JS_IsException(meta_obj)) + return -1; + JS_DefinePropertyValueStr(ctx, meta_obj, "url", + JS_NewString(ctx, buf), + JS_PROP_C_W_E); + JS_DefinePropertyValueStr(ctx, meta_obj, "main", + JS_NewBool(ctx, is_main), + JS_PROP_C_W_E); + JS_FreeValue(ctx, meta_obj); + return 0; +} + +static uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename) +{ + FILE *f; + uint8_t *buf; + size_t buf_len; + long lret; + + f = fopen(filename, "rb"); + if (!f) + return NULL; + if (fseek(f, 0, SEEK_END) < 0) + goto fail; + lret = ftell(f); + if (lret < 0) + goto fail; + /* XXX: on Linux, ftell() return LONG_MAX for directories */ + if (lret == LONG_MAX) { + errno = EISDIR; + goto fail; + } + buf_len = lret; + if (fseek(f, 0, SEEK_SET) < 0) + goto fail; + if (ctx) + buf = js_malloc(ctx, buf_len + 1); + else + buf = malloc(buf_len + 1); + if (!buf) + goto fail; + if (fread(buf, 1, buf_len, f) != buf_len) { + errno = EIO; + if (ctx) + js_free(ctx, buf); + else + free(buf); + fail: + fclose(f); + return NULL; + } + buf[buf_len] = '\0'; + fclose(f); + *pbuf_len = buf_len; + return buf; +} + void SetModelMaterial(Model *model, int materialIndex, Material material) { if(model->materialCount <= materialIndex) return; @@ -38,6 +206,36 @@ void SetModelMaterial(Model *model, int materialIndex, Material material) #include "bindings/js_raylib_core.h" +JSModuleDef *js_module_loader(JSContext *ctx, + const char *module_name, void *opaque) +{ + JSModuleDef *m; + + size_t buf_len; + uint8_t *buf; + JSValue func_val; + + buf = js_load_file(ctx, &buf_len, module_name); + if (!buf) { + JS_ThrowReferenceError(ctx, "could not load module filename '%s'", module_name); + return NULL; + } + + /* compile the module */ + func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name, + JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY); + js_free(ctx, buf); + if (JS_IsException(func_val)) + return NULL; + /* XXX: could propagate the exception */ + js_module_set_import_meta(ctx, func_val, true, false); + /* the module is already referenced, so we must free it */ + m = JS_VALUE_GET_PTR(func_val); + JS_FreeValue(ctx, func_val); + + return m; +} + int app_init_quickjs(int argc, char** argv){ TraceLog(LOG_INFO, "Starting QuickJS"); rt = JS_NewRuntime(); @@ -46,8 +244,8 @@ int app_init_quickjs(int argc, char** argv){ fprintf(stderr, "qjs: cannot allocate JS runtime\n"); return -1; } - js_std_set_worker_new_context_func(JS_NewCustomContext); - js_std_init_handlers(rt); + //js_std_set_worker_new_context_func(JS_NewCustomContext); + //js_std_init_handlers(rt); ctx = JS_NewCustomContext(rt); if (!ctx) { fprintf(stderr, "qjs: cannot allocate JS context\n"); @@ -56,7 +254,7 @@ int app_init_quickjs(int argc, char** argv){ JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL); - js_std_add_helpers(ctx, argc, argv); + //js_std_add_helpers(ctx, argc, argv); const char *str = "import * as rl from 'raylib'\n" "for (const key in rl) { globalThis[key] = rl[key] }\n"; @@ -118,7 +316,7 @@ static JSContext *JS_NewCustomContext(JSRuntime *rt) return NULL; /* system modules */ - js_init_module_std(ctx, "std"); + //js_init_module_std(ctx, "std"); //js_init_module_os(ctx, "os"); js_init_module_raylib_core(ctx, "raylib"); return ctx;