// 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 // (removed) Transitional duplicate using lines to avoid resolver duplicate-import error 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) } if emit_mir == 1 { // Lower minimal AST to MIR JSON (Return(Int) only for MVP) local mir = new MirEmitterBox() json = mir.emit_mir_min(ast_json) } else { // Emit Stage‑1 JSON with metadata local emitter = new EmitterBox() json = emitter.emit_program(ast_json, me._usings) } // Output JSON local console = new ConsoleBox() console.println(json) return 0 } }