Phase 25.1b: Step2完了(FuncBodyBasicLowerBox導入)

Step2実装内容:
- FuncBodyBasicLowerBox導入(defs専用下請けモジュール)
- _try_lower_local_if_return実装(Local+単純if)
- _inline_local_ints実装(軽い正規化)
- minimal lowers統合(Return/BinOp/IfCompare/MethodArray系)

Fail-Fast体制確立:
- MirBuilderBox: defs_onlyでも必ずタグ出力
- [builder/selfhost-first:unsupported:defs_only]
- [builder/selfhost-first:unsupported:no_match]

Phase構造整備:
- Phase 25.1b README新設(Step0-3計画)
- Phase 25.2b README新設(次期計画)
- UsingResolverBox追加(using system対応準備)

スモークテスト:
- stage1_launcher_program_to_mir_canary_vm.sh追加

Next: Step3 LoopForm対応

🤖 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-15 22:32:13 +09:00
parent 6856922374
commit 7ca7f646de
31 changed files with 1670 additions and 323 deletions

View File

@ -29,13 +29,13 @@ static box HakoCli {
@cmd = "" + cmd_raw
if cmd == "run" {
return self.cmd_run(args)
return me.cmd_run(args)
} else if cmd == "build" {
return self.cmd_build(args)
return me.cmd_build(args)
} else if cmd == "emit" {
return self.cmd_emit(args)
return me.cmd_emit(args)
} else if cmd == "check" {
return self.cmd_check(args)
return me.cmd_check(args)
}
print("[hakorune] unknown command: " + cmd)
@ -63,7 +63,7 @@ static box HakoCli {
@sub_raw = args.get(1)
@sub = "" + sub_raw
if sub == "exe" {
return self.cmd_build_exe(args)
return me.cmd_build_exe(args)
}
print("[hakorune] build: unknown subcommand: " + sub)
@ -86,7 +86,7 @@ static box HakoCli {
@source_path = null
@i = 2
while i < argc {
loop(i < argc) {
@arg_raw = args.get(i)
@arg = "" + arg_raw
if arg == "-o" || arg == "--out" {
@ -116,66 +116,53 @@ static box HakoCli {
return 91
}
// Read Hako source
@fb = new FileBox()
@ok = fb.open(source_path, "r")
if ok != 1 {
print("[hakorune] build exe: failed to open source " + source_path)
return 91
}
@src = fb.read()
fb.close()
if src == null || src == "" {
print("[hakorune] build exe: source is empty")
return 91
}
local tag = "[hakorune] build exe"
local src = me._read_file(tag, source_path)
if src == null { return 91 }
// .hako → Program(JSON v0)
@prog = BuildBox.emit_program_json_v0(src, null)
local prog = BuildBox.emit_program_json_v0(src, null)
if prog == null {
print("[hakorune] build exe: BuildBox returned null")
return 91
}
@ps = "" + prog
local ps = "" + prog
if ps.indexOf("\"version\":0") < 0 || ps.indexOf("\"kind\":\"Program\"") < 0 {
print("[hakorune] build exe: unexpected Program(JSON) output (missing version/kind)")
return 91
}
// Program(JSON v0) → MIR(JSON)
@mir = MirBuilderBox.emit_from_program_json_v0(ps, null)
local mir = MirBuilderBox.emit_from_program_json_v0(ps, null)
if mir == null {
print("[hakorune] build exe: MirBuilderBox returned null")
return 91
}
@ms = "" + mir
local ms = "" + mir
// MIR(JSON) → object via env.codegen.emit_object
@emit_args = new ArrayBox()
local emit_args = new ArrayBox()
emit_args.push(ms)
@obj = hostbridge.extern_invoke("env.codegen", "emit_object", emit_args)
local obj = hostbridge.extern_invoke("env.codegen", "emit_object", emit_args)
if obj == null || ("" + obj) == "" {
print("[hakorune] build exe: env.codegen.emit_object failed")
return 91
}
@obj_path = "" + obj
local obj_path = "" + obj
// object → EXE via env.codegen.link_object
@link_args = new ArrayBox()
local link_args = new ArrayBox()
link_args.push(obj_path)
if out_path != null && out_path != "" {
link_args.push(out_path)
}
@exe = hostbridge.extern_invoke("env.codegen", "link_object", link_args)
local exe = hostbridge.extern_invoke("env.codegen", "link_object", link_args)
if exe == null || ("" + exe) == "" {
print("[hakorune] build exe: env.codegen.link_object failed")
return 91
}
@exe_path = "" + exe
local exe_path = "" + exe
if quiet != 1 {
print("[hakorune] build exe: " + exe_path)
}
return 0
}
@ -192,9 +179,9 @@ static box HakoCli {
@sub_raw = args.get(1)
@sub = "" + sub_raw
if sub == "mir-json" {
return self.cmd_emit_mir_json(args)
return me.cmd_emit_mir_json(args)
} else if sub == "program-json" {
return self.cmd_emit_program_json(args)
return me.cmd_emit_program_json(args)
}
print("[hakorune] emit: unknown subcommand: " + sub)
@ -212,20 +199,20 @@ static box HakoCli {
return 92
}
@path = null
@out_path = null
@quiet = 0
local path = null
local out_path = null
local quiet = 0
@i = 2
while i < argc {
@arg_raw = args.get(i)
@arg = "" + arg_raw
local i = 2
loop(i < argc) {
local arg_raw = args.get(i)
local arg = "" + arg_raw
if arg == "-o" || arg == "--out" {
if i + 1 >= argc {
print("[hakorune] emit program-json: -o/--out requires a path")
return 92
}
@op_raw = args.get(i + 1)
local op_raw = args.get(i + 1)
out_path = "" + op_raw
i = i + 2
} else if arg == "--quiet" {
@ -247,46 +234,26 @@ static box HakoCli {
return 92
}
// Read Hako source from file
@fb = new FileBox()
@ok = fb.open(path, "r")
if ok != 1 {
print("[hakorune] emit program-json: failed to open " + path)
return 92
}
@src = fb.read()
fb.close()
if src == null || src == "" {
print("[hakorune] emit program-json: source is empty")
return 92
}
local tag = "[hakorune] emit program-json"
local src = me._read_file(tag, path)
if src == null { return 92 }
// Compile to Program(JSON v0) via BuildBox
@prog = BuildBox.emit_program_json_v0(src, null)
local prog = BuildBox.emit_program_json_v0(src, null)
if prog == null {
print("[hakorune] emit program-json: BuildBox returned null")
return 92
}
// Minimal validation: require Program(version 0)
@ps = "" + prog
local ps = "" + prog
if ps.indexOf("\"version\":0") < 0 || ps.indexOf("\"kind\":\"Program\"") < 0 {
print("[hakorune] emit program-json: unexpected output (missing version/kind)")
return 92
}
if out_path != null && out_path != "" {
@out_fb = new FileBox()
@ok2 = out_fb.open(out_path, "w")
if ok2 != 1 {
print("[hakorune] emit program-json: failed to open output " + out_path)
if me._write_file(tag, out_path, ps, quiet) != 1 {
return 92
}
out_fb.write(ps)
out_fb.close()
if quiet != 1 {
print("[hakorune] emit program-json: written " + out_path)
}
} else {
print(ps)
}
@ -298,23 +265,23 @@ static box HakoCli {
// - Program(JSON v0) から MIR(JSON) を生成する経路に加えて、
// .hako ソースから直接 Program(JSON v0)→MIR(JSON) まで進める経路もサポートする。
method cmd_emit_mir_json(args){
@argc = 0
local argc = 0
if args { argc = args.size() }
@prog_path = null
@source_path = null
@out_path = null
@quiet = 0
@i = 2
while i < argc {
@arg_raw = args.get(i)
@arg = "" + arg_raw
local prog_path = null
local source_path = null
local out_path = null
local quiet = 0
local i = 2
loop(i < argc) {
local arg_raw = args.get(i)
local arg = "" + arg_raw
if arg == "--from-program-json" {
if i + 1 >= argc {
print("[hakorune] emit mir-json: --from-program-json requires a path")
return 92
}
@p_raw = args.get(i + 1)
local p_raw = args.get(i + 1)
prog_path = "" + p_raw
i = i + 2
} else if arg == "-o" || arg == "--out" {
@ -322,14 +289,13 @@ static box HakoCli {
print("[hakorune] emit mir-json: -o/--out requires a path")
return 92
}
@op_raw = args.get(i + 1)
local op_raw = args.get(i + 1)
out_path = "" + op_raw
i = i + 2
} else if arg == "--quiet" {
quiet = 1
i = i + 1
} else {
// Interpret as <source.hako> when not already set
if source_path == null {
source_path = arg
i = i + 1
@ -340,54 +306,32 @@ static box HakoCli {
}
}
// Prevent ambiguous usage
if prog_path != null && prog_path != "" && source_path != null && source_path != "" {
print("[hakorune] emit mir-json: specify either --from-program-json or <source.hako>, not both")
return 92
}
@prog_json = null
if (prog_path == null || prog_path == "") && (source_path == null || source_path == "") {
print("[hakorune] emit mir-json: require --from-program-json <file> or <source.hako>")
return 92
}
local tag = "[hakorune] emit mir-json"
local prog_json = null
if prog_path != null && prog_path != "" {
// Read Program(JSON v0) from file
@fb = new FileBox()
@ok = fb.open(prog_path, "r")
if ok != 1 {
print("[hakorune] emit mir-json: failed to open " + prog_path)
return 92
}
@p = fb.read()
fb.close()
if p == null || p == "" {
print("[hakorune] emit mir-json: program JSON is empty")
return 92
}
prog_json = p
local prog_text = me._read_file(tag, prog_path)
if prog_text == null { return 92 }
prog_json = prog_text
} else {
// Expect .hako source path
if source_path == null || source_path == "" {
print("[hakorune] emit mir-json: require --from-program-json <file> or <source.hako>")
return 92
}
@fb2 = new FileBox()
@ok2 = fb2.open(source_path, "r")
if ok2 != 1 {
print("[hakorune] emit mir-json: failed to open source " + source_path)
return 92
}
@src = fb2.read()
fb2.close()
if src == null || src == "" {
print("[hakorune] emit mir-json: source is empty")
return 92
}
// Compile to Program(JSON v0) via BuildBox
@prog = BuildBox.emit_program_json_v0(src, null)
local src = me._read_file(tag, source_path)
if src == null { return 92 }
local prog = BuildBox.emit_program_json_v0(src, null)
if prog == null {
print("[hakorune] emit mir-json: BuildBox returned null")
return 92
}
@ps = "" + prog
local ps = "" + prog
if ps.indexOf("\"version\":0") < 0 || ps.indexOf("\"kind\":\"Program\"") < 0 {
print("[hakorune] emit mir-json: unexpected Program(JSON) output (missing version/kind)")
return 92
@ -395,27 +339,17 @@ static box HakoCli {
prog_json = ps
}
// Convert Program(JSON v0) → MIR(JSON) via MirBuilderBox
@mir = MirBuilderBox.emit_from_program_json_v0(prog_json, null)
local mir = MirBuilderBox.emit_from_program_json_v0(prog_json, null)
if mir == null {
print("[hakorune] emit mir-json: MirBuilderBox returned null")
return 92
}
// Success: emit MIR(JSON) to stdout or file
@ms = "" + mir
local ms = "" + mir
if out_path != null && out_path != "" {
@out_fb = new FileBox()
@ok3 = out_fb.open(out_path, "w")
if ok3 != 1 {
print("[hakorune] emit mir-json: failed to open output " + out_path)
if me._write_file(tag, out_path, ms, quiet) != 1 {
return 92
}
out_fb.write(ms)
out_fb.close()
if quiet != 1 {
print("[hakorune] emit mir-json: written " + out_path)
}
} else {
print(ms)
}
@ -423,18 +357,56 @@ static box HakoCli {
return 0
}
// hakorune check <entry.hako>
// - Reserved for future static checks (syntax/using/subset).
method cmd_check(args){
print("[hakorune] check: not implemented yet")
return 93
}
// Helpers for file I/O (Phase 25.1a: consolidate StageB friendly patterns)
method _read_file(tag, path){
if path == null || path == "" {
print(tag + ": source path is required")
return null
}
local fb = new FileBox()
local ok = fb.open(path, "r")
if ok != 1 {
print(tag + ": failed to open " + path)
return null
}
local content = fb.read()
fb.close()
if content == null || content == "" {
print(tag + ": source is empty")
return null
}
return "" + content
}
method _write_file(tag, path, content, quiet){
if path == null || path == "" { return 1 }
local fb = new FileBox()
local ok = fb.open(path, "w")
if ok != 1 {
print(tag + ": failed to open output " + path)
return 0
}
fb.write(content)
fb.close()
if quiet != 1 {
print(tag + ": written " + path)
}
return 1
}
}
static box Main {
// Main entrypoint for Stage1 hakorune CLI.
// args: raw argv array (excluding executable name).
main(args){
method main(args){
@cli = new HakoCli()
return cli.run(args)
}