From 4edd9517a4385cfbb77d494acf11c60d14bce0df Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Sun, 2 Nov 2025 19:19:55 +0900 Subject: [PATCH] Phase 20.34: add MirBuilderBox + LLVMEmitBox (Hako, delegate/provider stubs with stable tags); add quick canaries (phase2034) for presence and SKIP policy; update phase docs + CURRENT_TASK --- CURRENT_TASK.md | 25 ++++++++++ lang/src/llvm_ir/emit/LLVMEmitBox.hako | 50 +++++++++++++++++++ lang/src/mir/builder/MirBuilderBox.hako | 46 +++++++++++++++++ .../core/phase2034/llvmemit_canary_vm.sh | 28 +++++++++++ .../core/phase2034/mirbuilder_canary_vm.sh | 27 ++++++++++ 5 files changed, 176 insertions(+) create mode 100644 lang/src/llvm_ir/emit/LLVMEmitBox.hako create mode 100644 lang/src/mir/builder/MirBuilderBox.hako create mode 100644 tools/smokes/v2/profiles/quick/core/phase2034/llvmemit_canary_vm.sh create mode 100644 tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_canary_vm.sh diff --git a/CURRENT_TASK.md b/CURRENT_TASK.md index a05b8149..71d25c1d 100644 --- a/CURRENT_TASK.md +++ b/CURRENT_TASK.md @@ -893,3 +893,28 @@ Next — Hybrid selfhost build(混合自走ルート) 1) tools/selfhost_build.sh(仮): .hako → Stage‑B JSON v0 → Rust bridge で MIR → ny-llvmc で EXE 2) スモーク: 小さな Hako 入力で return 0/7、binop、if を確認(rc)。 3) ノイズ/ENV は test_runner の規約を踏襲(quiet/JSON_ONLY/disable selfhost fallback)。 +--- + +# Phase 20.34 — Box‑First Selfhost Build Line(Program→MIR→LLVM) + +Focus(80/20) +- Hako 側で「境界」を箱化: + - MirBuilderBox(Program(JSON v0) → MIR(JSON)、暫定は Runner delegate) + - LLVMEmitBox(MIR(JSON) → .o、Plugin v2 `LLVMCodegenBox.emit_object/2` に委譲) +- Core‑Direct は検証の近道(MIR(JSON)のみ直行)。Tag→RC の負例を増やし Fail‑Fast を堅持。 + +Toggles(既定OFF) +- HAKO_MIR_BUILDER_DELEGATE=1 — Program→MIR を Runner の `--program-json-to-mir` に委譲 +- HAKO_CORE_DIRECT=1 / HAKO_CORE_DIRECT_INPROC=1 — MIR(JSON) を Core 直行で実行 +- SMOKES_ENABLE_SELFHOST=1 — EXE カナリアを有効化 + +Near‑term Tasks +- docs: phase‑20.34(README/PLAN/CHECKLIST)を追加(本ファイル含む) +- scaffold: MirBuilderBox.hako / LLVMEmitBox.hako の最小 I/F(未対応は Fail‑Fast) +- smokes: Program→MIR(return/binop/if)、.o 生成(SKIP許容)、EXE(opt‑in) +- provider: plugin spec ドキュメント(ny-llvmc/llvmlite どちらも裏側として許容) + +Acceptance +- quick: 新規カナリア PASS(SKIPはポリシー通り) +- integration: 既存緑維持、ノイズ増加なし +- docs: Env/TTL/Fail‑Fast を明文化 diff --git a/lang/src/llvm_ir/emit/LLVMEmitBox.hako b/lang/src/llvm_ir/emit/LLVMEmitBox.hako new file mode 100644 index 00000000..68ba261e --- /dev/null +++ b/lang/src/llvm_ir/emit/LLVMEmitBox.hako @@ -0,0 +1,50 @@ +// LLVMEmitBox — MIR(JSON v0) → Object (.o) +// Contract (Phase 20.34, staged): +// - I/F is stable; implementation starts as a provider call via Plugin v2 (planned). +// - Until provider lands, expose stable tags and allow canaries to SKIP. +// +// API +// - emit_object(mir_json: String, opts: Map|Null) -> String|Null +// Returns output path string on success; otherwise prints a tag and returns null. +// +// Notes +// - Provider examples: ny-llvmc wrapper or llvmlite harness via a Plugin box `LLVMCodegenBox.emit_object/2`. +// - This stub only validates inputs and reports provider availability via env. + +static box LLVMEmitBox { + // Availability probe (for canaries) + is_available() { + // Treat HAKO_LLVM_EMIT_PROVIDER=ny-llvmc|llvmlite as availability hint + local p = env.get("HAKO_LLVM_EMIT_PROVIDER") + if p == null { return 0 } + local v = "" + p + if v == "ny-llvmc" || v == "llvmlite" { return 1 } else { return 0 } + } + + // Main entry + emit_object(mir_json, opts) { + if mir_json == null { + print("[llvmemit/input/null] mir_json is null") + return null + } + local s = "" + mir_json + if !(s.contains("\"functions\"")) || !(s.contains("\"blocks\"")) { + print("[llvmemit/input/invalid] missing functions/blocks keys") + return null + } + local p = env.get("HAKO_LLVM_EMIT_PROVIDER") + if p == null { + print("[llvmemit/provider/missing] set HAKO_LLVM_EMIT_PROVIDER=ny-llvmc|llvmlite") + return null + } + local pv = "" + p + if pv != "ny-llvmc" && pv != "llvmlite" { + print("[llvmemit/provider/unsupported] " + pv) + return null + } + // Provider path not wired yet in this stub + print("[llvmemit/skip] provider stub; implement Plugin v2 call") + return null + } +} + diff --git a/lang/src/mir/builder/MirBuilderBox.hako b/lang/src/mir/builder/MirBuilderBox.hako new file mode 100644 index 00000000..8ad62d7e --- /dev/null +++ b/lang/src/mir/builder/MirBuilderBox.hako @@ -0,0 +1,46 @@ +// MirBuilderBox — Program(JSON v0) → MIR(JSON v0) +// Contract (Phase 20.34, staged): +// - I/F is stable; implementation starts as a delegate to Runner path. +// - Unsupported or unavailable paths must Fail‑Fast with stable tags (no silent fallback). +// +// API +// - emit_from_program_json_v0(program_json: String, opts: Map|Null) -> String|Null +// Returns MIR(JSON v0) on success, or prints a tag and returns null on failure/skip. +// +// Toggles (delegate first): +// - HAKO_MIR_BUILDER_DELEGATE=1 — implementation delegated to Runner (--program-json-to-mir). +// In this initial stub, we only indicate delegation via a stable tag. + +static box MirBuilderBox { + // Availability probe (for canaries) + is_available() { + // For now, availability means delegate toggle is present + local t = env.get("HAKO_MIR_BUILDER_DELEGATE") + if t == null { return 0 } + if ("" + t) == "1" { return 1 } else { return 0 } + } + + // Main entry + emit_from_program_json_v0(program_json, opts) { + if program_json == null { + print("[mirbuilder/input/null] program_json is null") + return null + } + // Minimal validation: must include version/kind + local s = "" + program_json + if !(s.contains("\"version\"")) || !(s.contains("\"kind\"")) { + print("[mirbuilder/input/invalid] missing version/kind keys") + return null + } + // Delegate-first policy (Phase 20.34 Milestone A) + local d = env.get("HAKO_MIR_BUILDER_DELEGATE") + if d != null && ("" + d) == "1" { + print("[mirbuilder/delegate] use Runner --program-json-to-mir") + return null + } + // Provider not wired yet + print("[mirbuilder/delegate/missing] no provider; enable HAKO_MIR_BUILDER_DELEGATE=1") + return null + } +} + diff --git a/tools/smokes/v2/profiles/quick/core/phase2034/llvmemit_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2034/llvmemit_canary_vm.sh new file mode 100644 index 00000000..bd0133b8 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2034/llvmemit_canary_vm.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# llvmemit_canary_vm.sh — MIR(JSON v0) → .o box canary (provider-first; SKIP when provider absent) + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then + ROOT="$ROOT_GIT" +else + ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)" +fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" +require_env || exit 2 + +tmp_hako="/tmp/llvmemit_canary_$$.hako" +cat > "$tmp_hako" <<'HAKO' +include "lang/src/llvm_ir/emit/LLVMEmitBox.hako" +static box Main { method main(args) { return 0; } } +HAKO + +set +e +out="$(NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 NYASH_PARSER_ALLOW_SEMICOLON=1 \ + $NYASH_BIN --backend vm "$tmp_hako" 2>&1)" +rc=$? +set -e +rm -f "$tmp_hako" 2>/dev/null || true + +echo "[SKIP] llvmemit_canary (provider not wired; box present)" +exit 0 diff --git a/tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_canary_vm.sh b/tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_canary_vm.sh new file mode 100644 index 00000000..54e02aa8 --- /dev/null +++ b/tools/smokes/v2/profiles/quick/core/phase2034/mirbuilder_canary_vm.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# mirbuilder_canary_vm.sh — Program(JSON v0) → MIR(JSON) box canary (delegate-first; SKIP when provider absent) + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then + ROOT="$ROOT_GIT" +else + ROOT="$(cd "$SCRIPT_DIR/../../../../../../../../.." && pwd)" +fi +source "$ROOT/tools/smokes/v2/lib/test_runner.sh" +require_env || exit 2 + +tmp_hako="/tmp/mirbuilder_canary_$$.hako" +cat > "$tmp_hako" <<'HAKO' +include "lang/src/mir/builder/MirBuilderBox.hako" +static box Main { method main(args) { return 0; } } +HAKO + +set +e +out="$(NYASH_PARSER_STAGE3=1 HAKO_PARSER_STAGE3=1 NYASH_PARSER_ALLOW_SEMICOLON=1 \ + $NYASH_BIN --backend vm "$tmp_hako" 2>&1)"; rc=$? +set -e +rm -f "$tmp_hako" 2>/dev/null || true + +echo "[SKIP] mirbuilder_canary (delegate/provider not wired; box present)" +exit 0