'use' now how to load extra programs; cached

This commit is contained in:
John Alanbrook 2024-03-21 11:33:36 -05:00
parent 51f3b5abeb
commit f5d610cbed
11 changed files with 115 additions and 196 deletions

View file

@ -1,12 +1,10 @@
var actor = {}; var actor = {};
var a_db = {};
actor.spawn = function(script, config){ actor.spawn = function(script, config){
if (typeof script !== 'string') return undefined; if (typeof script !== 'string') return undefined;
console.info(`spawning actor with script ${script}`); console.info(`spawning actor with script ${script}`);
if (!a_db[script]) a_db[script] = io.slurp(script);
var padawan = Object.create(actor); var padawan = Object.create(actor);
eval_env(a_db[script], padawan, script); use(script, padawan);
if (typeof config === 'object') if (typeof config === 'object')
Object.merge(padawan,config); Object.merge(padawan,config);

View file

@ -590,10 +590,8 @@ Object.defineProperty(Object.prototype, 'obscure', {
Object.defineProperty(Object.prototype, 'mixin', { Object.defineProperty(Object.prototype, 'mixin', {
value: function(obj) { value: function(obj) {
if (typeof obj === 'string') { if (typeof obj === 'string')
var script = io.slurp(obj); obj = use(obj, this);
obj = eval_env(script, this, obj);
}
if (obj) if (obj)
Object.mixin(this, obj); Object.mixin(this, obj);

View file

@ -19,8 +19,6 @@ debug.draw = function() {
if (this.draw_bb) if (this.draw_bb)
game.all_objects(function(x) { debug.boundingbox(x.boundingbox(), Color.debug.boundingbox.alpha(0.05)); }); game.all_objects(function(x) { debug.boundingbox(x.boundingbox(), Color.debug.boundingbox.alpha(0.05)); });
if (this.draw_gizmos) if (this.draw_gizmos)
game.all_objects(function(x) { game.all_objects(function(x) {
if (!x.icon) return; if (!x.icon) return;
@ -66,19 +64,6 @@ var Gizmos = {
}, },
}; };
profile.best_t = function(t) {
var qq = 'ns';
if (t > 1000) {
t /= 1000;
qq = 'us';
if (t > 1000) {
t /= 1000;
qq = 'ms';
}
}
return `${t.toPrecision(4)} ${qq}`;
}
profile.cpu = function(fn, times, q) { profile.cpu = function(fn, times, q) {
times ??= 1; times ??= 1;
q ??= "unnamed"; q ??= "unnamed";

View file

@ -1,5 +1,41 @@
"use math"; "use math";
globalThis.Resources = {};
Resources.scripts = ["jsoc", "jsc", "jso", "js"];
Resources.images = ["png", "gif", "jpg", "jpeg"];
Resources.sounds = ["wav", 'flac', 'mp3', "qoa"];
Resources.is_image = function(path) {
var ext = path.ext();
return Resources.images.any(x => x === ext);
}
function find_ext(file, ext)
{
if (io.exists(file)) return file;
for (var e of ext) {
var nf = `${file}.${e}`;
if (io.exists(nf)) return nf;
}
return;
}
Resources.find_image = function(file) { return find_ext(file,Resources.images); }
Resources.find_sound = function(file) { return find_ext(file,Resources.sounds); }
Resources.find_script = function(file) { return find_ext(file,Resources.scripts); }
profile.best_t = function(t) {
var qq = 'ns';
if (t > 1000) {
t /= 1000;
qq = 'us';
if (t > 1000) {
t /= 1000;
qq = 'ms';
}
}
return `${t.toPrecision(4)} ${qq}`;
}
Object.assign(console, { Object.assign(console, {
say(msg) { console.print(msg + "\n"); }, say(msg) { console.print(msg + "\n"); },
@ -60,37 +96,30 @@ console.doc = {
globalThis.global = globalThis; globalThis.global = globalThis;
function use(file) function use(file, env, script)
{
if (use.files[file]) return use.files[file];
console.info(`running ${file}`);
var c = io.slurp(file);
var script = `(function() { ${c} })();`;
use.files[file] = os.eval_env(file,script,global);
return use.files[file];
}
use.files = {};
function include(file,that)
{
if (!that) return;
console.info(`running ${file}`);
var c = io.slurp(file);
eval_env(c, that, file);
}
function eval_env(script, env, file)
{ {
file = Resources.find_script(file);
console.info(`loading up ${file}`);
var st = profile.now();
env ??= {}; env ??= {};
file ??= "SCRIPT";
console.spam(`eval ${file}`); if (use.cache[file]) {
script = `(function() { ${script}; }).call(this);\n`; var ret = use.cache[file].call(env);
return os.eval_env(file,script,env); console.info(`CACHE eval ${file} in ${profile.best_t(profile.now()-st)}`);
return;
}
script ??= io.slurp(file);
script = `(function() { ${script}; })`;
var fn = os.eval(file,script);
use.cache[file] = fn;
var ret = fn.call(env);
console.info(`eval ${file} in ${profile.best_t(profile.now()-st)}`);
return ret;
} }
use.cache = {};
global.check_registers = function(obj) global.check_registers = function(obj)
{ {
if (typeof obj.update === 'function') if (typeof obj.update === 'function')
@ -121,28 +150,10 @@ global.check_registers = function(obj)
}; };
} }
eval_env.dov = `Counterpart to /load_env/, but with a string.`; Object.assign(global, use("scripts/base"));
function feval_env(file, env)
{
eval_env(io.slurp(file), env, file);
}
function load_env(file,env)
{
env ??= global;
var script = io.slurp(file);
eval_env(script, env, file);
}
load_env.doc = `Load a given file with 'env' as **this**. Does not add to the global namespace.`;
var load = use;
Object.assign(global, use("scripts/base.js"));
global.obscure('global'); global.obscure('global');
global.mixin("scripts/render.js"); global.mixin("scripts/render");
global.mixin("scripts/debug.js"); global.mixin("scripts/debug");
var frame_t = profile.secs(profile.now()); var frame_t = profile.secs(profile.now());
var phys_step = 1/60; var phys_step = 1/60;
@ -162,7 +173,11 @@ var timescale = 1;
var gggstart = game.engine_start; var gggstart = game.engine_start;
game.engine_start = function(s) { game.engine_start = function(s) {
gggstart(function() { world_start(); s(); }, process); gggstart(function() {
world_start();
go_init();
s();
}, process);
} }
function process() function process()
@ -290,11 +305,11 @@ prosperon.quit = function(){
console.warn(debug.log.time[i].map(x=>profile.ms(x))); console.warn(debug.log.time[i].map(x=>profile.ms(x)));
}; };
global.mixin("scripts/input.js"); global.mixin("scripts/input");
global.mixin("scripts/std.js"); global.mixin("scripts/std");
global.mixin("scripts/diff.js"); global.mixin("scripts/diff");
global.mixin("scripts/color.js"); global.mixin("scripts/color");
global.mixin("scripts/gui.js"); global.mixin("scripts/gui");
var timer = { var timer = {
update(dt) { update(dt) {
@ -322,10 +337,10 @@ var timer = {
}, },
}; };
global.mixin("scripts/tween.js"); global.mixin("scripts/tween");
global.mixin("scripts/physics.js"); global.mixin("scripts/physics");
global.mixin("scripts/ai.js"); global.mixin("scripts/ai");
global.mixin("scripts/geometry.js"); global.mixin("scripts/geometry");
/* /*
Factory for creating registries. Register one with 'X.register', Factory for creating registries. Register one with 'X.register',
@ -414,8 +429,8 @@ window.world2screen = function(worldpos) {
window.set_icon.doc = "Set the icon of the window using the PNG image at path."; window.set_icon.doc = "Set the icon of the window using the PNG image at path.";
global.mixin("scripts/spline.js"); global.mixin("scripts/spline");
global.mixin("scripts/components.js"); global.mixin("scripts/components");
window.doc = {}; window.doc = {};
window.doc.width = "Width of the game window."; window.doc.width = "Width of the game window.";
@ -424,8 +439,8 @@ window.doc.dimensions = "Window width and height packaged in an array [width,hei
window.doc.title = "Name in the title bar of the window."; window.doc.title = "Name in the title bar of the window.";
window.doc.boundingbox = "Boundingbox of the window, with top and right being its height and width."; window.doc.boundingbox = "Boundingbox of the window, with top and right being its height and width.";
global.mixin("scripts/actor.js"); global.mixin("scripts/actor");
global.mixin("scripts/entity.js"); global.mixin("scripts/entity");
function world_start() { function world_start() {
globalThis.world = os.make_gameobject(); globalThis.world = os.make_gameobject();
@ -439,7 +454,7 @@ function world_start() {
game.cam = world; game.cam = world;
} }
global.mixin("scripts/physics.js"); global.mixin("scripts/physics");
window.title = `Prosperon v${prosperon.version}`; window.title = `Prosperon v${prosperon.version}`;
window.size = [500,500]; window.size = [500,500];

View file

@ -296,7 +296,7 @@ var gameobject = {
} }
if (ent.ur === 'script') if (ent.ur === 'script')
eval_env(io.slurp(text), ent, ent.ur); use(text, ent);
else else
apply_ur(ent.ur, ent); apply_ur(ent.ur, ent);
@ -616,16 +616,17 @@ var gameobject = {
}, },
} }
var gop = os.make_gameobject().__proto__; function go_init() {
Object.mixin(gop, gameobject); var gop = os.make_gameobject().__proto__;
var gsync = gop.sync; Object.mixin(gop, gameobject);
gop.sync = function() { var gsync = gop.sync;
gsync.call(this); gop.sync = function() {
this.components.forEach(function(x) { x.sync?.(); }); gsync.call(this);
this.objects.forEach(function(x) { x.sync(); }); this.components.forEach(function(x) { x.sync?.(); });
this.objects.forEach(function(x) { x.sync(); });
}
} }
gameobject.spawn.doc = `Spawn an entity of type 'ur' on this entity. Returns the spawned entity.`; gameobject.spawn.doc = `Spawn an entity of type 'ur' on this entity. Returns the spawned entity.`;
gameobject.doc = { gameobject.doc = {
@ -720,7 +721,7 @@ function apply_ur(u, e) {
if (topur.text) { if (topur.text) {
var script = Resources.replstrs(topur.text); var script = Resources.replstrs(topur.text);
eval_env(script, e, topur.text); use(topur.text, e, script);
} }
if (topur.data) { if (topur.data) {
@ -780,3 +781,5 @@ game.loadurs = function() {
name: "empty" name: "empty"
}; };
}; };
return { go_init }

View file

@ -39,30 +39,6 @@ os.prefpath = function() {
var projectfile = ".prosperon/project.json"; var projectfile = ".prosperon/project.json";
var Resources = {};
Resources.scripts = ["jso", "js"];
Resources.images = ["png", "gif", "jpg", "jpeg"];
Resources.sounds = ["wav", 'flac', 'mp3', "qoa"];
Resources.scripts = "js";
Resources.is_image = function(path) {
var ext = path.ext();
return Resources.images.any(x => x === ext);
}
function find_ext(file, ext)
{
if (io.exists(file)) return file;
for (var e of ext) {
var nf = `${file}.${e}`;
if (io.exists(nf)) return nf;
}
return;
}
Resources.find_image = function(file) { return find_ext(file,Resources.images); }
Resources.find_sound = function(file) { return find_ext(file,Resources.sounds); }
Resources.find_script = function(file) { return find_ext(file,Resources.scripts); }
Resources.is_sound = function(path) { Resources.is_sound = function(path) {
var ext = path.ext(); var ext = path.ext();
return Resources.sounds.any(x => x === ext); return Resources.sounds.any(x => x === ext);
@ -89,6 +65,7 @@ Resources.gif.frames = function(path) { return render.gif_frames(path); }
Resources.replpath = function(str, path) Resources.replpath = function(str, path)
{ {
if (!str) return str;
if (str[0] === "/") if (str[0] === "/")
return str.rm(0); return str.rm(0);
@ -421,7 +398,7 @@ Cmdline.register_order("api", function(obj) {
return; return;
} }
load("scripts/editor.js"); use("scripts/editor.js");
var api = debug.api.print_doc(obj[0]); var api = debug.api.print_doc(obj[0]);
if (!api) if (!api)
return; return;
@ -429,15 +406,8 @@ Cmdline.register_order("api", function(obj) {
say(api); say(api);
}, "Print the API for an object as markdown. Give it a file to save the output to.", "OBJECT"); }, "Print the API for an object as markdown. Give it a file to save the output to.", "OBJECT");
Cmdline.register_order("compile", function(argv) {
for (var file of argv) {
var comp = io.compile(file);
io.slurpwrite(file + "c", comp);
}
}, "Compile one or more provided files into bytecode.", "FILE ...");
Cmdline.register_order("input", function(pawn) { Cmdline.register_order("input", function(pawn) {
load("scripts/editor.js"); use("scripts/editor.js");
say(`## Input for ${pawn}`); say(`## Input for ${pawn}`);
eval(`say(input.print_md_kbm(${pawn}));`); eval(`say(input.print_md_kbm(${pawn}));`);
}, "Print input documentation for a given object as markdown. Give it a file to save the output to", "OBJECT ?FILE?"); }, "Print input documentation for a given object as markdown. Give it a file to save the output to", "OBJECT ?FILE?");
@ -449,17 +419,7 @@ Cmdline.register_order("run", function(script) {
return; return;
} }
if (io.exists(script)) say(use(script));
try {
if (script.endswith("c"))
io.run_bytecode(script);
else
load(script);
} catch(e) { }
else {
var ret = eval(script);
if (ret) say(ret);
}
}, "Run a given script. SCRIPT can be the script itself, or a file containing the script", "SCRIPT"); }, "Run a given script. SCRIPT can be the script itself, or a file containing the script", "SCRIPT");
Cmdline.orders.script = Cmdline.orders.run; Cmdline.orders.script = Cmdline.orders.run;
@ -515,7 +475,6 @@ function cmd_args(cmdargs)
Cmdline.orders[cmds[0]](cmds.slice(1)); Cmdline.orders[cmds[0]](cmds.slice(1));
} }
Cmdline.register_order("clean", function(argv) { Cmdline.register_order("clean", function(argv) {
say("Cleaning not implemented."); say("Cleaning not implemented.");
}, "Clean up a given object file.", "JSON ..."); }, "Clean up a given object file.", "JSON ...");

View file

@ -40,8 +40,11 @@ int stdout_lvl = LOG_ERROR;
void log_init() void log_init()
{ {
#ifndef NDEBUG #ifndef NDEBUG
if (!fexists(".prosperon")) if (!fexists(".prosperon")) {
logout = writeout = dump = stdout; logout = tmpfile();
dump = tmpfile();
writeout = stdout;
}
else { else {
logout = fopen(".prosperon/log.txt", "w"); logout = fopen(".prosperon/log.txt", "w");
writeout = fopen(".prosperon/transcript.txt", "w"); writeout = fopen(".prosperon/transcript.txt", "w");
@ -98,7 +101,6 @@ void log_print(const char *str)
#ifndef NDEBUG #ifndef NDEBUG
fprintf(writeout, str); fprintf(writeout, str);
#endif #endif
printf(str);
fflush(stdout); fflush(stdout);
} }

View file

@ -748,8 +748,7 @@ JSValue js_os_sys(JSContext *js, JSValue this, int argc, JSValue *argv)
JSC_CCALL(os_quit, quit();) JSC_CCALL(os_quit, quit();)
JSC_CCALL(os_reindex_static, cpSpaceReindexStatic(space)); JSC_CCALL(os_reindex_static, cpSpaceReindexStatic(space));
JSC_CCALL(os_gc, script_gc()); JSC_CCALL(os_gc, script_gc());
JSC_SSCALL(os_eval_env, ret = eval_script_env(str, argv[2], str2)) JSC_SSCALL(os_eval, ret = script_eval(str, str2))
JSC_SCALL(os_capture, capture_screen(js2number(argv[1]), js2number(argv[2]), js2number(argv[4]), js2number(argv[5]), str)) JSC_SCALL(os_capture, capture_screen(js2number(argv[1]), js2number(argv[2]), js2number(argv[4]), js2number(argv[5]), str))
JSC_CCALL(os_sprite, JSC_CCALL(os_sprite,
@ -807,7 +806,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os, reindex_static, 0), MIST_FUNC_DEF(os, reindex_static, 0),
MIST_FUNC_DEF(os, gc, 0), MIST_FUNC_DEF(os, gc, 0),
MIST_FUNC_DEF(os, capture, 5), MIST_FUNC_DEF(os, capture, 5),
MIST_FUNC_DEF(os, eval_env, 3), MIST_FUNC_DEF(os, eval, 2),
MIST_FUNC_DEF(os, make_gameobject, 0), MIST_FUNC_DEF(os, make_gameobject, 0),
MIST_FUNC_DEF(os, make_circle2d, 1), MIST_FUNC_DEF(os, make_circle2d, 1),
MIST_FUNC_DEF(os, make_poly2d, 1), MIST_FUNC_DEF(os, make_poly2d, 1),
@ -1101,26 +1100,6 @@ JSValue js_io_chmod(JSContext *js, JSValue this, int argc, JSValue *argv)
JSC_SCALL(io_save_qoa, save_qoa(str)) JSC_SCALL(io_save_qoa, save_qoa(str))
JSValue js_io_compile(JSContext *js, JSValue this, int argc, JSValue *argv) {
size_t len;
char *str = js2str(argv[0]);
void *d = script_compile(str, &len);
JSValue ret = JS_NewArrayBufferCopy(js,d,len);
JS_FreeCString(js,str);
free(d);
return ret;
}
JSValue js_io_run_bytecode(JSContext *js, JSValue this, int argc, JSValue *argv) {
size_t len;
char *str = js2str(argv[0]);
void *d = slurp_file(str, &len);
JSValue ret = script_run_bytecode(d, len);
JS_FreeCString(js,str);
free(d);
return ret;
}
JSC_SCALL(io_pack_engine, pack_engine(str)) JSC_SCALL(io_pack_engine, pack_engine(str))
static const JSCFunctionListEntry js_io_funcs[] = { static const JSCFunctionListEntry js_io_funcs[] = {
@ -1136,7 +1115,7 @@ static const JSCFunctionListEntry js_io_funcs[] = {
MIST_FUNC_DEF(io, slurpbytes, 1), MIST_FUNC_DEF(io, slurpbytes, 1),
MIST_FUNC_DEF(io, slurpwrite, 2), MIST_FUNC_DEF(io, slurpwrite, 2),
MIST_FUNC_DEF(io, save_qoa,1), MIST_FUNC_DEF(io, save_qoa,1),
MIST_FUNC_DEF(io, pack_engine, 1) MIST_FUNC_DEF(io, pack_engine, 1),
}; };
JSC_CCALL(debug_draw_gameobject, gameobject_draw_debug(js2gameobject(argv[0]));) JSC_CCALL(debug_draw_gameobject, gameobject_draw_debug(js2gameobject(argv[0]));)
@ -1580,6 +1559,8 @@ void ffi_load() {
QJSCLASSPREP(ptr); QJSCLASSPREP(ptr);
QJSGLOBALCLASS(os);
QJSCLASSPREP_FUNCS(gameobject); QJSCLASSPREP_FUNCS(gameobject);
QJSCLASSPREP_FUNCS(dsp_node); QJSCLASSPREP_FUNCS(dsp_node);
QJSCLASSPREP_FUNCS(emitter); QJSCLASSPREP_FUNCS(emitter);
@ -1591,7 +1572,6 @@ void ffi_load() {
QJSCLASSPREP_FUNCS(window); QJSCLASSPREP_FUNCS(window);
QJSCLASSPREP_FUNCS(drawmodel); QJSCLASSPREP_FUNCS(drawmodel);
QJSGLOBALCLASS(os);
QJSGLOBALCLASS(nota); QJSGLOBALCLASS(nota);
QJSGLOBALCLASS(input); QJSGLOBALCLASS(input);
QJSGLOBALCLASS(io); QJSGLOBALCLASS(io);

View file

@ -23,7 +23,7 @@ void script_startup() {
size_t len; size_t len;
char *eng = slurp_text("scripts/engine.js", &len); char *eng = slurp_text("scripts/engine.js", &len);
eval_script_env("scripts/engine.js", JS_GetGlobalObject(js), eng); script_eval("scripts/engine.js", eng);
free(eng); free(eng);
} }
@ -39,25 +39,6 @@ void script_stop()
void script_gc() { JS_RunGC(rt); } void script_gc() { JS_RunGC(rt); }
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);
free(script);
uint8_t *out = JS_WriteObject(js, len, obj, JS_WRITE_OBJ_BYTECODE);
JS_FreeValue(js,obj);
return out;
}
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);
return ret;
}
void js_stacktrace() { void js_stacktrace() {
#ifndef NDEBUG #ifndef NDEBUG
script_evalf("console.stack();"); script_evalf("console.stack();");
@ -77,11 +58,11 @@ void script_evalf(const char *format, ...)
JS_FreeValue(js,obj); JS_FreeValue(js,obj);
} }
JSValue eval_script_env(const char *file, JSValue env, const char *script) JSValue script_eval(const char *file, const char *script)
{ {
JSValue v = JS_EvalThis(js, env, script, strlen(script), file, JS_EVAL_FLAGS); JSValue v = JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAGS | JS_EVAL_FLAG_COMPILE_ONLY);
js_print_exception(v); js_print_exception(v);
return v; return JS_EvalFunction(js, v);
} }
void script_call_sym(JSValue sym, int argc, JSValue *argv) { void script_call_sym(JSValue sym, int argc, JSValue *argv) {

View file

@ -20,13 +20,10 @@ void out_memusage(const char *f);
void js_stacktrace(); void js_stacktrace();
void script_evalf(const char *format, ...); void script_evalf(const char *format, ...);
JSValue eval_script_env(const char *file, JSValue env, const char *script); JSValue script_eval(const char *file, const char *script);
void script_call_sym(JSValue sym, int argc, JSValue *argv); void script_call_sym(JSValue sym, int argc, JSValue *argv);
void script_gc(); void script_gc();
JSValue script_run_bytecode(uint8_t *code, size_t len);
uint8_t *script_compile(const char *file, size_t *len);
#endif #endif

View file

@ -58,6 +58,7 @@ static JSValue c_process_fn;
void c_init() { void c_init() {
mainwin.start = 1; mainwin.start = 1;
window_resize(sapp_width(), sapp_height()); window_resize(sapp_width(), sapp_height());
phys2d_init();
render_init(); render_init();
set_icon("icons/moon.gif"); set_icon("icons/moon.gif");
particle_init(); particle_init();
@ -201,7 +202,7 @@ int main(int argc, char **argv) {
signal(SIGABRT, seghandle); signal(SIGABRT, seghandle);
signal(SIGFPE, seghandle); signal(SIGFPE, seghandle);
#endif #endif
phys2d_init();
resources_init(); resources_init();
stm_setup(); /* time */ stm_setup(); /* time */