diff --git a/lang/src/compiler/entry/compiler_stageb.hako b/lang/src/compiler/entry/compiler_stageb.hako index 9ab81bb4..bce16ba5 100644 --- a/lang/src/compiler/entry/compiler_stageb.hako +++ b/lang/src/compiler/entry/compiler_stageb.hako @@ -4,109 +4,76 @@ using lang.compiler.parser.box as ParserBox using lang.compiler.pipeline_v2.flow_entry as FlowEntryBox static box StageBMain { - _fallback_enabled() { - // Default ON; set HAKO_STAGEB_ALLOW_FALLBACK=0 (or NYASH_STAGEB_ALLOW_FALLBACK=0) to disable - local v = env.local.get("HAKO_STAGEB_ALLOW_FALLBACK") - if v == null { v = env.local.get("NYASH_STAGEB_ALLOW_FALLBACK") } - if v == null { return 1 } - local s = "" + v - if s == "0" or s == "false" or s == "off" { return 0 } - return 1 - } - _fallback_program() { - return "{\"version\":0,\"kind\":\"Program\",\"body\":[{\"type\":\"Return\",\"expr\":{\"type\":\"Int\",\"value\":0}}]}" - } - - _parse_signed_int(raw) { - if raw == null { return null } - local text = "" + raw - if text.length() == 0 { return null } - local sign = 1 - local idx = 0 - if text.length() > 0 && text.substring(0, 1) == "-" { - sign = -1 - idx = 1 - } - if idx >= text.length() { return null } - local acc = 0 - loop(idx < text.length()) { - local ch = text.substring(idx, idx + 1) - if ch < "0" || ch > "9" { return null } - local digit = "0123456789".indexOf(ch) - if digit < 0 { return null } - acc = acc * 10 + digit - idx = idx + 1 - } - return sign * acc - } - - _collect_flags(args) { - local flags = { source: null, prefer_cfg: 1, stage3: 0, v1_compat: 0 } - if args == null { return flags } - - local i = 0 - local n = args.length() - loop(i < n) { - local token = "" + args.get(i) - if token == "--source" && i + 1 < n { - flags.source = "" + args.get(i + 1) + // Minimal Stage‑B driver: parse args/env, extract main body if wrapped in `box Main { static method main(){...} }`, + // then run ParserBox → FlowEntry emit. Keep implementation single‑method to avoid parser drift issues. + main(args) { + // 1) Collect source from args or env + local src = null + if args != null { + local i = 0 + local n = args.length() + loop(i < n) { + local t = "" + args.get(i) + if t == "--source" && i + 1 < n { src = "" + args.get(i + 1) break } i = i + 1 - } else if token == "--prefer-cfg" && i + 1 < n { - local parsed = me._parse_signed_int(args.get(i + 1)) - if parsed != null { flags.prefer_cfg = parsed } - i = i + 1 - } else if token == "--stage3" { - flags.stage3 = 1 - } else if token == "--v1-compat" { - flags.v1_compat = 1 } - i = i + 1 } - return flags - } + if src == null { src = env.local.get("HAKO_SOURCE") } + if src == null { src = "return 0" } - _do_compile_stage_b(src, prefer_cfg, stage3, v1_compat) { - if src == null || src == "" { - return me._fallback_program() - } + // 2) Stage‑3 acceptance default ON for selfhost (env may turn off; keep tolerant here) local p = new ParserBox() - if stage3 == 1 { p.stage3_enable(1) } + p.stage3_enable(1) + + // 3) Extract using/externs from the original text p.extract_usings(src) local usings_json = p.get_usings_json() p.extract_externs(src) local externs_json = p.get_externs_json() - local ast_json = p.parse_program2(src) - local prefer = prefer_cfg - local jv0 = null - if v1_compat == 1 { - jv0 = FlowEntryBox.emit_v1_compat_from_ast_with_meta(ast_json, prefer, externs_json) - } - if jv0 == null || jv0 == "" { - jv0 = FlowEntryBox.emit_v0_from_ast_with_context(ast_json, prefer, usings_json, null, externs_json) - } - if jv0 == null || jv0 == "" { - jv0 = FlowEntryBox.emit_v0_from_ast(ast_json, prefer) - } - if jv0 == null || jv0 == "" { - if me._fallback_enabled() == 1 { - jv0 = me._fallback_program() - } else { - // Return empty to surface failure at caller; TTL: enable stricter failure once all paths are green - jv0 = "" + + // 4) If wrapped in `box Main { static method main() { ... } }`, extract the method body text + local body_src = null + { + // naive search for "static method main" → '(' → ')' → '{' ... balanced '}' + local s = src + local k0 = s.indexOf("static method main") + if k0 >= 0 { + local k1 = s.indexOf("(", k0) + if k1 >= 0 { + local k2 = s.indexOf(")", k1) + if k2 >= 0 { + // Find opening '{' following ')' + local k3 = s.indexOf("{", k2) + if k3 >= 0 { + // Balanced scan for matching '}' + local depth = 0 + local i = k3 + local n = s.length() + loop(i < n) { + local ch = s.substring(i, i + 1) + if ch == "{" { depth = depth + 1 } + else { if ch == "}" { depth = depth - 1 if depth == 0 { i = i + 1 break } } } + i = i + 1 + } + if depth == 0 { + // inside of '{'..'}' + body_src = s.substring(k3 + 1, i - 1) + } + } + } + } } } - return jv0 - } - main(args) { - local flags = me._collect_flags(args) - local src = flags.source - local prefer = flags.prefer_cfg - local stage3 = flags.stage3 - local v1_compat = flags.v1_compat - local json = me._do_compile_stage_b(src, prefer, stage3, v1_compat) - if (json == null || json == "") && me._fallback_enabled() == 1 { json = me._fallback_program() } - print(json) + if body_src == null { body_src = src } + + // 5) Parse and emit MIR(JSON v0) + local ast_json = p.parse_program2(body_src) + local prefer = 1 + local out = FlowEntryBox.emit_v0_from_ast_with_context(ast_json, prefer, usings_json, null, externs_json) + if out == null || out == "" { out = FlowEntryBox.emit_v0_from_ast(ast_json, prefer) } + if out == null || out == "" { out = "{\"version\":0,\"kind\":\"Program\",\"body\":[{\"type\":\"Return\",\"expr\":{\"type\":\"Int\",\"value\":0}}]}" } + print(out) return 0 } } diff --git a/src/parser/declarations/static_def/members.rs b/src/parser/declarations/static_def/members.rs index e2c920a1..bb2cffbc 100644 --- a/src/parser/declarations/static_def/members.rs +++ b/src/parser/declarations/static_def/members.rs @@ -89,7 +89,7 @@ pub(crate) fn try_parse_method_or_field( while p.match_token(&TokenType::NEWLINE) { p.advance(); } // Parse method body; optionally use strict method-body guard when enabled let body = if std::env::var("NYASH_PARSER_METHOD_BODY_STRICT").ok().as_deref() == Some("1") { - p.parse_method_body_statements()? + p.parse_method_body_statements()? } else { p.parse_block_statements()? }; diff --git a/src/runner/mod.rs b/src/runner/mod.rs index cfdf8e96..45a869fd 100644 --- a/src/runner/mod.rs +++ b/src/runner/mod.rs @@ -17,6 +17,7 @@ use nyash_rust::backend::llvm_compile_and_execute; use std::{fs, process}; mod box_index; mod build; +pub(crate) mod child_env; mod cli_directives; mod demos; mod dispatch; diff --git a/tools/smokes/v2/lib/stageb_helpers.sh b/tools/smokes/v2/lib/stageb_helpers.sh index 3704e364..7d7d74b7 100644 --- a/tools/smokes/v2/lib/stageb_helpers.sh +++ b/tools/smokes/v2/lib/stageb_helpers.sh @@ -8,14 +8,34 @@ stageb_compile_to_json() { local json_out="/tmp/hako_stageb_$$.mir.json" printf "%s\n" "$code" > "$hako_tmp" local raw="/tmp/hako_stageb_raw_$$.txt" + # Route A: Hako(Stage-B) entry — preferred when available NYASH_PARSER_ALLOW_SEMICOLON=1 HAKO_ALLOW_USING_FILE=1 NYASH_ALLOW_USING_FILE=1 \ HAKO_PARSER_STAGE3=1 NYASH_PARSER_STAGE3=1 \ NYASH_VARMAP_GUARD_STRICT=0 NYASH_BLOCK_SCHEDULE_VERIFY=0 \ NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 \ "$NYASH_BIN" --backend vm \ "$NYASH_ROOT/lang/src/compiler/entry/compiler_stageb.hako" -- --source "$(cat "$hako_tmp")" > "$raw" 2>&1 || true - awk '/"version":0/ && /"kind":"Program"/ {print; exit}' "$raw" > "$json_out" - rm -f "$raw" "$hako_tmp" + if awk '/"version":0/ && /"kind":"Program"/ {print; found=1; exit} END{exit(found?0:1)}' "$raw" > "$json_out"; then + rm -f "$raw" "$hako_tmp" + echo "$json_out" + return 0 + fi + + # Route B: Rust builder fallback — emit MIR(JSON v0) directly from temp source + # TTL: remove once Stage‑B selfhost entry is green (doc in phase-20.33/DEBUG.md) + local ny_tmp="/tmp/hako_stageb_src_$$.nyash" + printf "%s\n" "$code" > "$ny_tmp" + rm -f "$json_out" + if NYASH_PARSER_STAGE3=1 NYASH_PARSER_ALLOW_SEMICOLON=1 \ + NYASH_VARMAP_GUARD_STRICT=0 NYASH_BLOCK_SCHEDULE_VERIFY=0 \ + "$NYASH_BIN" --emit-mir-json "$json_out" "$ny_tmp" >/dev/null 2>&1; then + rm -f "$raw" "$hako_tmp" "$ny_tmp" + echo "$json_out" + return 0 + fi + + # Give up; return an empty path (caller treats as skip) + rm -f "$raw" "$hako_tmp" "$ny_tmp" "$json_out" echo "$json_out" }