feat(phase21.5): selfhost CWD fix + loop executable semantics + diagnostics

## Task 1: Selfhost Child Process CWD Fix 
- Fix: try_selfhost_builder() now runs from repo root
- Implementation: (cd "$ROOT" && ... "$NYASH_BIN" ...)
- Benefit: nyash.toml using mappings are reliably loaded
- Location: tools/hakorune_emit_mir.sh:96-108
- Resolves: "using not found: 'hako.mir.builder.internal.*'" errors

## Task 2: Loop JSONFrag Executable Semantics 
- Upgrade: FORCE=1 now generates complete executable while-loop
- Structure: entry(0) → loop(1) → body(2) → exit(3)
- Semantics:
  - PHI node: i = {i0, entry} | {i_next, body}
  - Increment: i_next = i + 1
  - Backedge: body → loop
  - Exit: ret i (final loop variable value)
- Location: lang/src/mir/builder/internal/loop_opts_adapter_box.hako:24-44
- Expected: rc=10 (limit value) instead of structure-only validation

## Task 3: Enhanced Diagnostics 
- Added: HAKO_SELFHOST_TRACE=1 outputs comprehensive diagnostics
- Info: prog_json_len, tokens (Loop/Compare counts), cwd, nyash.toml status
- Example: [builder/selfhost-first:trace] prog_json_len=90 tokens=Loop:0,Compare:0 cwd=... nyash.toml=present
- Location: tools/hakorune_emit_mir.sh:87-100
- Benefit: One-line diagnosis of CWD/nyash.toml/using issues

## Task 4: nyash.toml Missing Entries 
- Added: hako.mir.builder.internal.builder_config mapping
- Added: hako.mir.builder.internal.loop_opts_adapter mapping
- Location: nyash.toml
- Benefit: Selfhost-first can resolve internal builder dependencies

## Implementation Principles
- 既定挙動不変 (Default unchanged, FORCE=1 guarded)
- Dev toggle controlled (TRACE=1, NO_DELEGATE=1)
- Minimal diff with clear rollback path
- CWD fix ensures stable using resolution
- Executable semantics enable proper EXE testing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-11 09:09:55 +09:00
parent 0d41970313
commit 2299da7663
3 changed files with 60 additions and 14 deletions

View File

@ -17,6 +17,41 @@ static box LoopOptsBox {
using selfhost.shared.mir.loopform as LoopFormBox
using selfhost.shared.common.string_helpers as StringHelpers
using "hako.mir.builder.internal.jsonfrag_normalizer" as JsonFragNormalizerBox
// Force toggle: always return JsonFrag (dev/test override)
if BuilderConfigBox.loop_force_jsonfrag_on() == 1 {
local limit = opts.get("limit"); if limit == null { limit = 0 }
local limit_s = "" + limit
// Minimal while-loop semantics (executable, not just structure):
// Block 0 (entry): i0=0, limit=N, jump to loop
// Block 1 (loop header): phi i={i0,0}|{i_next,2}, cmp i<limit, branch
// Block 2 (body): i_next = i+1, jump back to loop
// Block 3 (exit): ret i (final loop variable value)
// Value IDs: r1=i0(0), r2=limit(N), r3=phi(i), r4=cmp, r5=i_next, r10=const(1)
local mir = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"locals\":[],\"blocks\":[" +
"{\"id\":0,\"instructions\":[" +
"{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":0}}," +
"{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + limit_s + "}}," +
"{\"op\":\"jump\",\"target\":1}]}," +
"{\"id\":1,\"instructions\":[" +
"{\"op\":\"phi\",\"dst\":3,\"incoming\":[[1,0],[5,2]]}," +
"{\"op\":\"compare\",\"operation\":\"<\",\"lhs\":3,\"rhs\":2,\"dst\":4}," +
"{\"op\":\"branch\",\"cond\":4,\"then\":2,\"else\":3}]}," +
"{\"id\":2,\"instructions\":[" +
"{\"op\":\"const\",\"dst\":10,\"value\":{\"type\":\"i64\",\"value\":1}}," +
"{\"op\":\"binop\",\"operation\":\"+\",\"lhs\":3,\"rhs\":10,\"dst\":5}," +
"{\"op\":\"jump\",\"target\":1}]}," +
"{\"id\":3,\"instructions\":[" +
"{\"op\":\"ret\",\"value\":3}]}]}]}"
if BuilderConfigBox.trace_enabled() == 1 { print("[mirbuilder/loop_opts:force_jsonfrag:semantics:limit=" + limit_s + "]") }
if BuilderConfigBox.jsonfrag_normalize_on() == 1 { mir = JsonFragNormalizerBox.normalize_all(mir) }
local mode = BuilderConfigBox.loop_adapter_return_mode()
if mode == "map" {
local m = self.new_map()
m = self.put(m, "mir", mir)
return m
}
return mir
}
// Opt-in: minimal MIR(JSON) construction for structure validation
if BuilderConfigBox.loop_jsonfrag_on() == 1 {
// Read limit if present, else default to 0 (safe)