#include "script.h" #include "log.h" #include "stdio.h" #include "ffi.h" #include "font.h" #include "ftw.h" #include "stb_ds.h" #include "sys/stat.h" #include "sys/types.h" #include "time.h" JSContext *js = NULL; JSRuntime *rt = NULL; #ifdef DBG #define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT #else #define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT | JS_EVAL_FLAG_STRIP #endif static int load_prefab(const char *fpath, const struct stat *sb, int typeflag) { if (typeflag != FTW_F) return 0; if (!strcmp(".prefab", strrchr(fpath, '.'))) script_dofile(fpath); return 0; } void script_startup() { rt = JS_NewRuntime(); JS_SetMaxStackSize(rt, 0); js = JS_NewContext(rt); ffi_load(); } JSValue num_cache[100] = {0}; int js_print_exception(JSValue v) { #ifdef DBG if (JS_IsException(v)) { JSValue exception = JS_GetException(js); /* TODO: Does it need freed if null? */ if (JS_IsNull(exception)) return 0; JSValue val = JS_GetPropertyStr(js, exception, "stack"); const char *name = JS_ToCString(js, JS_GetPropertyStr(js, exception, "name")); const char *msg = JS_ToCString(js, JS_GetPropertyStr(js, exception, "message")); const char *stack = JS_ToCString(js, val); YughLog(LOG_SCRIPT, LOG_ERROR, "%s :: %s\n%s", name, msg,stack); JS_FreeCString(js, name); JS_FreeCString(js, msg); JS_FreeCString(js, stack); JS_FreeValue(js,val); JS_FreeValue(js,exception); return 1; } #endif return 0; } void script_init() { /* Load all prefabs into memory */ // if (DBG) // script_dofile("scripts/debug.js"); // else script_dofile("scripts/engine.js"); for (int i = 0; i < 100; i++) num_cache[i] = int2js(i); } void script_run(const char *script, const char *file) { JSValue obj = JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAGS); js_print_exception(obj); JS_FreeValue(js,obj); } void compile_script(const char *file) { const char *script = slurp_text(file); JSValue obj = JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAG_COMPILE_ONLY | JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAGS); size_t out_len; uint8_t *out; out = JS_WriteObject(js, &out_len, obj, JS_WRITE_OBJ_BYTECODE); FILE *f = fopen("out.jsc", "w"); fwrite(out, sizeof out[0], out_len, f); fclose(f); } struct callee stacktrace_callee; time_t file_mod_secs(const char *file) { struct stat attr; stat(file, &attr); return attr.st_mtime; } void js_stacktrace() { #ifdef DBG call_callee(&stacktrace_callee); #endif } void js_dump_stack() { js_stacktrace(); } int script_dofile(const char *file) { const char *script = slurp_text(file); if (!script) { YughError("Can't find file %s.", file); return 0; } script_run(script,file); free(script); return file_mod_secs(file); } JSValue script_runfile(const char *file) { const char *script = slurp_text(file); int bufsize = strlen(script)+50; char scriptbuffer[bufsize]; snprintf(scriptbuffer,bufsize, "(function(){%s})()", script); JSValue obj = JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAGS); js_print_exception(obj); free(script); return obj; } /* env is an object in the scripting environment; s is the function to call on that object */ void script_eval_w_env(const char *s, JSValue env) { JSValue v = JS_EvalThis(js, env, s, strlen(s), "internal", JS_EVAL_FLAGS); js_print_exception(v); JS_FreeValue(js, v); } void script_call_sym(JSValue sym) { struct callee c; c.fn = sym; c.obj = JS_GetGlobalObject(js); call_callee(&c); } JSValue js_callee_exec(struct callee *c, int argc, JSValue *argv) { JSValue ret = JS_Call(js, c->fn, c->obj, argc, argv); js_print_exception(ret); JS_FreeValue(js, ret); return JS_NULL; } void call_callee(struct callee *c) { js_callee_exec(c, 0, NULL); } void callee_dbl(struct callee c, double d) { JSValue v = num2js(d); js_callee_exec(&c, 1, &v); JS_FreeValue(js, v); } void callee_int(struct callee c, int i) { JSValue v = int2js(i); js_callee_exec(&c, 1, &v); JS_FreeValue(js, v); } void callee_vec2(struct callee c, cpVect vec) { JSValue v = vec2js(vec); js_callee_exec(&c, 1, &v); JS_FreeValue(js, v); } void script_callee(struct callee c, int argc, JSValue *argv) { js_callee_exec(&c, argc, argv); } void send_signal(const char *signal, int argc, JSValue *argv) { JSValue globalThis = JS_GetGlobalObject(js); JSValue sig = JS_GetPropertyStr(js, globalThis, "Signal"); JSValue fn = JS_GetPropertyStr(js, sig, "call"); JSValue args[argc+1]; args[0] = str2js(signal); for (int i = 0; i < argc; i++) args[1+i] = argv[i]; JS_Call(js, fn, sig, argc+1, args); } static struct callee update_callee; void register_update(struct callee c) { update_callee = c; } void call_updates(double dt) { callee_dbl(update_callee, dt); } static struct callee gui_callee; void register_gui(struct callee c) { gui_callee = c; } void call_gui() { js_callee_exec(&gui_callee, 0, NULL); } static struct callee nk_gui_callee; void register_nk_gui(struct callee c) { nk_gui_callee = c; } void call_nk_gui() { js_callee_exec(&nk_gui_callee, 0, NULL); } static struct callee physupdate_callee; void register_physics(struct callee c) { physupdate_callee = c; } void call_physics(double dt) { callee_dbl(physupdate_callee, dt); } struct callee debug_callee; void register_debug(struct callee c) { debug_callee = c; } void call_debugs() { call_callee(&debug_callee); } static struct callee draw_callee; void register_draw(struct callee c) { draw_callee = c; } void call_draw() { call_callee(&draw_callee); }