Fix HS browser activation: host-get function sentinel, runtime symbol shadow, lazy dep chain

Three bugs fixed:
1. host-get in sx-platform.js: return true for function-valued properties
   so dom-get-attr/dom-set-attr guards pass (functions can't cross WASM boundary)
2. hs-runtime.sx: renamed host-get→hs-host-get and dom-query→hs-dom-query to
   stop shadowing platform natives when loaded as .sx source
3. compile-modules.js: HS dependency chain (integration→runtime→compiler→parser→tokenizer)
   so lazy loading pulls in all deps. Non-library modules load as .sx source
   for CEK env visibility.

Result: 8/8 elements activate, hs-on attaches listeners. Click handler needs
IO suspension support (VmSuspended in sx_browser.ml) to fire — next step.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-09 20:50:10 +00:00
parent 7f273dc7c2
commit c6df054957
7 changed files with 86 additions and 27 deletions

View File

@@ -382,9 +382,16 @@ for (const file of FILES) {
const defines = extractDefines(src);
if (defines.length > 0) {
const key = file.replace(/\.sx$/, '');
// HS modules form a dependency chain — loading one loads all predecessors.
const HS_DEPS = {
'hs-parser': ['hs-tokenizer'],
'hs-compiler': ['hs-tokenizer', 'hs-parser'],
'hs-runtime': ['hs-tokenizer', 'hs-parser', 'hs-compiler'],
'hs-integration': ['hs-tokenizer', 'hs-parser', 'hs-compiler', 'hs-runtime'],
};
manifest[key] = {
file: sxbcFile,
deps: [],
deps: HS_DEPS[key] || [],
exports: defines,
};
}

View File

@@ -40,7 +40,12 @@
var obj = args[0], prop = args[1];
if (obj == null) return null;
var v = obj[prop];
return v === undefined ? null : v;
if (v === undefined) return null;
// Functions can't cross the WASM boundary — return true as a truthy
// sentinel so (host-get el "getAttribute") works as a guard.
// Use host-call to actually invoke the method.
if (typeof v === "function") return true;
return v;
});
K.registerNative("host-set!", function(args) {
@@ -474,9 +479,19 @@
// 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) {
// Load this module.
// Non-library modules (no space in name, e.g. "hs-runtime") use source
// loading so their defines go into the CEK global env — needed when
// eval-expr-cek evaluates compiled hyperscript at runtime.
var isLibrary = name.indexOf(' ') >= 0 || name === '_entry';
var ok;
if (isLibrary) {
ok = loadBytecodeFile("sx/" + info.file);
if (!ok) {
var sxFile = info.file.replace(/\.sxbc$/, '.sx');
ok = loadSxFile("sx/" + sxFile);
}
} else {
var sxFile = info.file.replace(/\.sxbc$/, '.sx');
ok = loadSxFile("sx/" + sxFile);
}