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
This commit is contained in:
@ -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 を明文化
|
||||
|
||||
50
lang/src/llvm_ir/emit/LLVMEmitBox.hako
Normal file
50
lang/src/llvm_ir/emit/LLVMEmitBox.hako
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
46
lang/src/mir/builder/MirBuilderBox.hako
Normal file
46
lang/src/mir/builder/MirBuilderBox.hako
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
Reference in New Issue
Block a user