// bundle_resolver.hako — Stage‑B bundling resolver (Box‑first) static box BundleResolver { // Resolve and merge bundles. Returns merged prefix string or null on error. // Policy: // - Duplicate named modules are Fail‑Fast ([bundle/duplicate] Name) // - --require-mod Name must appear in named bundles ([bundle/missing] Name) // - Merge order: bundle-src* → bundle-mod* (in given order) resolve(bundle_srcs, bundle_names, bundle_mod_srcs, require_mods) { // Shallow recursion guard to prevent accidental self-recursion in Stage‑B bundler. { local depth = env.get("HAKO_STAGEB_BUNDLE_DEPTH") if depth != null && ("" + depth) != "0" { print("[stageb/recursion] BundleResolver.resolve recursion detected") return null } env.set("HAKO_STAGEB_BUNDLE_DEPTH", "1") } // Alias table via env: HAKO_BUNDLE_ALIAS_TABLE / NYASH_BUNDLE_ALIAS_TABLE // Format: entries separated by '|||', each entry as 'Name:code' local table = env.get("HAKO_BUNDLE_ALIAS_TABLE") if table == null || table == "" { table = env.get("NYASH_BUNDLE_ALIAS_TABLE") } if table != null && table != "" { local i = 0 loop(i < table.length()) { // find next delimiter or end local j = table.indexOf("|||", i) local seg = "" if j >= 0 { seg = table.substring(i, j) } else { seg = table.substring(i, table.length()) } if seg != "" { local pos = -1 local k = 0 loop(k < seg.length()) { if seg.substring(k,k+1) == ":" { pos = k break } k = k + 1 } if pos < 0 { print("[bundle/alias-table/bad] " + seg) return null } local name = seg.substring(0, pos) local code = seg.substring(pos+1, seg.length()) if name == "" || code == "" { print("[bundle/alias-table/bad] " + seg) return null } if bundle_names == null { bundle_names = new ArrayBox() } if bundle_mod_srcs == null { bundle_mod_srcs = new ArrayBox() } bundle_names.push(name) bundle_mod_srcs.push(code) } if j < 0 { break } i = j + 3 } } // Env alias injection (TTL, dev-only): HAKO_BUNDLE_ALIAS_ / NYASH_BUNDLE_ALIAS_ // If a required module is not provided via --bundle-mod, but an env alias // supplies its code, synthesize a named bundle entry before checks/merge. if require_mods != null { local i0 = 0; local rn0 = require_mods.length() loop(i0 < rn0) { local need = "" + require_mods.get(i0) local present = 0 if bundle_names != null { local j0 = 0; local bn0 = bundle_names.length() loop(j0 < bn0) { if ("" + bundle_names.get(j0)) == need { present = 1 break } j0 = j0 + 1 } } if present == 0 { local alias_key = "HAKO_BUNDLE_ALIAS_" + need local code = env.get(alias_key) if code == null || code == "" { code = env.get("NYASH_BUNDLE_ALIAS_" + need) } if code != null && code != "" { if bundle_names == null { bundle_names = new ArrayBox() } if bundle_mod_srcs == null { bundle_mod_srcs = new ArrayBox() } bundle_names.push(need) bundle_mod_srcs.push("" + code) } } i0 = i0 + 1 } } // Fail on duplicate names if bundle_names != null && bundle_names.length() > 1 { local i = 0; local n = bundle_names.length() loop(i < n) { local name_i = "" + bundle_names.get(i) local j = i + 1 loop(j < n) { if ("" + bundle_names.get(j)) == name_i { print("[bundle/duplicate] " + name_i) return null } j = j + 1 } i = i + 1 } } // Check required modules if require_mods != null && require_mods.length() > 0 { local idx = 0; local rn = require_mods.length() loop(idx < rn) { local need = "" + require_mods.get(idx) local found = 0 if bundle_names != null { local j = 0; local bn = bundle_names.length() loop(j < bn) { if ("" + bundle_names.get(j)) == need { found = 1 break } j = j + 1 } } if found == 0 { print("[bundle/missing] " + need) return null } idx = idx + 1 } } // Merge in order: bundle-src* → bundle-mod* local merged = "" if bundle_srcs != null { local i = 0; local m = bundle_srcs.length() loop(i < m) { merged = merged + bundle_srcs.get(i) + "\n" i = i + 1 } } if bundle_mod_srcs != null { local i2 = 0; local m2 = bundle_mod_srcs.length() loop(i2 < m2) { merged = merged + bundle_mod_srcs.get(i2) + "\n" i2 = i2 + 1 } } // Clear depth guard before returning env.set("HAKO_STAGEB_BUNDLE_DEPTH", "0") return merged } }