2021-11-30 21:29:18 -06:00
|
|
|
#include "script.h"
|
|
|
|
|
2022-08-03 17:00:00 -05:00
|
|
|
#include "log.h"
|
2023-05-12 13:22:05 -05:00
|
|
|
#include "stdio.h"
|
2022-06-21 12:48:19 -05:00
|
|
|
|
2023-11-03 22:01:30 -05:00
|
|
|
#include "jsffi.h"
|
2023-01-10 14:02:24 -06:00
|
|
|
#include "font.h"
|
2022-06-21 12:48:19 -05:00
|
|
|
|
2023-11-06 07:05:27 -06:00
|
|
|
#include "gameobject.h"
|
|
|
|
|
2023-01-05 15:34:15 -06:00
|
|
|
#include "ftw.h"
|
|
|
|
|
2022-12-19 09:12:34 -06:00
|
|
|
#include "stb_ds.h"
|
|
|
|
|
2023-01-13 13:07:44 -06:00
|
|
|
#include "sys/stat.h"
|
|
|
|
#include "sys/types.h"
|
2023-05-12 13:22:05 -05:00
|
|
|
#include "time.h"
|
2023-09-04 09:48:44 -05:00
|
|
|
#include "resources.h"
|
2023-10-16 09:40:43 -05:00
|
|
|
#include "input.h"
|
2023-01-13 13:07:44 -06:00
|
|
|
|
2023-08-31 02:05:06 -05:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
2023-04-18 14:49:17 -05:00
|
|
|
JSContext *js = NULL;
|
2023-04-18 17:58:44 -05:00
|
|
|
JSRuntime *rt = NULL;
|
2021-11-30 21:29:18 -06:00
|
|
|
|
2023-09-03 12:50:02 -05:00
|
|
|
#ifndef NDEBUG
|
2023-05-24 20:45:50 -05:00
|
|
|
#define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT
|
|
|
|
#else
|
2024-02-23 16:05:30 -06:00
|
|
|
#define JS_EVAL_FLAGS JS_EVAL_FLAG_STRICT | JS_EVAL_FLAG_STRIP
|
2023-05-24 20:45:50 -05:00
|
|
|
#endif
|
|
|
|
|
2023-10-16 09:40:43 -05:00
|
|
|
static struct {
|
|
|
|
char *key;
|
|
|
|
JSValue value;
|
|
|
|
} *jsstrs = NULL;
|
|
|
|
|
|
|
|
JSValue jstr(const char *str)
|
|
|
|
{
|
|
|
|
int index = shgeti(jsstrs, str);
|
|
|
|
if (index != -1) return jsstrs[index].value;
|
|
|
|
|
|
|
|
JSValue v = str2js(str);
|
|
|
|
shput(jsstrs, str, v);
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2023-01-05 15:34:15 -06:00
|
|
|
static int load_prefab(const char *fpath, const struct stat *sb, int typeflag) {
|
2023-05-12 13:22:05 -05:00
|
|
|
if (typeflag != FTW_F)
|
|
|
|
return 0;
|
2023-01-05 15:34:15 -06:00
|
|
|
|
2023-05-12 13:22:05 -05:00
|
|
|
if (!strcmp(".prefab", strrchr(fpath, '.')))
|
|
|
|
script_dofile(fpath);
|
2023-01-05 15:34:15 -06:00
|
|
|
|
2023-05-12 13:22:05 -05:00
|
|
|
return 0;
|
2023-01-05 15:34:15 -06:00
|
|
|
}
|
|
|
|
|
2023-05-12 13:22:05 -05:00
|
|
|
void script_startup() {
|
|
|
|
rt = JS_NewRuntime();
|
|
|
|
js = JS_NewContext(rt);
|
2023-10-16 09:40:43 -05:00
|
|
|
|
2024-02-29 13:54:33 -06:00
|
|
|
sh_new_arena(jsstrs);
|
2023-09-05 10:44:52 -05:00
|
|
|
|
2023-05-12 13:22:05 -05:00
|
|
|
ffi_load();
|
2023-09-04 09:48:44 -05:00
|
|
|
|
|
|
|
for (int i = 0; i < 100; i++)
|
|
|
|
num_cache[i] = int2js(i);
|
2023-09-18 10:45:51 -05:00
|
|
|
|
|
|
|
script_dofile("scripts/engine.js");
|
2023-09-18 07:36:07 -05:00
|
|
|
// jso_file("scripts/engine.js");
|
2023-04-22 14:07:37 -05:00
|
|
|
}
|
2023-01-05 15:34:15 -06:00
|
|
|
|
2023-10-03 17:16:38 -05:00
|
|
|
void script_stop()
|
|
|
|
{
|
2023-12-20 17:20:29 -06:00
|
|
|
script_evalf("Event.notify('quit');");
|
2023-10-04 08:18:09 -05:00
|
|
|
send_signal("quit",0,NULL);
|
2024-02-01 10:11:09 -06:00
|
|
|
ffi_stop();
|
2023-10-16 09:40:43 -05:00
|
|
|
for (int i = 0; i < shlen(jsstrs); i++)
|
|
|
|
JS_FreeValue(js,jsstrs[i].value);
|
2024-02-23 16:05:30 -06:00
|
|
|
|
|
|
|
#if LEAK
|
2023-10-16 09:40:43 -05:00
|
|
|
JS_FreeContext(js);
|
2023-10-03 17:16:38 -05:00
|
|
|
JS_FreeRuntime(rt);
|
2024-02-23 16:05:30 -06:00
|
|
|
#endif
|
2023-10-03 17:16:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void script_gc()
|
|
|
|
{
|
|
|
|
JS_RunGC(rt);
|
|
|
|
}
|
|
|
|
|
2023-04-28 12:49:18 -05:00
|
|
|
JSValue num_cache[100] = {0};
|
2022-06-21 12:48:19 -05:00
|
|
|
|
2023-10-10 17:37:58 -05:00
|
|
|
/*int js_print_exception(JSValue v) {
|
2023-09-03 12:50:02 -05:00
|
|
|
#ifndef NDEBUG
|
2023-05-30 11:39:22 -05:00
|
|
|
if (JS_IsException(v)) {
|
|
|
|
JSValue exception = JS_GetException(js);
|
|
|
|
|
2023-10-03 17:16:38 -05:00
|
|
|
if (JS_IsNull(exception)) {
|
|
|
|
JS_FreeValue(js,exception);
|
2023-05-30 11:39:22 -05:00
|
|
|
return 0;
|
2023-10-03 17:16:38 -05:00
|
|
|
}
|
2023-05-30 11:39:22 -05:00
|
|
|
|
2023-10-10 17:37:58 -05:00
|
|
|
JSValue val = JS_ToCStringJS_GetPropertyStr(js, exception, "stack");
|
2023-05-30 11:39:22 -05:00
|
|
|
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);
|
2024-02-27 10:09:15 -06:00
|
|
|
js_stacktrace();
|
2022-06-21 12:48:19 -05:00
|
|
|
|
2023-05-30 11:39:22 -05:00
|
|
|
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;
|
|
|
|
}
|
2023-10-10 17:37:58 -05:00
|
|
|
*/
|
2023-05-29 10:47:30 -05:00
|
|
|
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);
|
2023-05-24 20:45:50 -05:00
|
|
|
}
|
|
|
|
|
2023-06-28 11:35:41 -05:00
|
|
|
void script_evalf(const char *format, ...)
|
|
|
|
{
|
|
|
|
char fmtbuf[4096];
|
|
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
|
|
vsnprintf(fmtbuf, 4096, format, args);
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
JSValue obj = JS_Eval(js, fmtbuf, strlen(fmtbuf), "C eval", JS_EVAL_FLAGS);
|
|
|
|
js_print_exception(obj);
|
|
|
|
JS_FreeValue(js,obj);
|
|
|
|
}
|
|
|
|
|
2024-02-23 16:05:30 -06:00
|
|
|
uint8_t *script_compile(const char *file, size_t *len) {
|
|
|
|
size_t file_len;
|
|
|
|
char *script = slurp_text(file, &file_len);
|
|
|
|
JSValue obj = JS_Eval(js, script, file_len, file, JS_EVAL_FLAG_COMPILE_ONLY | JS_EVAL_TYPE_GLOBAL | JS_EVAL_FLAGS);
|
2023-09-18 07:36:07 -05:00
|
|
|
free(script);
|
2024-02-23 16:05:30 -06:00
|
|
|
uint8_t *out = JS_WriteObject(js, len, obj, JS_WRITE_OBJ_BYTECODE);
|
2023-10-04 08:18:09 -05:00
|
|
|
JS_FreeValue(js,obj);
|
2023-09-18 07:36:07 -05:00
|
|
|
return out;
|
2022-02-06 10:14:57 -06:00
|
|
|
}
|
2022-08-01 13:32:58 -05:00
|
|
|
|
2024-02-23 16:05:30 -06:00
|
|
|
JSValue script_run_bytecode(uint8_t *code, size_t len)
|
|
|
|
{
|
|
|
|
JSValue b = JS_ReadObject(js, code, len, JS_READ_OBJ_BYTECODE);
|
|
|
|
JSValue ret = JS_EvalFunction(js, b);
|
|
|
|
js_print_exception(ret);
|
|
|
|
JS_FreeValue(js,b);
|
2024-03-11 22:23:02 -05:00
|
|
|
return ret;
|
2024-02-23 16:05:30 -06:00
|
|
|
}
|
|
|
|
|
2023-04-28 12:49:18 -05:00
|
|
|
struct callee stacktrace_callee;
|
|
|
|
|
2023-01-13 13:07:44 -06:00
|
|
|
time_t file_mod_secs(const char *file) {
|
2023-05-12 13:22:05 -05:00
|
|
|
struct stat attr;
|
|
|
|
stat(file, &attr);
|
|
|
|
return attr.st_mtime;
|
2023-01-13 13:07:44 -06:00
|
|
|
}
|
|
|
|
|
2023-05-12 13:22:05 -05:00
|
|
|
void js_stacktrace() {
|
2023-09-03 12:50:02 -05:00
|
|
|
#ifndef NDEBUG
|
2024-03-11 22:23:02 -05:00
|
|
|
script_evalf("console.stack();");
|
2023-05-24 20:45:50 -05:00
|
|
|
#endif
|
2021-11-30 21:29:18 -06:00
|
|
|
}
|
|
|
|
|
2023-05-12 13:22:05 -05:00
|
|
|
void js_dump_stack() {
|
2023-04-28 12:49:18 -05:00
|
|
|
js_stacktrace();
|
2022-02-06 10:14:57 -06:00
|
|
|
}
|
2022-08-01 13:32:58 -05:00
|
|
|
|
2022-11-20 15:50:14 -06:00
|
|
|
int script_dofile(const char *file) {
|
2023-10-03 17:16:38 -05:00
|
|
|
JSValue ret = script_runfile(file);
|
|
|
|
JS_FreeValue(js,ret);
|
2023-05-29 10:47:30 -05:00
|
|
|
return file_mod_secs(file);
|
|
|
|
}
|
2023-01-13 13:07:44 -06:00
|
|
|
|
2023-09-18 07:36:07 -05:00
|
|
|
JSValue script_runjso(const uint8_t *buf, size_t len)
|
|
|
|
{
|
|
|
|
JSValue obj = JS_ReadObject(js, buf, len, JS_EVAL_FLAGS);
|
|
|
|
JSValue ret = JS_EvalFunction(js, obj);
|
|
|
|
js_print_exception(ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
time_t jso_file(const char *file)
|
|
|
|
{
|
|
|
|
size_t len;
|
2023-09-18 10:45:51 -05:00
|
|
|
uint8_t *byte = slurp_file(file, &len);
|
2023-09-18 07:36:07 -05:00
|
|
|
JSValue obj = JS_ReadObject(js, byte, len, JS_READ_OBJ_BYTECODE);
|
|
|
|
JSValue ret = JS_EvalFunction(js, obj);
|
|
|
|
js_print_exception(ret);
|
2023-10-04 08:18:09 -05:00
|
|
|
JS_FreeValue(js,ret);
|
2023-12-28 07:57:22 -06:00
|
|
|
JS_FreeValue(js,obj);
|
2023-09-18 07:36:07 -05:00
|
|
|
free(byte);
|
|
|
|
return file_mod_secs(file);
|
|
|
|
}
|
|
|
|
|
2023-06-08 17:27:37 -05:00
|
|
|
JSValue script_runfile(const char *file)
|
2023-05-29 10:47:30 -05:00
|
|
|
{
|
2023-09-07 16:46:35 -05:00
|
|
|
size_t len;
|
2023-12-21 17:21:01 -06:00
|
|
|
char *script = slurp_text(file, &len);
|
2023-11-29 12:40:13 -06:00
|
|
|
if (!script) return JS_UNDEFINED;
|
2024-03-13 16:30:55 -05:00
|
|
|
YughWarn("Eval %s.", file);
|
2023-09-07 16:46:35 -05:00
|
|
|
JSValue obj = JS_Eval(js, script, len, file, JS_EVAL_FLAGS);
|
2023-06-08 17:27:37 -05:00
|
|
|
js_print_exception(obj);
|
2023-10-04 08:18:09 -05:00
|
|
|
|
2023-05-29 10:47:30 -05:00
|
|
|
free(script);
|
2023-06-08 17:27:37 -05:00
|
|
|
return obj;
|
2022-08-03 17:00:00 -05:00
|
|
|
}
|
|
|
|
|
2023-02-02 17:52:15 -06:00
|
|
|
/* env is an object in the scripting environment;
|
|
|
|
s is the function to call on that object
|
|
|
|
*/
|
2023-09-07 16:46:35 -05:00
|
|
|
void script_eval_w_env(const char *s, JSValue env, const char *file) {
|
|
|
|
JSValue v = JS_EvalThis(js, env, s, strlen(s), file, JS_EVAL_FLAGS);
|
2023-04-19 15:16:35 -05:00
|
|
|
js_print_exception(v);
|
|
|
|
JS_FreeValue(js, v);
|
2022-08-07 01:43:45 -05:00
|
|
|
}
|
|
|
|
|
2024-02-27 10:09:15 -06:00
|
|
|
JSValue eval_file_env(const char *script, const char *file, JSValue env)
|
2023-11-27 17:04:04 -06:00
|
|
|
{
|
2024-02-27 10:09:15 -06:00
|
|
|
JSValue v = JS_EvalThis(js, env, script, strlen(script), file, JS_EVAL_FLAGS);
|
|
|
|
js_print_exception(v);
|
|
|
|
return v;
|
2023-11-27 14:29:55 -06:00
|
|
|
}
|
|
|
|
|
2024-02-29 13:54:33 -06:00
|
|
|
JSValue file_eval_env(const char *file, JSValue env)
|
2023-08-29 09:41:40 -05:00
|
|
|
{
|
2023-09-07 16:46:35 -05:00
|
|
|
size_t len;
|
|
|
|
char *script = slurp_text(file, &len);
|
|
|
|
JSValue v = JS_EvalThis(js, env, script, len, file, JS_EVAL_FLAGS);
|
2023-08-29 09:41:40 -05:00
|
|
|
free(script);
|
|
|
|
js_print_exception(v);
|
2024-03-11 22:23:02 -05:00
|
|
|
return v;
|
2023-08-29 09:41:40 -05:00
|
|
|
}
|
|
|
|
|
2023-05-12 13:22:05 -05:00
|
|
|
void script_call_sym(JSValue sym) {
|
2023-11-27 14:29:55 -06:00
|
|
|
if (!JS_IsFunction(js, sym)) return;
|
2023-04-19 16:58:17 -05:00
|
|
|
struct callee c;
|
|
|
|
c.fn = sym;
|
|
|
|
c.obj = JS_GetGlobalObject(js);
|
|
|
|
call_callee(&c);
|
2023-02-28 17:03:28 -06:00
|
|
|
}
|
|
|
|
|
2024-01-03 17:19:13 -06:00
|
|
|
void script_call_fn_arg(JSValue fn, JSValue arg)
|
|
|
|
{
|
|
|
|
if (!JS_IsFunction(js,fn)) return;
|
|
|
|
JSValue ret = JS_Call(js, fn, JS_GetGlobalObject(js), 1, &arg);
|
|
|
|
js_print_exception(ret);
|
|
|
|
JS_FreeValue(js, ret);
|
|
|
|
}
|
|
|
|
|
2023-10-03 17:16:38 -05:00
|
|
|
void out_memusage(const char *file)
|
|
|
|
{
|
2024-02-25 17:31:48 -06:00
|
|
|
FILE *f = fopen(file, "w");
|
|
|
|
if (!f) return;
|
2023-10-03 17:16:38 -05:00
|
|
|
JSMemoryUsage jsmem;
|
|
|
|
JS_ComputeMemoryUsage(rt, &jsmem);
|
|
|
|
JS_DumpMemoryUsage(f, &jsmem, rt);
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
2023-06-28 11:35:41 -05:00
|
|
|
JSValue js_callee_exec(struct callee *c, int argc, JSValue *argv)
|
|
|
|
{
|
2023-11-29 12:40:13 -06:00
|
|
|
if (JS_IsUndefined(c->fn)) return JS_UNDEFINED;
|
|
|
|
if (JS_IsUndefined(c->obj)) return JS_UNDEFINED;
|
2023-11-27 14:29:55 -06:00
|
|
|
|
2023-04-19 15:16:35 -05:00
|
|
|
JSValue ret = JS_Call(js, c->fn, c->obj, argc, argv);
|
|
|
|
js_print_exception(ret);
|
|
|
|
JS_FreeValue(js, ret);
|
2023-11-29 12:40:13 -06:00
|
|
|
return JS_UNDEFINED;
|
2022-08-03 17:00:00 -05:00
|
|
|
}
|
|
|
|
|
2023-02-02 17:52:15 -06:00
|
|
|
void call_callee(struct callee *c) {
|
2023-04-19 15:16:35 -05:00
|
|
|
js_callee_exec(c, 0, NULL);
|
2022-08-03 17:00:00 -05:00
|
|
|
}
|
|
|
|
|
2023-05-12 13:22:05 -05:00
|
|
|
void callee_dbl(struct callee c, double d) {
|
2024-01-14 10:24:31 -06:00
|
|
|
JSValue v = number2js(d);
|
2023-04-18 17:58:44 -05:00
|
|
|
js_callee_exec(&c, 1, &v);
|
2023-04-19 15:16:35 -05:00
|
|
|
JS_FreeValue(js, v);
|
2022-08-03 20:49:56 -05:00
|
|
|
}
|
|
|
|
|
2023-05-12 13:22:05 -05:00
|
|
|
void callee_int(struct callee c, int i) {
|
2023-04-18 17:58:44 -05:00
|
|
|
JSValue v = int2js(i);
|
|
|
|
js_callee_exec(&c, 1, &v);
|
2023-04-19 15:16:35 -05:00
|
|
|
JS_FreeValue(js, v);
|
2022-08-05 14:23:39 -05:00
|
|
|
}
|
|
|
|
|
2023-11-14 09:20:09 -06:00
|
|
|
void callee_vec2(struct callee c, HMM_Vec2 vec) {
|
2024-03-13 03:51:44 -05:00
|
|
|
JSValue v = vec22js(vec);
|
2023-04-18 17:58:44 -05:00
|
|
|
js_callee_exec(&c, 1, &v);
|
2023-04-19 15:16:35 -05:00
|
|
|
JS_FreeValue(js, v);
|
2022-08-07 01:43:45 -05:00
|
|
|
}
|
|
|
|
|
2023-05-12 13:22:05 -05:00
|
|
|
void script_callee(struct callee c, int argc, JSValue *argv) {
|
2023-04-19 15:16:35 -05:00
|
|
|
js_callee_exec(&c, argc, argv);
|
2022-12-20 19:34:22 -06:00
|
|
|
}
|
|
|
|
|
2023-11-27 14:29:55 -06:00
|
|
|
void free_callee(struct callee c)
|
2023-11-07 12:45:52 -06:00
|
|
|
{
|
2023-11-27 14:29:55 -06:00
|
|
|
JS_FreeValue(js,c.fn);
|
|
|
|
JS_FreeValue(js,c.obj);
|
2023-11-07 12:45:52 -06:00
|
|
|
}
|
|
|
|
|
2023-06-06 15:49:55 -05:00
|
|
|
void send_signal(const char *signal, int argc, JSValue *argv)
|
2022-08-07 01:43:45 -05:00
|
|
|
{
|
2023-06-06 15:49:55 -05:00
|
|
|
JSValue globalThis = JS_GetGlobalObject(js);
|
|
|
|
JSValue sig = JS_GetPropertyStr(js, globalThis, "Signal");
|
2023-10-04 08:18:09 -05:00
|
|
|
JS_FreeValue(js, globalThis);
|
2023-06-06 15:49:55 -05:00
|
|
|
JSValue fn = JS_GetPropertyStr(js, sig, "call");
|
|
|
|
JSValue args[argc+1];
|
2023-10-16 09:40:43 -05:00
|
|
|
args[0] = jstr(signal);
|
2023-06-06 15:49:55 -05:00
|
|
|
for (int i = 0; i < argc; i++)
|
|
|
|
args[1+i] = argv[i];
|
|
|
|
|
2023-10-04 08:18:09 -05:00
|
|
|
JS_FreeValue(js,JS_Call(js, fn, sig, argc+1, args));
|
2023-10-16 09:40:43 -05:00
|
|
|
JS_FreeValue(js, sig);
|
|
|
|
JS_FreeValue(js, fn);
|
2022-08-07 01:43:45 -05:00
|
|
|
}
|