✨ Phase 3.1-3.2実装完了 - build_indirect_call_expressionでCallTarget::Value使用 - print関数をcall_global print()として統一 - build_function_callでemit_unified_call使用 - ExternCall(env.console.log)→Callee::Global(print)完全移行 🏗️ MIR統一基盤構築 - src/mir/definitions/call_unified.rs: 統一定義(297行) - emit_unified_call()と便利メソッド3種実装 - NYASH_MIR_UNIFIED_CALL=1で段階移行制御 - VM実行器でCallee対応実装済み 📊 進捗状況(26%削減見込み) - Phase 1-2: ✅ 基盤構築完了 - Phase 3.1-3.2: ✅ 基本関数統一完了 - Phase 3.3: 🔄 BoxCall統一中 - Phase 4: 📅 Python LLVM(最優先・63%削減) - Phase 5: 📅 PyVM/VM統一 📚 ドキュメント更新 - CLAUDE.md: テストスクリプト参考集追加 - CURRENT_TASK.md: Phase 3進捗更新 - python-llvm-priority-rationale.md: 優先順位戦略文書化 - mir-call-unification-master-plan.md: スケジュール最新化 🎯 6種類→1種類: Call/BoxCall/PluginInvoke/ExternCall/NewBox/NewClosure → MirCall統一へ 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
159 lines
4.7 KiB
Plaintext
159 lines
4.7 KiB
Plaintext
// Selfhost Compiler MVP (Phase 15.3)
|
||
// Reads tmp/ny_parser_input.ny and prints a minimal JSON v0 program.
|
||
// Components are split under boxes/ and included here.
|
||
|
||
// Prefer using for module declaration (Runner strips and registers)
|
||
using "apps/selfhost-compiler/boxes/debug_box.nyash" as DebugBoxMod
|
||
using "apps/selfhost-compiler/boxes/parser_box.nyash" as ParserBoxMod
|
||
using "apps/selfhost-compiler/boxes/emitter_box.nyash" as EmitterBoxMod
|
||
using "apps/selfhost-compiler/boxes/mir_emitter_box.nyash" as MirEmitterBoxMod
|
||
|
||
// Transitional: keep include for Phase-15 compatibility
|
||
include "apps/selfhost-compiler/boxes/debug_box.nyash"
|
||
include "apps/selfhost-compiler/boxes/parser_box.nyash"
|
||
include "apps/selfhost-compiler/boxes/emitter_box.nyash"
|
||
include "apps/selfhost-compiler/boxes/mir_emitter_box.nyash"
|
||
// Prepass libs (ScopeBox/LoopForm)
|
||
include "apps/lib/scopebox_inject.nyash"
|
||
include "apps/lib/loopform_normalize.nyash"
|
||
|
||
static box Main {
|
||
// ---- IO helper ----
|
||
read_all(path) {
|
||
local fb = new FileBox()
|
||
fb.open(path, "r")
|
||
local s = fb.read()
|
||
fb.close()
|
||
if s == null { return "return 1+2*3" }
|
||
return s
|
||
}
|
||
|
||
// ---- JSON helpers ----
|
||
esc_json(s) {
|
||
local out = ""
|
||
local i = 0
|
||
local n = s.length()
|
||
loop(i < n) {
|
||
local ch = s.substring(i, i+1)
|
||
if ch == "\\" { out = out + "\\\\" } else {
|
||
if ch == "\"" { out = out + "\\\"" } else { out = out + ch }
|
||
}
|
||
i = i + 1
|
||
}
|
||
return out
|
||
}
|
||
|
||
// Parser delegation
|
||
parse_program(src, stage3_flag) {
|
||
local parser = new ParserBox()
|
||
if stage3_flag == 1 { parser.stage3_enable(1) }
|
||
// Collect using metadata (no-op acceptance in Stage‑15)
|
||
parser.extract_usings(src)
|
||
me._usings = parser.get_usings_json()
|
||
return parser.parse_program2(src)
|
||
}
|
||
|
||
main(args) {
|
||
// Debug setup
|
||
me.dbg = new DebugBox()
|
||
me.dbg.set_enabled(0)
|
||
|
||
// Source selection (EXE-first friendly)
|
||
// - default: safe constant
|
||
// - positional arg: treat as input file path
|
||
// - --read-tmp: use tmp/ny_parser_input.ny (requires FileBox plugin)
|
||
local src = "return 1+2*3"
|
||
local read_tmp = 0
|
||
local input_path = null
|
||
local stage3_mode = 0
|
||
if args != null {
|
||
local alen = args.length()
|
||
local i = 0
|
||
loop(i < alen) {
|
||
local a = args.get(i)
|
||
if a == "--read-tmp" {
|
||
read_tmp = 1
|
||
} else {
|
||
if a == "--min-json" {
|
||
/* handled later */
|
||
} else {
|
||
if a == "--stage3" {
|
||
stage3_mode = 1
|
||
} else {
|
||
if input_path == null { input_path = a }
|
||
}
|
||
}
|
||
}
|
||
i = i + 1
|
||
}
|
||
}
|
||
if input_path != null {
|
||
// Prefer explicit file when provided (requires FileBox plugin)
|
||
local s1 = me.read_all(input_path)
|
||
if s1 != null { src = s1 }
|
||
} else {
|
||
if read_tmp == 1 {
|
||
// Optional: read tmp/ny_parser_input.ny (requires FileBox plugin; do not use in CI)
|
||
local s2 = me.read_all("tmp/ny_parser_input.ny")
|
||
if s2 != null { src = s2 }
|
||
}
|
||
}
|
||
|
||
// Gate: minimal JSON when requested via script arg
|
||
local min_mode = 0
|
||
local emit_mir = 0
|
||
if args != null {
|
||
local alen = args.length()
|
||
local i = 0
|
||
loop(i < alen) {
|
||
local arg = args.get(i)
|
||
if arg == "--min-json" { min_mode = 1 }
|
||
if arg == "--emit-mir" { emit_mir = 1 }
|
||
i = i + 1
|
||
}
|
||
}
|
||
local json = null
|
||
local ast_json = null
|
||
if min_mode == 1 {
|
||
ast_json = "{\"version\":0,\"kind\":\"Program\",\"body\":[{\"type\":\"Return\",\"expr\":{\"type\":\"Int\",\"value\":0}}]}"
|
||
} else {
|
||
ast_json = me.parse_program(src, stage3_mode)
|
||
}
|
||
|
||
// Optional prepasses driven by CLI flags (mapped from env by runner)
|
||
local do_scopebox = 0
|
||
local do_loopform = 0
|
||
if args != null {
|
||
local alen3 = args.length()
|
||
local i3 = 0
|
||
loop(i3 < alen3) {
|
||
local a3 = args.get(i3)
|
||
if a3 == "--scopebox" { do_scopebox = 1 }
|
||
if a3 == "--loopform" { do_loopform = 1 }
|
||
i3 = i3 + 1
|
||
}
|
||
}
|
||
|
||
if emit_mir == 1 {
|
||
// Lower minimal AST to MIR JSON (Return(Int) only for MVP)
|
||
local mir = new MirEmitterBox()
|
||
local aj = ast_json
|
||
if do_scopebox == 1 { aj = new ScopeBoxInject().apply(aj) }
|
||
if do_loopform == 1 { aj = new LoopFormNormalize().apply(aj) }
|
||
json = mir.emit_mir_min(aj)
|
||
} else {
|
||
// Emit Stage‑1 JSON with metadata
|
||
local emitter = new EmitterBox()
|
||
local aj2 = ast_json
|
||
if do_scopebox == 1 { aj2 = new ScopeBoxInject().apply(aj2) }
|
||
if do_loopform == 1 { aj2 = new LoopFormNormalize().apply(aj2) }
|
||
json = emitter.emit_program(aj2, me._usings)
|
||
}
|
||
|
||
// Output JSON
|
||
local console = new ConsoleBox()
|
||
console.println(json)
|
||
return 0
|
||
}
|
||
}
|