fix(dx): Quick Win 1-3 for better error messages and API simplification

Quick Win 1: Show available boxes on "Unknown Box type" error
- vm.rs, vm_fallback.rs: Display sorted list of available user-defined boxes
- Before: "Unknown Box type: Foo"
- After:  "Unknown Box type: Foo. Available: Bar, Baz, Main"

Quick Win 2: Show stderr on child process timeout
- child.rs, selfhost_exe.rs: Capture and display stderr (up to 500 chars)
- Helps diagnose what went wrong in selfhost compiler child process

Quick Win 3: Simplify Stage-B compiler API (SSOT)
- compiler_stageb.hako: Add StageBDriverBox.compile() as single entry point
- compiler_stageb.hako: Remove StageBMain compatibility wrapper
- compiler.hako: Change from `using ... as StageBMain` to direct import
- compiler.hako: Call StageBDriverBox.compile() directly

Also includes child_env.rs NYASH_MODULES env var for module mapping.

🤖 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-25 08:44:31 +09:00
parent 6726ee246d
commit c479e5f527
7 changed files with 190 additions and 15 deletions

View File

@ -2,7 +2,9 @@
// - When invoked with --min-json, emit minimal Program JSON v0 to stdout
// - Otherwise, act as a silent placeholder (return 0)
using lang.compiler.entry.compiler_stageb as StageBMain
// Phase 28.2 Quick Win 3: Direct import without alias
// StageBDriverBox.compile() is the SSOT entry point for Stage-B compilation
using lang.compiler.entry.compiler_stageb
static box Main {
_parse_signed_int(raw) {
@ -478,7 +480,8 @@ static box Main {
main(args) {
local flags = me._collect_flags(args)
if flags.stage_b == 1 {
local json = StageBMain._do_compile_stage_b(flags.source, flags.prefer_cfg, flags.stage3, flags.v1_compat)
// Phase 28.2 Quick Win 3: Direct call to SSOT
local json = StageBDriverBox.compile(flags.source, flags.prefer_cfg, flags.stage3, flags.v1_compat)
print(json)
return 0
}

View File

@ -1139,6 +1139,89 @@ static box StageBHelperBox {
// Phase 25.1c: Main driver logic
static box StageBDriverBox {
// Phase 28.2 Quick Win 3: SSOT compile API for compiler.hako direct call
// Returns Program(JSON v0) instead of printing it.
compile(source, prefer_cfg, stage3, v1_compat) {
// 1) Set env vars for internal functions
if stage3 != null && stage3 != 0 {
env.set("NYASH_PARSER_STAGE3", "1")
env.set("HAKO_PARSER_STAGE3", "1")
}
// 2) Create parser
local p = new ParserBox()
if stage3 != null && stage3 != 0 {
p.stage3_enable(1)
}
// 3) Extract body and parse
local body_src = StageBBodyExtractorBox.build_body_src(source, null)
// 4) Parse to JSON
local ast_json = "{\"version\":0,\"kind\":\"Program\",\"body\":[]}"
if body_src != null {
local block_src = "{" + body_src + "}"
local block_res = p.parse_block2(block_src, 0)
local at = block_res.lastIndexOf("@")
if at >= 0 {
local body_json = block_res.substring(0, at)
if body_json != null && body_json != "" {
ast_json = "{\"version\":0,\"kind\":\"Program\",\"body\":" + body_json + "}"
}
}
}
// 5) Apply SSA transformations
ast_json = CompilerBuilder.apply_all(ast_json)
// 6) Scan for function definitions
local defs_json = ""
local methods = StageBFuncScannerBox.scan_all_boxes(source)
if methods != null && methods.length() > 0 {
defs_json = ",\"defs\":["
local mi = 0
local mn = methods.length()
loop(mi < mn) {
local def = methods.get(mi)
local mname = "" + def.get("name")
local mparams = def.get("params")
local mbody = "" + def.get("body_json")
local mbox = "" + def.get("box")
local wrapped_body = "{\"type\":\"Block\",\"body\":" + mbody + "}"
local params_arr = "["
local pi = 0
local pn = mparams.length()
loop(pi < pn) {
if pi > 0 { params_arr = params_arr + "," }
params_arr = params_arr + "\"" + ("" + mparams.get(pi)) + "\""
pi = pi + 1
}
params_arr = params_arr + "]"
if mi > 0 { defs_json = defs_json + "," }
defs_json = defs_json + "{\"name\":\"" + mname + "\",\"params\":" + params_arr + ",\"body\":" + wrapped_body + ",\"box\":\"" + mbox + "\"}"
mi = mi + 1
}
defs_json = defs_json + "]"
}
// 7) Inject defs into Program JSON
if defs_json != "" && defs_json.length() > 0 {
local ajson = "" + ast_json
local close_pos = -1
local j = ajson.length() - 1
loop(j >= 0) {
if ajson.substring(j, j + 1) == "}" { close_pos = j break }
j = j - 1
}
if close_pos >= 0 {
ast_json = ajson.substring(0, close_pos) + defs_json + ajson.substring(close_pos, ajson.length())
}
}
// 8) Return JSON (SSOT - single return point)
return ast_json
}
main(args) {
// ============================================================================
// Phase 25.1c: Guaranteed marker for entry point confirmation (dev-only)