Lazy module loading: compiler loads on demand, playground page

- load-library! native: islands can declare module dependencies at
  hydration time, triggering on-demand .sxbc loading
- JIT compiler lazy-load: compiler.sxbc loads via setTimeout after boot,
  eliminating "JIT: compiler not loaded" errors
- _import_hook on sx_types: infrastructure for hosts to resolve import
  suspensions inside eval_expr (server wiring deferred to Step 8)
- Playground page (/sx/(tools.(playground))): REPL island that lazy-loads
  the compiler module when navigated to — demonstrates the full
  lazy loading pipeline

Known remaining issues:
- SPA navigation broken for pages using let-match (orchestration.sx,
  router.sx) — bytecode compiler doesn't handle let-match special form
- Server-side "IO suspension in non-IO context" during http_load_files —
  needs cek_run import handling (deferred to Step 8)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-04 20:34:08 +00:00
parent 4baed1853c
commit aee4770a6a
4 changed files with 90 additions and 7 deletions

View File

@@ -19,9 +19,16 @@
function boot(K) {
// ================================================================
// 8 FFI Host Primitives
// FFI Host Primitives
// ================================================================
// Lazy module loading — islands/components call this to declare dependencies
K.registerNative("load-library!", function(args) {
var name = args[0];
if (!name) return false;
return __sxLoadLibrary(name) || false;
});
K.registerNative("host-global", function(args) {
var name = args[0];
if (typeof globalThis !== "undefined" && name in globalThis) return globalThis[name];
@@ -463,13 +470,16 @@
loadLibrary(info.deps[i], loading);
}
// Mark as loaded BEFORE executing — self-imports (define-library re-exports)
// will see it as already loaded and skip rather than infinite-looping.
_loadedLibs[name] = true;
// Load this module
var ok = loadBytecodeFile("sx/" + info.file);
if (!ok) {
var sxFile = info.file.replace(/\.sxbc$/, '.sx');
ok = loadSxFile("sx/" + sxFile);
}
_loadedLibs[name] = true;
return !!ok;
}
@@ -614,8 +624,14 @@
var _doInit = function() {
loadWebStack();
Sx.init();
// Enable JIT after all boot code has run
setTimeout(function() { K.eval('(enable-jit!)'); }, 0);
// Enable JIT after all boot code has run.
// Lazy-load the compiler first — JIT needs it to compile functions.
setTimeout(function() {
if (K.beginModuleLoad) K.beginModuleLoad();
loadLibrary("sx compiler", {});
if (K.endModuleLoad) K.endModuleLoad();
K.eval('(enable-jit!)');
}, 0);
};
if (document.readyState === "loading") {

View File

@@ -255,6 +255,10 @@ let _env_bind_hook : (env -> string -> value -> unit) option ref = ref None
Used by browser kernel to sync mutations back to global_env. *)
let _vm_global_set_hook : (string -> value -> unit) option ref = ref None
(* Optional hook: called by cek_run on import suspension.
If set, the hook loads the library and returns true; cek_run then resumes. *)
let _import_hook : (value -> bool) option ref = ref None
let env_bind env name v =
Hashtbl.replace env.bindings (intern name) v;
(match !_env_bind_hook with Some f -> f env name v | None -> ());