From f1a35be9f20954f428b5f8cc1c9b8c94bba3af9e Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Sat, 1 Nov 2025 18:54:36 +0900 Subject: [PATCH] Remove legacy apps/selfhost tree; intentionally break remaining references to surface migrations (moving to lang/) --- apps/selfhost/README.md | 20 - apps/selfhost/common/json_adapter.nyash | 19 - apps/selfhost/common/mini_vm_binop.nyash | 277 ------ apps/selfhost/common/mini_vm_compare.nyash | 47 - apps/selfhost/common/mini_vm_scan.nyash | 205 ---- apps/selfhost/compiler/README.md | 19 - apps/selfhost/compiler/boxes/debug_box.nyash | 38 - .../selfhost/compiler/boxes/emitter_box.nyash | 26 - .../compiler/boxes/mir_emitter_box.nyash | 52 - apps/selfhost/compiler/boxes/parser_box.nyash | 917 ------------------ apps/selfhost/compiler/compiler.nyash | 158 --- apps/selfhost/compiler/emitter/json_v0.nyash | 8 - apps/selfhost/compiler/mir/builder.nyash | 5 - apps/selfhost/compiler/mir/optimizer.nyash | 5 - apps/selfhost/compiler/parser/ast.nyash | 5 - apps/selfhost/compiler/parser/lexer.nyash | 5 - apps/selfhost/compiler/parser/parser.nyash | 5 - apps/selfhost/compiler/tests/stage1/README.md | 4 - apps/selfhost/ny-parser-nyash/README.md | 14 - apps/selfhost/ny-parser-nyash/main.nyash | 29 - .../ny-parser-nyash/parser_minimal.nyash | 88 -- apps/selfhost/ny-parser-nyash/tokenizer.nyash | 55 -- apps/selfhost/parser/ny_parser_v0/main.nyash | 217 ----- apps/selfhost/smokes/dep_smoke_child.nyash | 7 - apps/selfhost/smokes/dep_smoke_cycle_a.nyash | 6 - apps/selfhost/smokes/dep_smoke_cycle_b.nyash | 6 - apps/selfhost/smokes/dep_smoke_root.nyash | 13 - apps/selfhost/tools/dep_tree.nyash | 253 ----- apps/selfhost/tools/dep_tree_main.nyash | 19 - apps/selfhost/tools/dep_tree_min_string.nyash | 159 --- apps/selfhost/tools/dep_tree_simple.nyash | 265 ----- apps/selfhost/vm/README.md | 14 - apps/selfhost/vm/boxes/json_cur.nyash | 61 -- apps/selfhost/vm/boxes/mini_vm_core.nyash | 774 --------------- apps/selfhost/vm/boxes/mini_vm_prints.nyash | 531 ---------- apps/selfhost/vm/boxes/mir_vm_m2.nyash | 112 --- apps/selfhost/vm/boxes/mir_vm_min.nyash | 309 ------ apps/selfhost/vm/boxes/seam_inspector.nyash | 249 ----- apps/selfhost/vm/boxes/vm_kernel_box.nyash | 32 - .../vm/collect_empty_args_smoke.nyash | 59 -- .../vm/collect_empty_args_using_smoke.nyash | 14 - apps/selfhost/vm/collect_literal_eval.nyash | 30 - apps/selfhost/vm/collect_mixed_smoke.nyash | 282 ------ .../vm/collect_mixed_using_smoke.nyash | 11 - .../vm/collect_prints_loader_smoke.nyash | 18 - apps/selfhost/vm/json_loader.nyash | 51 - apps/selfhost/vm/mini_vm.nyash | 12 - apps/selfhost/vm/mini_vm_if_branch.nyash | 59 -- apps/selfhost/vm/mini_vm_lib.nyash | 33 - apps/selfhost/vm/mir_min_entry.nyash | 15 - apps/selfhost/vm/run_core_wrapper.nyash | 16 - 51 files changed, 5628 deletions(-) delete mode 100644 apps/selfhost/README.md delete mode 100644 apps/selfhost/common/json_adapter.nyash delete mode 100644 apps/selfhost/common/mini_vm_binop.nyash delete mode 100644 apps/selfhost/common/mini_vm_compare.nyash delete mode 100644 apps/selfhost/common/mini_vm_scan.nyash delete mode 100644 apps/selfhost/compiler/README.md delete mode 100644 apps/selfhost/compiler/boxes/debug_box.nyash delete mode 100644 apps/selfhost/compiler/boxes/emitter_box.nyash delete mode 100644 apps/selfhost/compiler/boxes/mir_emitter_box.nyash delete mode 100644 apps/selfhost/compiler/boxes/parser_box.nyash delete mode 100644 apps/selfhost/compiler/compiler.nyash delete mode 100644 apps/selfhost/compiler/emitter/json_v0.nyash delete mode 100644 apps/selfhost/compiler/mir/builder.nyash delete mode 100644 apps/selfhost/compiler/mir/optimizer.nyash delete mode 100644 apps/selfhost/compiler/parser/ast.nyash delete mode 100644 apps/selfhost/compiler/parser/lexer.nyash delete mode 100644 apps/selfhost/compiler/parser/parser.nyash delete mode 100644 apps/selfhost/compiler/tests/stage1/README.md delete mode 100644 apps/selfhost/ny-parser-nyash/README.md delete mode 100644 apps/selfhost/ny-parser-nyash/main.nyash delete mode 100644 apps/selfhost/ny-parser-nyash/parser_minimal.nyash delete mode 100644 apps/selfhost/ny-parser-nyash/tokenizer.nyash delete mode 100644 apps/selfhost/parser/ny_parser_v0/main.nyash delete mode 100644 apps/selfhost/smokes/dep_smoke_child.nyash delete mode 100644 apps/selfhost/smokes/dep_smoke_cycle_a.nyash delete mode 100644 apps/selfhost/smokes/dep_smoke_cycle_b.nyash delete mode 100644 apps/selfhost/smokes/dep_smoke_root.nyash delete mode 100644 apps/selfhost/tools/dep_tree.nyash delete mode 100644 apps/selfhost/tools/dep_tree_main.nyash delete mode 100644 apps/selfhost/tools/dep_tree_min_string.nyash delete mode 100644 apps/selfhost/tools/dep_tree_simple.nyash delete mode 100644 apps/selfhost/vm/README.md delete mode 100644 apps/selfhost/vm/boxes/json_cur.nyash delete mode 100644 apps/selfhost/vm/boxes/mini_vm_core.nyash delete mode 100644 apps/selfhost/vm/boxes/mini_vm_prints.nyash delete mode 100644 apps/selfhost/vm/boxes/mir_vm_m2.nyash delete mode 100644 apps/selfhost/vm/boxes/mir_vm_min.nyash delete mode 100644 apps/selfhost/vm/boxes/seam_inspector.nyash delete mode 100644 apps/selfhost/vm/boxes/vm_kernel_box.nyash delete mode 100644 apps/selfhost/vm/collect_empty_args_smoke.nyash delete mode 100644 apps/selfhost/vm/collect_empty_args_using_smoke.nyash delete mode 100644 apps/selfhost/vm/collect_literal_eval.nyash delete mode 100644 apps/selfhost/vm/collect_mixed_smoke.nyash delete mode 100644 apps/selfhost/vm/collect_mixed_using_smoke.nyash delete mode 100644 apps/selfhost/vm/collect_prints_loader_smoke.nyash delete mode 100644 apps/selfhost/vm/json_loader.nyash delete mode 100644 apps/selfhost/vm/mini_vm.nyash delete mode 100644 apps/selfhost/vm/mini_vm_if_branch.nyash delete mode 100644 apps/selfhost/vm/mini_vm_lib.nyash delete mode 100644 apps/selfhost/vm/mir_min_entry.nyash delete mode 100644 apps/selfhost/vm/run_core_wrapper.nyash diff --git a/apps/selfhost/README.md b/apps/selfhost/README.md deleted file mode 100644 index b3a8b70e..00000000 --- a/apps/selfhost/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Self‑Hosting Apps (Ny‑only) - -Purpose -- Keep self‑hosting Ny scripts isolated from general `apps/` noise. -- Enable fast inner loop without touching Rust unless necessary. - -Conventions -- Entry scripts live under this folder; prefer minimal dependencies. -- Use `--using-path apps/selfhost:apps` when resolving modules. -- Prefer VM (`--backend vm`) for speed and stability. - -Quickstart -- Run minimal sample: `make dev` (uses `apps/selfhost-minimal/main.nyash`) -- Watch changes: `make dev-watch` -- Run parser Ny project: `./tools/dev_selfhost_loop.sh --std -v --backend vm -- apps/selfhost/ny-parser-nyash/main.nyash` - -Guidelines -- Keep files small and composable; avoid cross‑project coupling. -- If moving an existing `apps/*` item here, update docs/scripts accordingly. -- For namespace usage, pass `--using-path apps/selfhost:apps`. diff --git a/apps/selfhost/common/json_adapter.nyash b/apps/selfhost/common/json_adapter.nyash deleted file mode 100644 index 63f9fa22..00000000 --- a/apps/selfhost/common/json_adapter.nyash +++ /dev/null @@ -1,19 +0,0 @@ -// Adapter for JSON cursor operations (extracted) -// Wraps MiniJsonCur and exposes a stable facade -using selfhost.vm.json_cur as MiniJsonCur - -static box MiniJson { - read_quoted_from(s, pos) { - local cur = new MiniJsonCur() - return cur.read_quoted_from(s, pos) - } - read_digits_from(s, pos) { - local cur = new MiniJsonCur() - return cur.read_digits_from(s, pos) - } - next_non_ws(s, pos) { - local cur = new MiniJsonCur() - return cur.next_non_ws(s, pos) - } -} - diff --git a/apps/selfhost/common/mini_vm_binop.nyash b/apps/selfhost/common/mini_vm_binop.nyash deleted file mode 100644 index 7cd0b16d..00000000 --- a/apps/selfhost/common/mini_vm_binop.nyash +++ /dev/null @@ -1,277 +0,0 @@ -using selfhost.vm.json as MiniJson -using selfhost.vm.scan as MiniVmScan - -static box MiniVmBinOp { - // Minimal: Print(BinaryOp) with operator "+"; supports string+string and int+int - try_print_binop_at(json, end, print_pos) { - local scan = new MiniVmScan() - local k_bo = "\"kind\":\"BinaryOp\"" - local bpos = scan.index_of_from(json, k_bo, print_pos) - if bpos <= 0 || bpos >= end { return -1 } - // bound BinaryOp object (prefer expression object) - local k_expr = "\"expression\":{" - local expr_pos = scan.index_of_from(json, k_expr, print_pos) - local obj_start = -1 - if expr_pos > 0 && expr_pos < end { - obj_start = scan.index_of_from(json, "{", expr_pos) - } else { - obj_start = scan.index_of_from(json, "{", bpos) - } - local obj_end = scan.find_balanced_object_end(json, obj_start) - if obj_start <= 0 || obj_end <= 0 || obj_end > end { return -1 } - // operator must be '+' - local k_op = "\"operator\":\"+\"" - local opos = scan.index_of_from(json, k_op, bpos) - if opos <= 0 || opos >= obj_end { return -1 } - - // string + string fast-path - local cur = new MiniJson() - local k_left_lit = "\"left\":{\"kind\":\"Literal\"" - local lhdr = scan.index_of_from(json, k_left_lit, opos) - if lhdr > 0 && lhdr < obj_end { - local k_sval = "\"value\":\"" - local lvp = scan.index_of_from(json, k_sval, lhdr) - if lvp > 0 && lvp < obj_end { - local li = lvp + k_sval.length() - local lval = cur.read_quoted_from(json, li) - if lval { - local k_right_lit = "\"right\":{\"kind\":\"Literal\"" - local rhdr = scan.index_of_from(json, k_right_lit, li + lval.length()) - if rhdr > 0 && rhdr < obj_end { - local rvp = scan.index_of_from(json, k_sval, rhdr) - if rvp > 0 && rvp < obj_end { - local ri = rvp + k_sval.length() - local rval = cur.read_quoted_from(json, ri) - if rval { print(lval + rval) return ri + rval.length() + 1 } - } - } - } - } - } - // int + int typed pattern - local k_l = "\"left\":{\"kind\":\"Literal\"" - local lpos = scan.index_of_from(json, k_l, opos) - if lpos <= 0 || lpos >= obj_end { return -1 } - local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local li2 = scan.index_of_from(json, k_lint, opos) - if li2 <= 0 || li2 >= obj_end { return -1 } - local ldigits = scan.read_digits(json, li2 + k_lint.length()) - if ldigits == "" { return -1 } - local k_r = "\"right\":{\"kind\":\"Literal\"" - local rpos = scan.index_of_from(json, k_r, lpos) - if rpos <= 0 || rpos >= obj_end { return -1 } - local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local ri2 = scan.index_of_from(json, k_rint, lpos) - if ri2 <= 0 || ri2 >= obj_end { return -1 } - local rdigits = scan.read_digits(json, ri2 + k_rint.length()) - if rdigits == "" { return -1 } - local ai = scan._str_to_int(ldigits) - local bi = scan._str_to_int(rdigits) - print(scan._int_to_str(ai + bi)) - return obj_end + 1 - } - - // Greedy disabled (kept for parity) - try_print_binop_int_greedy(json, end, print_pos) { return -1 } - - // Fallback: within the current Print's expression BinaryOp object, scan for two numeric values and sum - try_print_binop_sum_any(json, end, print_pos) { - local scan = new MiniVmScan() - local k_expr = "\"expression\":{" - local expr_pos = scan.index_of_from(json, k_expr, print_pos) - // If expression object cannot be bounded, fall back to typed-direct pattern within the current slice - if expr_pos <= 0 || expr_pos >= end { - // bound coarse slice to current Print by next Print marker - local k_print = "\"kind\":\"Print\"" - local next_p = scan.index_of_from(json, k_print, print_pos + 1) - local slice_end = end - if next_p > 0 { slice_end = next_p } - local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - // only if BinaryOp is present in this slice - if scan.index_of_from(json, "\"kind\":\"BinaryOp\"", print_pos) > 0 { - local lp = scan.index_of_from(json, k_lint, print_pos) - if lp > 0 { if lp < slice_end { - local ld = scan.read_digits(json, lp + k_lint.length()) - if ld != "" { - local rp = scan.index_of_from(json, k_rint, lp + k_lint.length()) - if rp > 0 { if rp < slice_end { - local rd = scan.read_digits(json, rp + k_rint.length()) - if rd != "" { print(scan._int_to_str(scan._str_to_int(ld) + scan._str_to_int(rd))) return 1 } - }} - } - }} - } - return -1 - } - local obj_start = scan.index_of_from(json, "{", expr_pos) - if obj_start <= 0 || obj_start >= end { return -1 } - local obj_end = scan.find_balanced_object_end(json, obj_start) - if obj_end <= 0 || obj_end > end { - local k_print = "\"kind\":\"Print\"" - local next_p = scan.index_of_from(json, k_print, print_pos + 1) - local obj_end2 = end - if next_p > 0 && next_p <= end { obj_end2 = next_p } - // typed-direct fallback in bounded region - local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local lp = scan.index_of_from(json, k_lint, obj_start) - if lp > 0 { if lp < obj_end2 { - local ld = scan.read_digits(json, lp + k_lint.length()) - if ld != "" { - local rp = scan.index_of_from(json, k_rint, lp + k_lint.length()) - if rp > 0 { if rp < obj_end2 { - local rd = scan.read_digits(json, rp + k_rint.length()) - if rd != "" { print(scan._int_to_str(scan._str_to_int(ld) + scan._str_to_int(rd))) return 1 } - }} - } - }} - return -1 - } - local k_bo = "\"kind\":\"BinaryOp\"" - local bpos = scan.index_of_from(json, k_bo, obj_start) - if bpos <= 0 || bpos >= obj_end { - // typed-direct fallback (within bounds window) - local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local lp = scan.index_of_from(json, k_lint, obj_start) - if lp > 0 { if lp < obj_end { - local ld = scan.read_digits(json, lp + k_lint.length()) - if ld != "" { - local rp = scan.index_of_from(json, k_rint, lp + k_lint.length()) - if rp > 0 { if rp < obj_end { - local rd = scan.read_digits(json, rp + k_rint.length()) - if rd != "" { print(scan._int_to_str(scan._str_to_int(ld) + scan._str_to_int(rd))) return 1 } - }} - } - }} - return -1 - } - local k_plus = "\"operator\":\"+\"" - local opos = scan.index_of_from(json, k_plus, bpos) - if opos <= 0 || opos >= obj_end { - // typed-direct fallback - local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local lp = scan.index_of_from(json, k_lint, obj_start) - if lp > 0 { if lp < obj_end { - local ld = scan.read_digits(json, lp + k_lint.length()) - if ld != "" { - local rp = scan.index_of_from(json, k_rint, lp + k_lint.length()) - if rp > 0 { if rp < obj_end { - local rd = scan.read_digits(json, rp + k_rint.length()) - if rd != "" { print(scan._int_to_str(scan._str_to_int(ld) + scan._str_to_int(rd))) return 1 } - }} - } - }} - return -1 - } - local nums = [] - local i = obj_start - loop (i < obj_end) { - if json.substring(i, i+1) == "\"" { - local j = scan.index_of_from(json, "\"", i+1) - if j < 0 || j >= obj_end { break } - i = j + 1 - continue - } - local d = scan.read_digits(json, i) - if d { nums.push(d) i = i + d.length() continue } - i = i + 1 - } - local nsz = nums.size() - if nsz < 2 { return -1 } - local a = scan._str_to_int(nums.get(nsz-2)) - local b = scan._str_to_int(nums.get(nsz-1)) - print(scan._int_to_str(a + b)) - return obj_end + 1 - } - - // Deterministic: within Print.expression BinaryOp('+'), pick two successive 'value' fields and sum - try_print_binop_sum_expr_values(json, end, print_pos) { - local scan = new MiniVmScan() - local cur = new MiniJson() - local k_expr = "\"expression\":{" - local expr_pos = scan.index_of_from(json, k_expr, print_pos) - if expr_pos <= 0 || expr_pos >= end { return -1 } - local obj_start = scan.index_of_from(json, "{", expr_pos) - if obj_start <= 0 || obj_start >= end { return -1 } - local obj_end = scan.find_balanced_object_end(json, obj_start) - if obj_end <= 0 || obj_end > end { return -1 } - local k_bo = "\"kind\":\"BinaryOp\"" - local bpos = scan.index_of_from(json, k_bo, obj_start) - if bpos <= 0 || bpos >= obj_end { return -1 } - local k_plus = "\"operator\":\"+\"" - local opos = scan.index_of_from(json, k_plus, bpos) - if opos <= 0 || opos >= obj_end { return -1 } - local k_v = "\"value\":" - local found = 0 - local a = 0 - local pos = scan.index_of_from(json, k_v, obj_start) - loop (pos > 0 && pos < obj_end) { - local di = cur.read_digits_from(json, pos + k_v.length()) - if di != "" { - if found == 0 { a = scan._str_to_int(di) found = 1 } else { - local b = scan._str_to_int(di) - print(scan._int_to_str(a + b)) - return obj_end + 1 - } - } - pos = scan.index_of_from(json, k_v, pos + k_v.length()) - if pos <= 0 || pos >= obj_end { break } - } - return -1 - } - - // Simpler: after operator '+', scan two successive 'value' fields and sum - try_print_binop_sum_after_bop(json) { - local scan = new MiniVmScan() - local k_bo = "\"kind\":\"BinaryOp\"" - local bpos = json.indexOf(k_bo) - if bpos < 0 { return -1 } - local k_plus = "\"operator\":\"+\"" - local opos = scan.index_of_from(json, k_plus, bpos) - if opos < 0 { return -1 } - local k_v = "\"value\":" - local p = opos - p = scan.index_of_from(json, k_v, p) - if p < 0 { return -1 } - p = scan.index_of_from(json, k_v, p + k_v.length()) - if p < 0 { return -1 } - local end1 = scan.index_of_from(json, "}", p) - if end1 < 0 { return -1 } - local d1 = scan.read_digits(json, p + k_v.length()) - if d1 == "" { return -1 } - p = scan.index_of_from(json, k_v, end1) - if p < 0 { return -1 } - p = scan.index_of_from(json, k_v, p + k_v.length()) - if p < 0 { return -1 } - local end2 = scan.index_of_from(json, "}", p) - if end2 < 0 { return -1 } - local d2 = scan.read_digits(json, p + k_v.length()) - if d2 == "" { return -1 } - local ai = scan._str_to_int(d1) - local bi = scan._str_to_int(d2) - print(scan._int_to_str(ai + bi)) - return 0 - } - - // Fallback: find first BinaryOp and return sum of two numeric values as string - parse_first_binop_sum(json) { - local scan = new MiniVmScan() - local k_bo = "\"kind\":\"BinaryOp\"" - local bpos = json.indexOf(k_bo) - if bpos < 0 { return "" } - local k_typed = "\"type\":\"int\",\"value\":" - local p1 = scan.index_of_from(json, k_typed, bpos) - if p1 < 0 { return "" } - local d1 = scan.read_digits(json, p1 + k_typed.length()) - if d1 == "" { return "" } - local p2 = scan.index_of_from(json, k_typed, p1 + k_typed.length()) - if p2 < 0 { return "" } - local d2 = scan.read_digits(json, p2 + k_typed.length()) - if d2 == "" { return "" } - return scan._int_to_str(scan._str_to_int(d1) + scan._str_to_int(d2)) - } -} - diff --git a/apps/selfhost/common/mini_vm_compare.nyash b/apps/selfhost/common/mini_vm_compare.nyash deleted file mode 100644 index 82c4bc21..00000000 --- a/apps/selfhost/common/mini_vm_compare.nyash +++ /dev/null @@ -1,47 +0,0 @@ -using selfhost.vm.scan as MiniVmScan - -static box MiniVmCompare { - // Compare(lhs int, rhs int) minimal: prints 0/1 and returns next pos or -1 - try_print_compare_at(json, end, print_pos) { - local scan = new MiniVmScan() - local k_cp = "\"kind\":\"Compare\"" - local cpos = scan.index_of_from(json, k_cp, print_pos) - if cpos <= 0 || cpos >= end { return -1 } - local k_op = "\"operation\":\"" - local opos = scan.index_of_from(json, k_op, cpos) - if opos <= 0 || opos >= end { return -1 } - local oi = opos + k_op.length() - local oj = scan.index_of_from(json, "\"", oi) - if oj <= 0 || oj > end { return -1 } - local op = json.substring(oi, oj) - // lhs value - local k_lhs = "\"lhs\":{\"kind\":\"Literal\"" - local hl = scan.index_of_from(json, k_lhs, oj) - if hl <= 0 || hl >= end { return -1 } - local k_v = "\"value\":" - local hv = scan.index_of_from(json, k_v, hl) - if hv <= 0 || hv >= end { return -1 } - local a = scan.read_digits(json, hv + k_v.length()) - // rhs value - local k_rhs = "\"rhs\":{\"kind\":\"Literal\"" - local hr = scan.index_of_from(json, k_rhs, hl) - if hr <= 0 || hr >= end { return -1 } - local rv = scan.index_of_from(json, k_v, hr) - if rv <= 0 || rv >= end { return -1 } - local b = scan.read_digits(json, rv + k_v.length()) - if !a || !b { return -1 } - local ai = scan._str_to_int(a) - local bi = scan._str_to_int(b) - local res = 0 - if op == "<" { if ai < bi { res = 1 } } - if op == "==" { if ai == bi { res = 1 } } - if op == "<=" { if ai <= bi { res = 1 } } - if op == ">" { if ai > bi { res = 1 } } - if op == ">=" { if ai >= bi { res = 1 } } - if op == "!=" { if ai != bi { res = 1 } } - print(res) - // advance after rhs object (coarsely) - return rv + 1 - } -} - diff --git a/apps/selfhost/common/mini_vm_scan.nyash b/apps/selfhost/common/mini_vm_scan.nyash deleted file mode 100644 index 46543f3f..00000000 --- a/apps/selfhost/common/mini_vm_scan.nyash +++ /dev/null @@ -1,205 +0,0 @@ -// Mini-VM scanning and numeric helpers -static box MiniVmScan { - // helper: find needle from position pos - index_of_from(hay, needle, pos) { - // Guard position; clamp to valid range to avoid negative substring - if pos < 0 { pos = 0 } - local n = hay.length() - if pos >= n { return -1 } - local m = needle.length() - if m <= 0 { return pos } - local i = pos - local limit = n - m - loop (i <= limit) { - local seg = hay.substring(i, i + m) - if seg == needle { return i } - i = i + 1 - } - return -1 - } - - // helper: find balanced bracket range [ ... ] starting at idx (points to '[') - find_balanced_array_end(json, idx) { - @n = json.length() - if json.substring(idx, idx+1) != "[" { return -1 } - @depth = 0 - @i = idx - @in_str = 0 - @guard = 0 - loop (i < n) { - guard = guard + 1 - if guard > 50000 { return -1 } - @ch = json.substring(i, i+1) - if in_str == 1 { - if ch == "\\" { i = i + 2 continue } - if ch == "\"" { in_str = 0 i = i + 1 continue } - i = i + 1 - continue - } - if ch == "\"" { in_str = 1 i = i + 1 continue } - if ch == "[" { depth = depth + 1 } - if ch == "]" { - depth = depth - 1 - if depth == 0 { return i } - } - i = i + 1 - } - return -1 - } - - // helper: find balanced object range { ... } starting at idx (points to '{') - find_balanced_object_end(json, idx) { - @n = json.length() - if json.substring(idx, idx+1) != "{" { return -1 } - @depth = 0 - @i = idx - @in_str = 0 - @guard = 0 - loop (i < n) { - guard = guard + 1 - if guard > 50000 { return -1 } - @ch = json.substring(i, i+1) - if in_str == 1 { - if ch == "\\" { i = i + 2 continue } - if ch == "\"" { in_str = 0 i = i + 1 continue } - i = i + 1 - continue - } - if ch == "\"" { in_str = 1 i = i + 1 continue } - if ch == "{" { depth = depth + 1 } - if ch == "}" { - depth = depth - 1 - if depth == 0 { return i } - } - i = i + 1 - } - return -1 - } - - _str_to_int(s) { - @i = 0 - @n = s.length() - @acc = 0 - loop (i < n) { - @ch = s.substring(i, i+1) - if ch == "0" { acc = acc * 10 + 0 i = i + 1 continue } - if ch == "1" { acc = acc * 10 + 1 i = i + 1 continue } - if ch == "2" { acc = acc * 10 + 2 i = i + 1 continue } - if ch == "3" { acc = acc * 10 + 3 i = i + 1 continue } - if ch == "4" { acc = acc * 10 + 4 i = i + 1 continue } - if ch == "5" { acc = acc * 10 + 5 i = i + 1 continue } - if ch == "6" { acc = acc * 10 + 6 i = i + 1 continue } - if ch == "7" { acc = acc * 10 + 7 i = i + 1 continue } - if ch == "8" { acc = acc * 10 + 8 i = i + 1 continue } - if ch == "9" { acc = acc * 10 + 9 i = i + 1 continue } - break - } - return acc - } - _digit_char(d) { - if d == 0 { return "0" } - if d == 1 { return "1" } - if d == 2 { return "2" } - if d == 3 { return "3" } - if d == 4 { return "4" } - if d == 5 { return "5" } - if d == 6 { return "6" } - if d == 7 { return "7" } - if d == 8 { return "8" } - if d == 9 { return "9" } - return "0" - } - _int_to_str(n) { - if n == 0 { return "0" } - @v = n - @out = "" - loop (v > 0) { - @d = v % 10 - @ch = _digit_char(d) - out = ch + out - v = v / 10 - } - return out - } - - // Read digit runs starting at pos - read_digits(json, pos) { - @out = "" - loop (true) { - @s = json.substring(pos, pos+1) - if s == "" { break } - if s == "0" { out = out + s pos = pos + 1 continue } - if s == "1" { out = out + s pos = pos + 1 continue } - if s == "2" { out = out + s pos = pos + 1 continue } - if s == "3" { out = out + s pos = pos + 1 continue } - if s == "4" { out = out + s pos = pos + 1 continue } - if s == "5" { out = out + s pos = pos + 1 continue } - if s == "6" { out = out + s pos = pos + 1 continue } - if s == "7" { out = out + s pos = pos + 1 continue } - if s == "8" { out = out + s pos = pos + 1 continue } - if s == "9" { out = out + s pos = pos + 1 continue } - break - } - return out - } - - // Linear pass: sum all numbers outside of quotes - sum_numbers_no_quotes(json) { - @i = 0 - @n = json.length() - @total = 0 - loop (i < n) { - @ch = json.substring(i, i+1) - if ch == "\"" { - @j = index_of_from(json, "\"", i+1) - if j < 0 { break } - i = j + 1 - continue - } - @d = read_digits(json, i) - if d { total = total + _str_to_int(d) i = i + d.length() continue } - i = i + 1 - } - return _int_to_str(total) - } - - // Naive: sum all digit runs anywhere - sum_all_digits_naive(json) { - @i = 0 - @n = json.length() - @total = 0 - loop (i < n) { - @d = read_digits(json, i) - if d { total = total + _str_to_int(d) i = i + d.length() continue } - i = i + 1 - } - return _int_to_str(total) - } - - // Sum first two integers outside quotes; returns string or empty - sum_first_two_numbers(json) { - @i = 0 - @n = json.length() - @total = 0 - local found = 0 - loop (i < n) { - @ch = json.substring(i, i+1) - if ch == "\"" { - @j = index_of_from(json, "\"", i+1) - if j < 0 { break } - i = j + 1 - continue - } - @d = read_digits(json, i) - if d { - total = total + _str_to_int(d) - found = found + 1 - i = i + d.length() - if found >= 2 { return _int_to_str(total) } - continue - } - i = i + 1 - } - return "" - } -} diff --git a/apps/selfhost/compiler/README.md b/apps/selfhost/compiler/README.md deleted file mode 100644 index 847a3b78..00000000 --- a/apps/selfhost/compiler/README.md +++ /dev/null @@ -1,19 +0,0 @@ -# Nyash Selfhost Compiler (MVP scaffold) - -This is the Phase 15.3 work-in-progress Nyash compiler implemented in Ny. - -Layout -- `compiler.nyash`: entry (CompilerBox). Reads `tmp/ny_parser_input.ny`, prints JSON v0. -- `parser/`: lexer/parser/ast (scaffolds; to be filled as we extend Stage‑2) -- `mir/`: builder/optimizer stubs (future; current target is JSON v0 emit) -- `tests/`: Stage‑1/2 samples (TBD) - -Run (behind flag) -- `NYASH_USE_NY_COMPILER=1 target/release/nyash --backend vm ` - - The runner writes the input to `tmp/ny_parser_input.ny` and invokes this program. - - It captures a JSON v0 line from stdout and executes it via the JSON bridge. - - Stage‑3 syntax gate: set `NYASH_NY_COMPILER_STAGE3=1` to pass `--stage3` to the parser (accepts Break/Continue/Throw/Try in JSON v0). - -Notes -- Early MVP emits a minimal JSON v0 (currently a placeholder: return 0). We will gradually wire lexer/parser/emitter. -- Keep JSON v0 spec in `docs/reference/ir/json_v0.md`. diff --git a/apps/selfhost/compiler/boxes/debug_box.nyash b/apps/selfhost/compiler/boxes/debug_box.nyash deleted file mode 100644 index 08bcdec0..00000000 --- a/apps/selfhost/compiler/boxes/debug_box.nyash +++ /dev/null @@ -1,38 +0,0 @@ -// DebugBox — conditional debug output aggregator (extracted) -box DebugBox { - enabled - birth() { - me.enabled = 0 - return 0 - } - set_enabled(v) { - me.enabled = v - return 0 - } - log(msg) { - if me.enabled { - local c = new ConsoleBox() - c.println("[DEBUG] " + msg) - } - return 0 - } - info(msg) { - if me.enabled { - local c = new ConsoleBox() - c.println("[INFO] " + msg) - } - return 0 - } - error(msg) { - if me.enabled { - local c = new ConsoleBox() - c.println("[ERROR] " + msg) - } - return 0 - } -} - -// Include stub to satisfy current include lowering (expects a static box) -static box DebugStub { - main(args) { return 0 } -} diff --git a/apps/selfhost/compiler/boxes/emitter_box.nyash b/apps/selfhost/compiler/boxes/emitter_box.nyash deleted file mode 100644 index bb132879..00000000 --- a/apps/selfhost/compiler/boxes/emitter_box.nyash +++ /dev/null @@ -1,26 +0,0 @@ -// EmitterBox — thin wrapper to emit JSON v0 (extracted) -box EmitterBox { - emit_program(json, usings_json) { - if json == null { return json } - // Normalize usings payload to at least an empty array so meta.usings is always present - local payload = usings_json - if payload == null { payload = "[]" } - if payload.length() == 0 { payload = "[]" } - // Inject meta.usings before closing brace of top-level object - local n = json.lastIndexOf("}") - if n < 0 { return json } - local head = json.substring(0, n) - local tail = json.substring(n, json.length()) - local needs_comma = 1 - if head.length() == 0 { needs_comma = 0 } else { - local last = head.substring(head.length() - 1, head.length()) - if last == "{" || last == "," { needs_comma = 0 } - } - if needs_comma == 1 { head = head + "," } - return head + "\"meta\":{\"usings\":" + payload + "}" + tail - } -} - -static box EmitterStub { - main(args) { return 0 } -} diff --git a/apps/selfhost/compiler/boxes/mir_emitter_box.nyash b/apps/selfhost/compiler/boxes/mir_emitter_box.nyash deleted file mode 100644 index fa0c0740..00000000 --- a/apps/selfhost/compiler/boxes/mir_emitter_box.nyash +++ /dev/null @@ -1,52 +0,0 @@ -// MirEmitterBox — Minimal MIR JSON v0 emitter (M2 MVP) -// Scope: Return(Int) only (const + ret). Safe default to 0 when not found. -// Future: add Binary/Compare/ExternCall/BoxCall lowering incrementally. - -box MirEmitterBox { - // Extract first Return(Int) value from Stage-1 JSON (very small string scan) - _extract_return_int(ast_json) { - if ast_json == null { return 0 } - // Look for '"type":"Return"' - local p = ast_json.lastIndexOf("\"type\":\"Return\"") - if p < 0 { p = ast_json.indexOf("\"type\":\"Return\"") } - if p < 0 { return 0 } - // From there, search for '"type":"Int","value":' - local q = ast_json.indexOf("\"type\":\"Int\",\"value\":", p) - if q < 0 { return 0 } - q = q + 23 // length of the marker - // Read consecutive digits (optional minus not handled in Stage-1 yet) - local n = ast_json.length() - local i = q - local s = "" - loop(i < n) { - local ch = ast_json.substring(i, i+1) - if ch >= "0" && ch <= "9" { s = s + ch i = i + 1 } else { break } - } - if s.length() == 0 { return 0 } - // String to int via addition loop - local val = 0 - local k = 0 - local m = s.length() - loop(k < m) { - local d = s.substring(k, k+1) - local dv = 0 - if d == "1" { dv = 1 } else { if d == "2" { dv = 2 } else { if d == "3" { dv = 3 } else { if d == "4" { dv = 4 } else { if d == "5" { dv = 5 } else { if d == "6" { dv = 6 } else { if d == "7" { dv = 7 } else { if d == "8" { dv = 8 } else { if d == "9" { dv = 9 } } } } } } } } } - val = val * 10 + dv - k = k + 1 - } - return val - } - - // Build minimal MIR JSON v0: main with const -> ret - emit_mir_min(ast_json) { - local retv = me._extract_return_int(ast_json) - local s = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"blocks\":[{\"id\":0,\"instructions\":[" - s = s + "{\\\"op\\\":\\\"const\\\",\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":" + retv + "},\\\"dst\\\":1}," - s = s + "{\\\"op\\\":\\\"ret\\\",\\\"value\\\":1}" - s = s + "]}]}]}" - return s - } -} - -static box MirEmitterStub { main(args) { return 0 } } - diff --git a/apps/selfhost/compiler/boxes/parser_box.nyash b/apps/selfhost/compiler/boxes/parser_box.nyash deleted file mode 100644 index f20f5780..00000000 --- a/apps/selfhost/compiler/boxes/parser_box.nyash +++ /dev/null @@ -1,917 +0,0 @@ -// ParserBox — Stage‑1 JSON v0 generator(extracted, simplified for Rust parser) -box ParserBox { - gpos - usings_json - stage3 - - birth() { me.gpos = 0 me.usings_json = "[]" me.stage3 = 0 return 0 } - - stage3_enable(flag) { - if flag == null { flag = 0 } - if flag == 0 { me.stage3 = 0 } else { me.stage3 = 1 } - return 0 - } - - stage3_enabled() { - if me.stage3 == 1 { return 1 } - return 0 - } - - 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 - } - - is_digit(ch) { return ch >= "0" && ch <= "9" } - is_space(ch) { return ch == " " || ch == "\t" || ch == "\n" || ch == "\r" } - // simple alpha/underscore check for identifiers - is_alpha(ch) { return (ch >= "A" && ch <= "Z") || (ch >= "a" && ch <= "z") || ch == "_" } - - gpos_set(i) { me.gpos = i return 0 } - gpos_get() { return me.gpos } - - // lightweight string helpers - starts_with(src, i, pat) { - local n = src.length() - local m = pat.length() - if i + m > n { return 0 } - local k = 0 - loop(k < m) { - if src.substring(i + k, i + k + 1) != pat.substring(k, k + 1) { return 0 } - k = k + 1 - } - return 1 - } - index_of(src, i, pat) { - local n = src.length() - local m = pat.length() - if m == 0 { return i } - local j = i - loop(j + m <= n) { - if me.starts_with(src, j, pat) { return j } - j = j + 1 - } - return -1 - } - trim(s) { - local i = 0 - local n = s.length() - loop(i < n && (s.substring(i,i+1) == " " || s.substring(i,i+1) == "\t")) { i = i + 1 } - local j = n - loop(j > i && (s.substring(j-1,j) == " " || s.substring(j-1,j) == "\t" || s.substring(j-1,j) == ";")) { j = j - 1 } - return s.substring(i, j) - } - - // Enhanced whitespace skipper (inline lines): used by line-based using extractor - trim_ws_and_line_comments(s) { - local i = 0 - local n = s.length() - // leading spaces/tabs - loop(i < n && (s.substring(i,i+1) == " " || s.substring(i,i+1) == "\t")) { i = i + 1 } - // strip line comments - if i + 1 < n && s.substring(i, i+2) == "//" { return "" } - return s.substring(i, n) - } - - // keyword match at position i with word-boundary (next char not [A-Za-z0-9_]) - starts_with_kw(src, i, kw) { - if me.starts_with(src, i, kw) == 0 { return 0 } - local n = src.length() - local j = i + kw.length() - if j >= n { return 1 } - local ch = src.substring(j, j+1) - if me.is_alpha(ch) || me.is_digit(ch) { return 0 } - return 1 - } - - // integer to string (uses string concat coercion) - i2s(v) { return "" + v } - - // Read identifier starting at i: [A-Za-z_][A-Za-z0-9_]*; returns "name@pos" - read_ident2(src, i) { - local n = src.length() - local j = i - if j >= n { return "@" + me.i2s(i) } - local ch = src.substring(j, j+1) - if me.is_alpha(ch) == 0 { return "@" + me.i2s(i) } - j = j + 1 - loop(j < n) { - local c = src.substring(j, j+1) - if me.is_alpha(c) || me.is_digit(c) { j = j + 1 } else { break } - } - local name = src.substring(i, j) - return name + "@" + me.i2s(j) - } - - // Read string literal at i (i points to '"'); returns raw content (no quotes), updates gpos - read_string_lit(src, i) { - local n = src.length() - local j = i - if j >= n || src.substring(j, j+1) != "\"" { me.gpos_set(i) return "" } - j = j + 1 - local out = "" - local guard = 0 - local max = 200000 - loop(j < n) { - if guard > max { break } else { guard = guard + 1 } - local ch = src.substring(j, j+1) - if ch == "\"" { j = j + 1 me.gpos_set(j) return out } - if ch == "\\" && j + 1 < n { - local nx = src.substring(j+1, j+2) - if nx == "\"" { out = out + "\"" j = j + 2 } else { if nx == "\\" { out = out + "\\" j = j + 2 } else { if nx == "n" { out = out + "\n" j = j + 2 } else { if nx == "r" { out = out + "\r" j = j + 2 } else { if nx == "t" { out = out + "\t" j = j + 2 } else { if nx == "u" && j + 5 < n { out = out + src.substring(j, j+6) j = j + 6 } else { out = out + nx j = j + 2 } } } } } } - } else { out = out + ch j = j + 1 } - } - me.gpos_set(j) - return out - } - - // Append a using entry into usings_json (no-op acceptance path) - add_using(kind, target, alias) { - // kind: "path" or "ns"; target: path or namespace; alias: nullable - local cur = me.usings_json - if cur == null || cur.length() == 0 { cur = "[]" } - // Build entry - local name = "" - local path = null - if kind == "path" { - path = target - if alias != null { name = alias } else { - local p = target - // basename - local idx = -1 - local t = 0 - loop(t < p.length()) { if p.substring(t,t+1) == "/" { idx = t } t = t + 1 } - if idx >= 0 { p = p.substring(idx+1, p.length()) } - if p.length() > 6 && me.starts_with(p, p.length()-6, ".nyash") == 1 { p = p.substring(0, p.length()-6) } - name = p - } - } else { - name = target - if alias != null { name = alias } - } - local entry = "{\"name\":\"" + me.esc_json(name) + "\"" - if path != null { entry = entry + ",\"path\":\"" + me.esc_json(path) + "\"" } - entry = entry + "}" - // Insert before closing ']' of array - if cur == "[]" { me.usings_json = "[" + entry + "]" return 0 } - // naive append - local pos = cur.lastIndexOf("]") - if pos < 0 { me.usings_json = "[" + entry + "]" return 0 } - me.usings_json = cur.substring(0, pos) + "," + entry + "]" - return 0 - } - - // Collect `using` lines into JSON array stored in me.usings_json (no-op acceptance) - extract_usings(src) { - if src == null { me.usings_json = "[]" return 0 } - local n = src.length() - local i = 0 - local first = 1 - local out = "[" - loop(i < n) { - // read a line - local j = i - loop(j < n && src.substring(j, j+1) != "\n") { j = j + 1 } - local line = src.substring(i, j) - // process - local k = 0 - loop(k < line.length() && (line.substring(k,k+1) == " " || line.substring(k,k+1) == "\t")) { k = k + 1 } - if me.starts_with(line, k, "using ") == 1 { - local rest = me.trim(line.substring(k + 6, line.length())) - // split on ' as ' - local as_pos = me.index_of(rest, 0, " as ") - local target = rest - local alias = null - if as_pos >= 0 { - target = me.trim(rest.substring(0, as_pos)) - alias = me.trim(rest.substring(as_pos + 4, rest.length())) - } - // path or namespace - local is_path = 0 - if target.length() > 0 { - if me.starts_with(target, 0, "\"") == 1 { is_path = 1 } - if me.starts_with(target, 0, "./") == 1 { is_path = 1 } - if me.starts_with(target, 0, "/") == 1 { is_path = 1 } - if target.length() >= 6 && me.starts_with(target, target.length()-6, ".nyash") == 1 { is_path = 1 } - } - local name = "" - local path = null - if is_path == 1 { - // trim quotes - if me.starts_with(target, 0, "\"") == 1 { - target = target.substring(1, target.length()) - if target.length() > 0 && target.substring(target.length()-1, target.length()) == "\"" { - target = target.substring(0, target.length()-1) - } - } - path = target - if alias != null { name = alias } else { - // derive from basename - local p = target - // find last '/' - local idx = -1 - local t = 0 - loop(t < p.length()) { if p.substring(t,t+1) == "/" { idx = t } t = t + 1 } - if idx >= 0 { p = p.substring(idx+1, p.length()) } - // strip .nyash - if p.length() > 6 && me.starts_with(p, p.length()-6, ".nyash") == 1 { p = p.substring(0, p.length()-6) } - name = p - } - } else { - name = target - } - // append JSON entry - if first == 0 { out = out + "," } else { first = 0 } - out = out + "{\"name\":\"" + me.esc_json(name) + "\"" - if path != null { out = out + ",\"path\":\"" + me.esc_json(path) + "\"" } - out = out + "}" - } - i = j + 1 - } - out = out + "]" - me.usings_json = out - return 0 - } - get_usings_json() { return me.usings_json } - - to_int(s) { local n = s.length() if n == 0 { return 0 } local i = 0 local acc = 0 loop(i < n) { local d = s.substring(i, i+1) local dv = 0 if d == "1" { dv = 1 } else { if d == "2" { dv = 2 } else { if d == "3" { dv = 3 } else { if d == "4" { dv = 4 } else { if d == "5" { dv = 5 } else { if d == "6" { dv = 6 } else { if d == "7" { dv = 7 } else { if d == "8" { dv = 8 } else { if d == "9" { dv = 9 } } } } } } } } } acc = acc * 10 + dv i = i + 1 } return acc } - - skip_ws(src, i) { if src == null { return i } local n = src.length() local cont = 1 local guard = 0 local max = 100000 loop(cont == 1) { if guard > max { return i } guard = guard + 1 if i < n { if me.is_space(src.substring(i, i+1)) { i = i + 1 } else { cont = 0 } } else { cont = 0 } } return i } - // identifiers/strings not required for Stage‑1 beyond string literal parse above - - // using metadata omitted in Stage‑1 - - parse_number2(src, i) { local n = src.length() local j = i local cont = 1 local guard = 0 local max = 100000 loop(cont == 1) { if guard > max { cont = 0 } else { guard = guard + 1 if j < n { if me.is_digit(src.substring(j, j+1)) { j = j + 1 } else { cont = 0 } } else { cont = 0 } } } local s = src.substring(i, j) me.gpos_set(j) return "{\"type\":\"Int\",\"value\":" + s + "}" } - parse_string2(src, i) { local n = src.length() local j = i + 1 local out = "" local guard = 0 local max = 200000 loop(j < n) { if guard > max { break } guard = guard + 1 local ch = src.substring(j, j+1) if ch == "\"" { j = j + 1 me.gpos_set(j) return "{\"type\":\"Str\",\"value\":\"" + me.esc_json(out) + "\"}" } if ch == "\\" && j + 1 < n { local nx = src.substring(j+1, j+2) if nx == "\"" { out = out + "\"" j = j + 2 } else { if nx == "\\" { out = out + "\\" j = j + 2 } else { if nx == "n" { out = out + "\n" j = j + 2 } else { if nx == "r" { out = out + "\r" j = j + 2 } else { if nx == "t" { out = out + "\t" j = j + 2 } else { if nx == "u" && j + 5 < n { out = out + src.substring(j, j+6) j = j + 6 } else { out = out + nx j = j + 2 } } } } } } } else { out = out + ch j = j + 1 } } me.gpos_set(j) return "{\"type\":\"Str\",\"value\":\"" + me.esc_json(out) + "\"}" } - - parse_factor2(src, i) { - local j = me.skip_ws(src, i) - if j >= src.length() { me.gpos_set(j) return "{\"type\":\"Int\",\"value\":0}" } - if me.starts_with_kw(src, j, "true") == 1 { me.gpos_set(j + 4) return "{\"type\":\"Bool\",\"value\":true}" } - if me.starts_with_kw(src, j, "false") == 1 { me.gpos_set(j + 5) return "{\"type\":\"Bool\",\"value\":false}" } - if me.starts_with_kw(src, j, "null") == 1 { me.gpos_set(j + 4) return "{\"type\":\"Null\"}" } - // Peek expression: peek { "label" => , ..., else => } - if me.starts_with_kw(src, j, "peek") == 1 { - j = j + 4 - j = me.skip_ws(src, j) - // scrutinee expression - local scr = me.parse_expr2(src, j) - j = me.gpos_get() - j = me.skip_ws(src, j) - if src.substring(j, j+1) == "{" { j = j + 1 } // enter arms block - j = me.skip_ws(src, j) - local arms_json = "[" - local first_arm = 1 - local else_json = null - local n = src.length() - local contp = 1 - local guardp = 0 - local maxp = 400000 - loop(contp == 1) { - if guardp > maxp { contp = 0 } else { guardp = guardp + 1 } - j = me.skip_ws(src, j) - if j >= n { contp = 0 } else { - if src.substring(j, j+1) == "}" { - j = j + 1 - contp = 0 - } else { - // else arm or labeled arm - if me.starts_with_kw(src, j, "else") == 1 { - j = j + 4 - j = me.skip_ws(src, j) - if src.substring(j, j+2) == "=>" { j = j + 2 } - j = me.skip_ws(src, j) - // else body may be a block or bare expr - if src.substring(j, j+1) == "{" { - j = j + 1 - j = me.skip_ws(src, j) - else_json = me.parse_expr2(src, j) - j = me.gpos_get() - j = me.skip_ws(src, j) - if src.substring(j, j+1) == "}" { j = j + 1 } - } else { - else_json = me.parse_expr2(src, j) - j = me.gpos_get() - } - // optional separator/newline tolerated; continue until '}' - } else { - // labeled arm: string literal label - if src.substring(j, j+1) != "\"" { - // degrade safely to avoid infinite loop - j = j + 1 - continue - } - local label_raw = me.read_string_lit(src, j) - j = me.gpos_get() - j = me.skip_ws(src, j) - if src.substring(j, j+2) == "=>" { j = j + 2 } - j = me.skip_ws(src, j) - // arm expr: block or bare expr - local expr_json = "{\"type\":\"Int\",\"value\":0}" - if src.substring(j, j+1) == "{" { - j = j + 1 - j = me.skip_ws(src, j) - expr_json = me.parse_expr2(src, j) - j = me.gpos_get() - j = me.skip_ws(src, j) - if src.substring(j, j+1) == "}" { j = j + 1 } - } else { - expr_json = me.parse_expr2(src, j) - j = me.gpos_get() - } - local arm_json = "{\"label\":\"" + me.esc_json(label_raw) + "\",\"expr\":" + expr_json + "}" - if first_arm == 1 { arms_json = arms_json + arm_json first_arm = 0 } else { arms_json = arms_json + "," + arm_json } - } - } - } - } - arms_json = arms_json + "]" - if else_json == null { else_json = "{\"type\":\"Null\"}" } - me.gpos_set(j) - return "{\"type\":\"Peek\",\"scrutinee\":" + scr + ",\"arms\":" + arms_json + ",\"else\":" + else_json + "}" - } - local ch = src.substring(j, j+1) - // Parenthesized - if ch == "(" { - local inner = me.parse_expr2(src, j + 1) - local k = me.gpos_get() - k = me.skip_ws(src, k) - if src.substring(k, k+1) == ")" { k = k + 1 } - me.gpos_set(k) - return inner - } - // String literal - if ch == "\"" { return me.parse_string2(src, j) } - // Map literal: {"k": v, ...} (string keys only) → Call{name:"map.of", args:[Str(k1), v1, Str(k2), v2, ...]} - if ch == "{" { - local n = src.length() - j = j + 1 - local out = "[" - local first = 1 - local cont = 1 - local guard = 0 - local max = 400000 - loop(cont == 1) { - if guard > max { cont = 0 } else { guard = guard + 1 } - j = me.skip_ws(src, j) - if j >= n { cont = 0 } else { - if src.substring(j, j+1) == "}" { j = j + 1 cont = 0 } else { - // key (string only for Stage-2) - if src.substring(j, j+1) != "\"" { - // degrade by skipping one char to avoid infinite loop - j = j + 1 - continue - } - local key_raw = me.read_string_lit(src, j) - j = me.gpos_get() - j = me.skip_ws(src, j) - if src.substring(j, j+1) == ":" { j = j + 1 } - j = me.skip_ws(src, j) - local val_json = me.parse_expr2(src, j) - j = me.gpos_get() - local key_json = "{\"type\":\"Str\",\"value\":\"" + me.esc_json(key_raw) + "\"}" - if first == 1 { out = out + key_json + "," + val_json first = 0 } else { out = out + "," + key_json + "," + val_json } - // optional comma - local before2 = j - j = me.skip_ws(src, j) - if j < n && src.substring(j, j+1) == "," { j = j + 1 } - // progress guard (in case of malformed input) - if j <= before2 { if j < n { j = j + 1 } else { j = n } } - } - } - } - out = out + "]" - me.gpos_set(j) - return "{\"type\":\"Call\",\"name\":\"map.of\",\"args\":" + out + "}" - } - // Array literal: [e1, e2, ...] → Call{name:"array.of", args:[...]} - if ch == "[" { - local n = src.length() - j = j + 1 - local out = "[" - local first = 1 - local cont = 1 - local guard = 0 - local max = 400000 - loop(cont == 1) { - if guard > max { cont = 0 } else { guard = guard + 1 } - j = me.skip_ws(src, j) - if j >= n { cont = 0 } else { - if src.substring(j, j+1) == "]" { j = j + 1 cont = 0 } else { - local before = j - local ej = me.parse_expr2(src, j) - j = me.gpos_get() - if first == 1 { out = out + ej first = 0 } else { out = out + "," + ej } - // optional comma+whitespace - local before2 = j - j = me.skip_ws(src, j) - if j < n && src.substring(j, j+1) == "," { j = j + 1 } - // progress guard - if j <= before { if j < n { j = j + 1 } else { j = n } } - } - } - } - out = out + "]" - me.gpos_set(j) - return "{\"type\":\"Call\",\"name\":\"array.of\",\"args\":" + out + "}" - } - // true/false - if me.starts_with_kw(src, j, "true") == 1 { me.gpos_set(j + 4) return "{\"type\":\"Bool\",\"value\":true}" } - if me.starts_with_kw(src, j, "false") == 1 { me.gpos_set(j + 5) return "{\"type\":\"Bool\",\"value\":false}" } - // new Class(args) - if me.starts_with_kw(src, j, "new") == 1 { - local p = me.skip_ws(src, j + 3) - local idp = me.read_ident2(src, p) - local at = idp.lastIndexOf("@") - local cls = idp.substring(0, at) - local k = me.to_int(idp.substring(at+1, idp.length())) - k = me.skip_ws(src, k) - if src.substring(k, k+1) == "(" { k = k + 1 } - local args_and_pos = me.parse_args2(src, k) - local at2 = args_and_pos.lastIndexOf("@") - local args_json = args_and_pos.substring(0, at2) - k = me.to_int(args_and_pos.substring(at2+1, args_and_pos.length())) - k = me.skip_ws(src, k) - if src.substring(k, k+1) == ")" { k = k + 1 } - me.gpos_set(k) - return "{\"type\":\"New\",\"class\":\"" + cls + "\",\"args\":" + args_json + "}" - } - // Identifier / Call / Method chain - if me.is_alpha(ch) { - local idp = me.read_ident2(src, j) - local at = idp.lastIndexOf("@") - local name = idp.substring(0, at) - local k = me.to_int(idp.substring(at+1, idp.length())) - local node = "{\"type\":\"Var\",\"name\":\"" + name + "\"}" - local cont2 = 1 - loop(cont2 == 1) { - k = me.skip_ws(src, k) - local tch = src.substring(k, k+1) - if tch == "(" { - k = k + 1 - local args_and_pos = me.parse_args2(src, k) - local at2 = args_and_pos.lastIndexOf("@") - local args_json = args_and_pos.substring(0, at2) - k = me.to_int(args_and_pos.substring(at2+1, args_and_pos.length())) - k = me.skip_ws(src, k) - if src.substring(k, k+1) == ")" { k = k + 1 } - node = "{\"type\":\"Call\",\"name\":\"" + name + "\",\"args\":" + args_json + "}" - } else { - if tch == "." { - k = k + 1 - k = me.skip_ws(src, k) - local midp = me.read_ident2(src, k) - local at3 = midp.lastIndexOf("@") - local mname = midp.substring(0, at3) - k = me.to_int(midp.substring(at3+1, midp.length())) - k = me.skip_ws(src, k) - if src.substring(k, k+1) == "(" { k = k + 1 } - local args2 = me.parse_args2(src, k) - local at4 = args2.lastIndexOf("@") - local args_json2 = args2.substring(0, at4) - k = me.to_int(args2.substring(at4+1, args2.length())) - k = me.skip_ws(src, k) - if src.substring(k, k+1) == ")" { k = k + 1 } - node = "{\"type\":\"Method\",\"recv\":" + node + ",\"method\":\"" + mname + "\",\"args\":" + args_json2 + "}" - } else { cont2 = 0 } - } - } - me.gpos_set(k) - return node - } - // Fallback: number - return me.parse_number2(src, j) - } - // unary minus binds tighter than * / - parse_unary2(src, i) { - local j = me.skip_ws(src, i) - if src.substring(j, j+1) == "-" { - local rhs = me.parse_factor2(src, j + 1) - j = me.gpos_get() - local zero = "{\"type\":\"Int\",\"value\":0}" - me.gpos_set(j) - return "{\"type\":\"Binary\",\"op\":\"-\",\"lhs\":" + zero + ",\"rhs\":" + rhs + "}" - } - return me.parse_factor2(src, j) - } - parse_term2(src, i) { local lhs = me.parse_unary2(src, i) local j = me.gpos_get() local cont = 1 loop(cont == 1) { j = me.skip_ws(src, j) if j >= src.length() { cont = 0 } else { local op = src.substring(j, j+1) if op != "*" && op != "/" { cont = 0 } else { local rhs = me.parse_unary2(src, j+1) j = me.gpos_get() lhs = "{\"type\":\"Binary\",\"op\":\"" + op + "\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" } } } me.gpos_set(j) return lhs } - parse_sum2(src, i) { local lhs = me.parse_term2(src, i) local j = me.gpos_get() local cont = 1 loop(cont == 1) { j = me.skip_ws(src, j) if j >= src.length() { cont = 0 } else { local op = src.substring(j, j+1) if op != "+" && op != "-" { cont = 0 } else { local rhs = me.parse_term2(src, j+1) j = me.gpos_get() lhs = "{\"type\":\"Binary\",\"op\":\"" + op + "\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" } } } me.gpos_set(j) return lhs } - parse_compare2(src, i) { local lhs = me.parse_sum2(src, i) local j = me.gpos_get() j = me.skip_ws(src, j) local two = src.substring(j, j+2) local one = src.substring(j, j+1) local op = "" if two == "==" || two == "!=" || two == "<=" || two == ">=" { op = two j = j + 2 } else { if one == "<" || one == ">" { op = one j = j + 1 } } if op == "" { me.gpos_set(j) return lhs } local rhs = me.parse_sum2(src, j) j = me.gpos_get() me.gpos_set(j) return "{\"type\":\"Compare\",\"op\":\"" + op + "\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" } - parse_expr2(src, i) { - local lhs = me.parse_compare2(src, i) - local j = me.gpos_get() - local cont = 1 - loop(cont == 1) { - j = me.skip_ws(src, j) - local two = src.substring(j, j+2) - if two != "&&" && two != "||" { cont = 0 } else { - local rhs = me.parse_compare2(src, j+2) - j = me.gpos_get() - lhs = "{\"type\":\"Logical\",\"op\":\"" + two + "\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" - } - } - j = me.skip_ws(src, j) - if src.substring(j, j+1) == "?" { - j = j + 1 - j = me.skip_ws(src, j) - local then_expr = me.parse_expr2(src, j) - j = me.gpos_get() - j = me.skip_ws(src, j) - if src.substring(j, j+1) == ":" { j = j + 1 } - j = me.skip_ws(src, j) - local else_expr = me.parse_expr2(src, j) - j = me.gpos_get() - if else_expr.length() == 0 { else_expr = "{\"type\":\"Int\",\"value\":0}" } - me.gpos_set(j) - return "{\"type\":\"Ternary\",\"cond\":" + lhs + ",\"then\":" + then_expr + ",\"else\":" + else_expr + "}" - } - me.gpos_set(j) - return lhs - } - parse_args2(src, i) { - local j = me.skip_ws(src, i) - local n = src.length() - local out = "[" - j = me.skip_ws(src, j) - if j < n && src.substring(j, j+1) == ")" { return "[]@" + me.i2s(j) } - // first argument - local e = me.parse_expr2(src, j) - j = me.gpos_get() - out = out + e - // subsequent arguments with guard - local cont_args = 1 - local guard = 0 - local max = 100000 - loop(cont_args == 1) { - if guard > max { cont_args = 0 } else { guard = guard + 1 } - local before = j - j = me.skip_ws(src, j) - if j < n && src.substring(j, j+1) == "," { - j = j + 1 - j = me.skip_ws(src, j) - e = me.parse_expr2(src, j) - j = me.gpos_get() - out = out + "," + e - } else { cont_args = 0 } - if j == before { cont_args = 0 } - } - out = out + "]" - return out + "@" + me.i2s(j) - } - parse_stmt2(src, i) { - local j = me.skip_ws(src, i) - local stmt_start = j - if me.starts_with_kw(src, j, "using") == 1 { - j = j + 5 - j = me.skip_ws(src, j) - if src.substring(j, j+1) == "\"" { - local p = me.read_string_lit(src, j) - j = me.gpos_get() - j = me.skip_ws(src, j) - local alias = null - if me.starts_with_kw(src, j, "as") == 1 { j = j + 2 j = me.skip_ws(src, j) local idp = me.read_ident2(src, j) local at = idp.lastIndexOf("@") alias = idp.substring(0, at) j = me.to_int(idp.substring(at+1, idp.length())) } - me.add_using("path", p, alias) - } else { - if me.is_alpha(src.substring(j, j+1)) { - local idp = me.read_ident2(src, j) - local at = idp.lastIndexOf("@") - local name = idp.substring(0, at) - j = me.to_int(idp.substring(at+1, idp.length())) - local cont = 1 - loop(cont == 1) { - j = me.skip_ws(src, j) - if src.substring(j, j+1) == "." { j = j + 1 j = me.skip_ws(src, j) idp = me.read_ident2(src, j) at = idp.lastIndexOf("@") name = name + "." + idp.substring(0, at) j = me.to_int(idp.substring(at+1, idp.length())) } else { cont = 0 } - } - j = me.skip_ws(src, j) - local alias2 = null - if me.starts_with_kw(src, j, "as") == 1 { j = j + 2 j = me.skip_ws(src, j) idp = me.read_ident2(src, j) at = idp.lastIndexOf("@") alias2 = idp.substring(0, at) j = me.to_int(idp.substring(at+1, idp.length())) } - me.add_using("ns", name, alias2) - } - } - // ensure progress - if j <= stmt_start { if j < src.length() { j = j + 1 } else { j = src.length() } } - me.gpos_set(j) - return "" - } - // simple assignment: IDENT '=' expr ; → JSON v0 Local{name, expr} (Stage‑2 uses Local for updates) - if j < src.length() && me.is_alpha(src.substring(j, j+1)) { - local idp0 = me.read_ident2(src, j) - local at0 = idp0.lastIndexOf("@") - if at0 > 0 { - local name0 = idp0.substring(0, at0) - local k0 = me.to_int(idp0.substring(at0+1, idp0.length())) - k0 = me.skip_ws(src, k0) - if k0 < src.length() && src.substring(k0, k0+1) == "=" { - local eq_two = "=" - if k0 + 1 < src.length() { eq_two = src.substring(k0, k0+2) } - if eq_two != "==" { - k0 = k0 + 1 - k0 = me.skip_ws(src, k0) - local default_local = "{\"type\":\"Int\",\"value\":0}" - local expr_json0 = default_local - local end_pos0 = k0 - if k0 < src.length() { - local ahead = src.substring(k0, k0+1) - if ahead != "}" && ahead != ";" { - expr_json0 = me.parse_expr2(src, k0) - end_pos0 = me.gpos_get() - } - } - k0 = end_pos0 - if k0 <= stmt_start { if k0 < src.length() { k0 = k0 + 1 } else { k0 = src.length() } } - me.gpos_set(k0) - return "{\"type\":\"Local\",\"name\":\"" + name0 + "\",\"expr\":" + expr_json0 + "}" - } - } - } - } - if me.starts_with_kw(src, j, "return") == 1 { - j = j + 6 - j = me.skip_ws(src, j) - local default_ret = "{\"type\":\"Int\",\"value\":0}" - local expr_json_ret = default_ret - local end_pos_ret = j - if j < src.length() { - local ahead_ret = src.substring(j, j+1) - if ahead_ret != "}" && ahead_ret != ";" { - expr_json_ret = me.parse_expr2(src, j) - end_pos_ret = me.gpos_get() - } - } - j = end_pos_ret - if j <= stmt_start { if j < src.length() { j = j + 1 } else { j = src.length() } } - me.gpos_set(j) - return "{\"type\":\"Return\",\"expr\":" + expr_json_ret + "}" - } - if me.starts_with_kw(src, j, "local") == 1 { - j = j + 5 - j = me.skip_ws(src, j) - local idp = me.read_ident2(src, j) - local at = idp.lastIndexOf("@") - local name = idp.substring(0, at) - j = me.to_int(idp.substring(at+1, idp.length())) - j = me.skip_ws(src, j) - if j < src.length() && src.substring(j, j+1) == "=" { j = j + 1 } - j = me.skip_ws(src, j) - local default_local = "{\"type\":\"Int\",\"value\":0}" - local expr_json_local = default_local - local end_pos_local = j - if j < src.length() { - local ahead_local = src.substring(j, j+1) - if ahead_local != "}" && ahead_local != ";" { - expr_json_local = me.parse_expr2(src, j) - end_pos_local = me.gpos_get() - } - } - j = end_pos_local - if j <= stmt_start { if j < src.length() { j = j + 1 } else { j = src.length() } } - me.gpos_set(j) - return "{\"type\":\"Local\",\"name\":\"" + name + "\",\"expr\":" + expr_json_local + "}" - } - if me.starts_with_kw(src, j, "if") == 1 { - j = j + 2 - j = me.skip_ws(src, j) - local paren = 0 - if src.substring(j, j+1) == "(" { paren = 1 j = j + 1 } - local cond = me.parse_expr2(src, j) - j = me.gpos_get() - if paren == 1 { j = me.skip_ws(src, j) if src.substring(j, j+1) == ")" { j = j + 1 } } - j = me.skip_ws(src, j) - local then_res = me.parse_block2(src, j) - local at1 = then_res.lastIndexOf("@") - local then_json = then_res.substring(0, at1) - j = me.to_int(then_res.substring(at1+1, then_res.length())) - j = me.skip_ws(src, j) - local else_json = null - if me.starts_with_kw(src, j, "else") == 1 { j = j + 4 j = me.skip_ws(src, j) local else_res = me.parse_block2(src, j) local at2 = else_res.lastIndexOf("@") else_json = else_res.substring(0, at2) j = me.to_int(else_res.substring(at2+1, else_res.length())) } - if j <= stmt_start { if j < src.length() { j = j + 1 } else { j = src.length() } } - me.gpos_set(j) - if else_json == null { return "{\"type\":\"If\",\"cond\":" + cond + ",\"then\":" + then_json + "}" } else { return "{\"type\":\"If\",\"cond\":" + cond + ",\"then\":" + then_json + ",\"else\":" + else_json + "}" } - } - if me.starts_with_kw(src, j, "loop") == 1 { - j = j + 4 - j = me.skip_ws(src, j) - if src.substring(j, j+1) == "(" { j = j + 1 } - local cond = me.parse_expr2(src, j) - j = me.gpos_get() - j = me.skip_ws(src, j) - if src.substring(j, j+1) == ")" { j = j + 1 } - j = me.skip_ws(src, j) - local body_res = me.parse_block2(src, j) - local at3 = body_res.lastIndexOf("@") - local body_json = body_res.substring(0, at3) - j = me.to_int(body_res.substring(at3+1, body_res.length())) - if j <= stmt_start { if j < src.length() { j = j + 1 } else { j = src.length() } } - me.gpos_set(j) - return "{\"type\":\"Loop\",\"cond\":" + cond + ",\"body\":" + body_json + "}" - } - // Stage-3 acceptance (syntax only): break / continue → no-op expression - if me.starts_with_kw(src, j, "break") == 1 { - j = j + 5 - if me.stage3_enabled() == 1 { - j = me.skip_ws(src, j) - if j <= stmt_start { if j < src.length() { j = j + 1 } else { j = src.length() } } - me.gpos_set(j) - return "{\"type\":\"Break\"}" - } - if j <= stmt_start { if j < src.length() { j = j + 1 } else { j = src.length() } } - me.gpos_set(j) - return "{\"type\":\"Expr\",\"expr\":{\"type\":\"Int\",\"value\":0}}" - } - if me.starts_with_kw(src, j, "continue") == 1 { - j = j + 8 - if me.stage3_enabled() == 1 { - j = me.skip_ws(src, j) - if j <= stmt_start { if j < src.length() { j = j + 1 } else { j = src.length() } } - me.gpos_set(j) - return "{\"type\":\"Continue\"}" - } - if j <= stmt_start { if j < src.length() { j = j + 1 } else { j = src.length() } } - me.gpos_set(j) - return "{\"type\":\"Expr\",\"expr\":{\"type\":\"Int\",\"value\":0}}" - } - // Stage-3 acceptance: throw expr → degrade to Expr(expr) - if me.starts_with_kw(src, j, "throw") == 1 { - j = j + 5 - j = me.skip_ws(src, j) - local e_throw = me.parse_expr2(src, j) - j = me.gpos_get() - if me.stage3_enabled() == 1 { - if j <= stmt_start { if j < src.length() { j = j + 1 } else { j = src.length() } } - me.gpos_set(j) - return "{\"type\":\"Throw\",\"expr\":" + e_throw + "}" - } - if j <= stmt_start { if j < src.length() { j = j + 1 } else { j = src.length() } } - me.gpos_set(j) - return "{\"type\":\"Expr\",\"expr\":" + e_throw + "}" - } - // Stage-3 acceptance: try { ... } (catch ...)* (cleanup { ... })? → degrade to no-op (syntax only) - if me.starts_with_kw(src, j, "try") == 1 { - j = j + 3 - j = me.skip_ws(src, j) - // parse try block - local try_res = me.parse_block2(src, j) - local at_t = try_res.lastIndexOf("@") - local try_json = try_res.substring(0, at_t) - j = me.to_int(try_res.substring(at_t+1, try_res.length())) - local catches_json = "[" - local catch_first = 1 - // zero or more catch - local guard_ct = 0 - local max_ct = 100 - local cont_ct = 1 - loop(cont_ct == 1) { - if guard_ct > max_ct { cont_ct = 0 } else { guard_ct = guard_ct + 1 } - j = me.skip_ws(src, j) - if me.starts_with_kw(src, j, "catch") == 1 { - j = j + 5 - j = me.skip_ws(src, j) - local catch_type = null - local catch_param = null - if src.substring(j, j+1) == "(" { j = j + 1 j = me.skip_ws(src, j) - // optional type + name - if me.is_alpha(src.substring(j, j+1)) { - local id1 = me.read_ident2(src, j) - local at1 = id1.lastIndexOf("@") - catch_type = id1.substring(0, at1) - j = me.to_int(id1.substring(at1+1, id1.length())) - j = me.skip_ws(src, j) - } - if me.is_alpha(src.substring(j, j+1)) { - local id2 = me.read_ident2(src, j) - local at2 = id2.lastIndexOf("@") - catch_param = id2.substring(0, at2) - j = me.to_int(id2.substring(at2+1, id2.length())) - j = me.skip_ws(src, j) - } - if src.substring(j, j+1) == ")" { j = j + 1 } - } - j = me.skip_ws(src, j) - // catch body - local c_res = me.parse_block2(src, j) - local atc = c_res.lastIndexOf("@") - j = me.to_int(c_res.substring(atc+1, c_res.length())) - if me.stage3_enabled() == 1 { - local entry = "{" - local wrote = 0 - if catch_param != null && catch_param.length() > 0 { entry = entry + "\"param\":\"" + me.esc_json(catch_param) + "\"" wrote = 1 } - if catch_type != null && catch_type.length() > 0 { if wrote == 1 { entry = entry + "," } entry = entry + "\"typeHint\":\"" + me.esc_json(catch_type) + "\"" wrote = 1 } - local body_json = c_res.substring(0, atc) - if wrote == 1 { entry = entry + "," } - entry = entry + "\"body\":" + body_json + "}" - if catch_first == 0 { catches_json = catches_json + "," + entry } else { catches_json = catches_json + entry catch_first = 0 } - } - } else { cont_ct = 0 } - } - catches_json = catches_json + "]" - // optional cleanup - j = me.skip_ws(src, j) - local finally_json = null - if me.starts_with_kw(src, j, "cleanup") == 1 { - j = j + 7 - j = me.skip_ws(src, j) - local f_res = me.parse_block2(src, j) - local atf = f_res.lastIndexOf("@") - j = me.to_int(f_res.substring(atf+1, f_res.length())) - finally_json = f_res.substring(0, atf) - } - if me.stage3_enabled() == 1 { - if j <= stmt_start { if j < src.length() { j = j + 1 } else { j = src.length() } } - me.gpos_set(j) - local node = "{\"type\":\"Try\",\"try\":" + try_json + ",\"catches\":" + catches_json - if finally_json != null { node = node + ",\"finally\":" + finally_json } - node = node + "}" - return node - } - if j <= stmt_start { if j < src.length() { j = j + 1 } else { j = src.length() } } - me.gpos_set(j) - return "{\"type\":\"Expr\",\"expr\":{\"type\":\"Int\",\"value\":0}}" - } - // Fallback: expression or unknown token — ensure progress even on malformed input - local expr_start = j - local e = me.parse_expr2(src, j) - j = me.gpos_get() - if j <= expr_start { if j < src.length() { j = j + 1 } else { j = src.length() } } - me.gpos_set(j) - return "{\"type\":\"Expr\",\"expr\":" + e + "}" - } - parse_block2(src, i) { - local j = me.skip_ws(src, i) - if src.substring(j, j+1) != "{" { return "[]@" + me.i2s(j) } - j = j + 1 - local body = "[" - local first = 1 - local cont_block = 1 - loop(cont_block == 1) { - j = me.skip_ws(src, j) - if j >= src.length() { cont_block = 0 } else { - if src.substring(j, j+1) == "}" { j = j + 1 cont_block = 0 } else { - local start_j = j - local s = me.parse_stmt2(src, j) - j = me.gpos_get() - // Progress guard: ensure forward movement to avoid infinite loop on malformed input - if j <= start_j { - if j < src.length() { j = j + 1 } else { j = src.length() } - me.gpos_set(j) - } - // consume optional semicolons (ASI minimal) - local done = 0 - local guard = 0 - local max = 100000 - loop(done == 0) { - if guard > max { done = 1 } else { guard = guard + 1 } - local before = j - j = me.skip_ws(src, j) - if j < src.length() && src.substring(j, j+1) == ";" { j = j + 1 } else { done = 1 } - if j == before { done = 1 } - } - if s.length() > 0 { if first == 1 { body = body + s first = 0 } else { body = body + "," + s } } - } - } - } - body = body + "]" - return body + "@" + me.i2s(j) - } - parse_program2(src) { - local i = me.skip_ws(src, 0) - local body = "[" - local first = 1 - local cont_prog = 1 - loop(cont_prog == 1) { - i = me.skip_ws(src, i) - if i >= src.length() { cont_prog = 0 } else { - local start_i = i - local s = me.parse_stmt2(src, i) - i = me.gpos_get() - // Progress guard: ensure forward movement to avoid infinite loop on malformed input - if i <= start_i { - if i < src.length() { i = i + 1 } else { i = src.length() } - me.gpos_set(i) - } - // consume optional semicolons between top-level statements - local done2 = 0 - local guard2 = 0 - local max2 = 100000 - loop(done2 == 0) { - if guard2 > max2 { done2 = 1 } else { guard2 = guard2 + 1 } - local before2 = i - i = me.skip_ws(src, i) - if i < src.length() && src.substring(i, i+1) == ";" { i = i + 1 } else { done2 = 1 } - if i == before2 { done2 = 1 } - } - if s.length() > 0 { if first == 1 { body = body + s first = 0 } else { body = body + "," + s } } - } - } - body = body + "]" - return "{\"version\":0,\"kind\":\"Program\",\"body\":" + body + "}" - } -} - -static box ParserStub { main(args) { return 0 } } diff --git a/apps/selfhost/compiler/compiler.nyash b/apps/selfhost/compiler/compiler.nyash deleted file mode 100644 index 67e4cb87..00000000 --- a/apps/selfhost/compiler/compiler.nyash +++ /dev/null @@ -1,158 +0,0 @@ -// 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 -using "apps/selfhost-compiler/boxes/debug_box.nyash" -using "apps/selfhost-compiler/boxes/parser_box.nyash" -using "apps/selfhost-compiler/boxes/emitter_box.nyash" -using "apps/selfhost-compiler/boxes/mir_emitter_box.nyash" -// Prepass libs (ScopeBox/LoopForm) -using "apps/lib/scopebox_inject.nyash" -using "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 - } -} diff --git a/apps/selfhost/compiler/emitter/json_v0.nyash b/apps/selfhost/compiler/emitter/json_v0.nyash deleted file mode 100644 index 4dab9a6a..00000000 --- a/apps/selfhost/compiler/emitter/json_v0.nyash +++ /dev/null @@ -1,8 +0,0 @@ -// JSON v0 emitter (MVP placeholder) -static box JsonV0Emitter { - // Emit a minimal Program{return 0} - program_return0() { - return "{\"version\":0,\"kind\":\"Program\",\"body\":[{\"type\":\"Return\",\"expr\":{\"type\":\"Int\",\"value\":0}}]}" - } -} - diff --git a/apps/selfhost/compiler/mir/builder.nyash b/apps/selfhost/compiler/mir/builder.nyash deleted file mode 100644 index 16324230..00000000 --- a/apps/selfhost/compiler/mir/builder.nyash +++ /dev/null @@ -1,5 +0,0 @@ -static box MirBuilder { - // placeholder - main(args) { return 0 } -} - diff --git a/apps/selfhost/compiler/mir/optimizer.nyash b/apps/selfhost/compiler/mir/optimizer.nyash deleted file mode 100644 index 4df27d1f..00000000 --- a/apps/selfhost/compiler/mir/optimizer.nyash +++ /dev/null @@ -1,5 +0,0 @@ -static box Optimizer { - // placeholder - main(args) { return 0 } -} - diff --git a/apps/selfhost/compiler/parser/ast.nyash b/apps/selfhost/compiler/parser/ast.nyash deleted file mode 100644 index 912dd3af..00000000 --- a/apps/selfhost/compiler/parser/ast.nyash +++ /dev/null @@ -1,5 +0,0 @@ -static box AST { - // scaffold for future AST node constructors - main(args) { return 0 } -} - diff --git a/apps/selfhost/compiler/parser/lexer.nyash b/apps/selfhost/compiler/parser/lexer.nyash deleted file mode 100644 index 06051d74..00000000 --- a/apps/selfhost/compiler/parser/lexer.nyash +++ /dev/null @@ -1,5 +0,0 @@ -static box Lexer { - // scaffold for future implementation - main(args) { return 0 } -} - diff --git a/apps/selfhost/compiler/parser/parser.nyash b/apps/selfhost/compiler/parser/parser.nyash deleted file mode 100644 index 70193cf8..00000000 --- a/apps/selfhost/compiler/parser/parser.nyash +++ /dev/null @@ -1,5 +0,0 @@ -static box Parser { - // scaffold for future implementation - main(args) { return 0 } -} - diff --git a/apps/selfhost/compiler/tests/stage1/README.md b/apps/selfhost/compiler/tests/stage1/README.md deleted file mode 100644 index 85a037a6..00000000 --- a/apps/selfhost/compiler/tests/stage1/README.md +++ /dev/null @@ -1,4 +0,0 @@ -Stage‑1 tests (scaffold) - -Add minimal Ny source samples here. Harness TBD. - diff --git a/apps/selfhost/ny-parser-nyash/README.md b/apps/selfhost/ny-parser-nyash/README.md deleted file mode 100644 index 81ed4222..00000000 --- a/apps/selfhost/ny-parser-nyash/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Ny Parser (v0) — Minimal Nyash-made Parser - -- Scope: integers, + - * /, parentheses, and a single `return` statement. -- Output: JSON IR v0 as documented in CURRENT_TASK.md (Program/Return/Int/Binary). - -Usage (Unix) -- echo "return 1+2*3" | ./tools/ny_parser_run.sh - -Usage (Windows PowerShell) -- Get-Content .\apps\ny-mir-samples\arithmetic.nyash | .\tools\ny_parser_run.ps1 - -Notes -- This is a minimal educational parser to bootstrap the self-host loop. -- Errors print a JSON envelope: {"version":0,"kind":"Error",...}. diff --git a/apps/selfhost/ny-parser-nyash/main.nyash b/apps/selfhost/ny-parser-nyash/main.nyash deleted file mode 100644 index b086c7d5..00000000 --- a/apps/selfhost/ny-parser-nyash/main.nyash +++ /dev/null @@ -1,29 +0,0 @@ -// Entry: read stdin, parse with ParserV0, print JSON IR or error JSON - -using "./apps/selfhost/ny-parser-nyash/parser_minimal.nyash" as ParserMod -using "./apps/selfhost/ny-parser-nyash/parser_minimal.nyash" - -static box Main { - main(args) { - local console = new ConsoleBox() - // Read all stdin - local buf = "" - loop(true) { - local line = console.readLine() - if line == null { break } - buf = buf + line + "\n" - } - if buf == "" { buf = "return 0\n" } - local ir = ParserV0.parse_program(buf) - // If already an Error envelope, print as-is - local s = ir.as_any().toString() - if s.indexOf("\"kind\":\"Error\"") >= 0 { - console.log(s) - return 1 - } - // Expect MapBox with Program; toJson available on MapBox - local json = ir.toJson() - console.log(json) - return 0 - } -} diff --git a/apps/selfhost/ny-parser-nyash/parser_minimal.nyash b/apps/selfhost/ny-parser-nyash/parser_minimal.nyash deleted file mode 100644 index bf58f9ff..00000000 --- a/apps/selfhost/ny-parser-nyash/parser_minimal.nyash +++ /dev/null @@ -1,88 +0,0 @@ -// Minimal recursive-descent parser for Ny v0 producing JSON IR v0 (MapBox) - -using "./apps/selfhost/ny-parser-nyash/tokenizer.nyash" as Tokenizer -using "./apps/selfhost/ny-parser-nyash/tokenizer.nyash" - -static box ParserV0 { - init { tokens, pos } - - parse_program(input) { - me.tokens = Tokenizer.tokenize(input) - // Error passthrough - if me.tokens.as_any().toString().indexOf("\"kind\":\"Error\"") >= 0 { - return me.tokens - } - me.pos = 0 - local stmt = me.parse_stmt() - if stmt.as_any().toString().indexOf("\"kind\":\"Error\"") >= 0 { return stmt } - local body = new ArrayBox(); body.push(stmt) - local prog = new MapBox(); prog.set("version", 0); prog.set("kind", "Program"); prog.set("body", body) - return prog - } - - parse_stmt() { - local tok = me.peek() - if tok.get("type") == "RETURN" { - me.next() - local expr = me.parse_expr() - if expr.as_any().toString().indexOf("\"kind\":\"Error\"") >= 0 { return expr } - local ret = new MapBox(); ret.set("type", "Return"); ret.set("expr", expr) - return ret - } - return me.err("Expected 'return'") - } - - parse_expr() { - local left = me.parse_term() - loop(true) { - local t = me.peek(); local ty = t.get("type") - if ty == "+" || ty == "-" { - me.next(); local right = me.parse_term() - left = me.bin(ty, left, right) - } else { break } - } - return left - } - - parse_term() { - local left = me.parse_factor() - loop(true) { - local t = me.peek(); local ty = t.get("type") - if ty == "*" || ty == "/" { - me.next(); local right = me.parse_factor() - left = me.bin(ty, left, right) - } else { break } - } - return left - } - - parse_factor() { - local t = me.peek(); local ty = t.get("type") - if ty == "INT" { - me.next(); - local node = new MapBox(); node.set("type", "Int"); node.set("value", t.get("value")) - return node - } - if ty == "(" { - me.next(); - local e = me.parse_expr() - local r = me.peek(); if r.get("type") != ")" { return me.err(") expected") } else { me.next() } - return e - } - return me.err("factor expected") - } - - // helpers - peek() { return me.tokens.get(me.pos) } - next() { me.pos = me.pos + 1; return me.tokens.get(me.pos-1) } - bin(op, lhs, rhs) { - local m = new MapBox(); m.set("type", "Binary"); m.set("op", op); m.set("lhs", lhs); m.set("rhs", rhs); return m - } - err(msg) { - local err = new MapBox(); err.set("version", 0); err.set("kind", "Error") - local e = new MapBox(); e.set("message", msg) - local sp = new MapBox(); sp.set("start", me.pos); sp.set("end", me.pos) - e.set("span", sp); err.set("error", e) - return err - } -} diff --git a/apps/selfhost/ny-parser-nyash/tokenizer.nyash b/apps/selfhost/ny-parser-nyash/tokenizer.nyash deleted file mode 100644 index f271002c..00000000 --- a/apps/selfhost/ny-parser-nyash/tokenizer.nyash +++ /dev/null @@ -1,55 +0,0 @@ -// Minimal tokenizer for Ny v0 (ints, + - * /, ( ), return) - -static box Tokenizer { - tokenize(input) { - local tokens = new ArrayBox() - local i = 0 - local n = input.length() - // helper: skip whitespace - fn skip_ws() { - loop(i < n) { - local ch = input.substring(i, i+1) - if ch == " " || ch == "\t" || ch == "\r" || ch == "\n" { i = i + 1 } else { return } - } - } - // main loop - loop(i < n) { - skip_ws() - if i >= n { break } - local ch = input.substring(i, i+1) - if ch == "+" || ch == "-" || ch == "*" || ch == "/" || ch == "(" || ch == ")" { - local tok = new MapBox(); tok.set("type", ch) - tokens.push(tok); i = i + 1; continue - } - // keyword: return - if i + 6 <= n { - local kw = input.substring(i, i+6) - if kw == "return" { - local t = new MapBox(); t.set("type", "RETURN") - tokens.push(t); i = i + 6; continue - } - } - // integer literal - if ch >= "0" && ch <= "9" { - local j = i - loop(j < n) { - local cj = input.substring(j, j+1) - if cj >= "0" && cj <= "9" { j = j + 1 } else { break } - } - local num_str = input.substring(i, j) - local tnum = new MapBox(); tnum.set("type", "INT"); tnum.set("value", num_str) - tokens.push(tnum); i = j; continue - } - // unknown - local err = new MapBox(); err.set("version", 0); err.set("kind", "Error") - local e = new MapBox(); e.set("message", "Unknown token"); - local sp = new MapBox(); sp.set("start", i); sp.set("end", i+1) - e.set("span", sp); err.set("error", e) - return err - } - // EOF - local eof = new MapBox(); eof.set("type", "EOF"); tokens.push(eof) - return tokens - } -} - diff --git a/apps/selfhost/parser/ny_parser_v0/main.nyash b/apps/selfhost/parser/ny_parser_v0/main.nyash deleted file mode 100644 index 0bb69775..00000000 --- a/apps/selfhost/parser/ny_parser_v0/main.nyash +++ /dev/null @@ -1,217 +0,0 @@ -// ny_parser_v0 — Stage 1 MVP: Ny -> JSON v0 (minimal) -// Supports: return ; expr ::= term (('+'|'-') term)* -// term ::= factor (('*'|'/') factor)* -// factor::= INT | STRING | '(' expr ')' - -static box Main { - // --- Utilities --- - is_digit(ch) { return ch >= "0" && ch <= "9" } - is_space(ch) { - return ch == " " || ch == "\t" || ch == "\n" || ch == "\r" - } - - esc_json(s) { - // escape backslash and quote for JSON strings - 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 - } - - // Cursor helpers over source string - skip_ws(src, i) { - local n = src.length() - loop(i < n && me.is_space(src.substring(i, i+1))) { i = i + 1 } - return i - } - - // (helper match removed; inline checks in parse_program) - - parse_number(src, i) { - // returns (json, next_i) - local n = src.length() - local j = i - loop(j < n && me.is_digit(src.substring(j, j+1))) { j = j + 1 } - local s = src.substring(i, j) - local json = "{\"type\":\"Int\",\"value\":" + s + "}" - return json + "@" + j // pack result with '@' separator - } - - parse_string(src, i) { - local n = src.length() - local j = i + 1 // skip opening quote - local out = "" - loop(j < n) { - local ch = src.substring(j, j+1) - if ch == "\"" { - j = j + 1 - local json0 = "{\"type\":\"Str\",\"value\":\"" + me.esc_json(out) + "\"}" - return json0 + "@" + j - } - if ch == "\\" && j + 1 < n { - local nx = src.substring(j+1, j+2) - // minimal escapes (\" and \\) - if nx == "\"" { out = out + "\"" } else { if nx == "\\" { out = out + "\\" } else { out = out + nx } } - j = j + 2 - } else { - out = out + ch - j = j + 1 - } - } - // Unterminated string (fallback) - local json = "{\"type\":\"Str\",\"value\":\"" + me.esc_json(out) + "\"}" - return json + "@" + j - } - - // Recursive descent - parse_factor(src, i) { - // skip ws - local nsrc = src.length() - loop(i < nsrc && me.is_space(src.substring(i, i+1))) { i = i + 1 } - local ch = src.substring(i, i+1) - if ch == "(" { - // (expr) - local p = me.parse_expr(src, i + 1) - local at = p.lastIndexOf("@") - local ej = p.substring(0, at) - local j = me.to_int(p.substring(at+1, p.length())) - // skip ws - local n2 = src.length() - loop(j < n2 && me.is_space(src.substring(j, j+1))) { j = j + 1 } - if src.substring(j, j+1) == ")" { j = j + 1 } - return ej + "@" + j - } - if ch == "\"" { return me.parse_string(src, i) } - // number - return me.parse_number(src, i) - } - - parse_term(src, i) { - local p = me.parse_factor(src, i) - local at = p.lastIndexOf("@") - local lhs = p.substring(0, at) - local j = me.to_int(p.substring(at+1, p.length())) - local cont = 1 - loop(cont == 1) { - // skip ws - local n3 = src.length() - loop(j < n3 && me.is_space(src.substring(j, j+1))) { j = j + 1 } - if j >= src.length() { cont = 0 } else { - local op = src.substring(j, j+1) - if op != "*" && op != "/" { cont = 0 } else { - // parse rhs - local q = me.parse_factor(src, j+1) - local at2 = q.lastIndexOf("@") - local rhs = q.substring(0, at2) - j = me.to_int(q.substring(at2+1, q.length())) - lhs = "{\"type\":\"Binary\",\"op\":\"" + op + "\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" - } - } - } - return lhs + "@" + j - } - - parse_expr(src, i) { - local p = me.parse_term(src, i) - local at = p.lastIndexOf("@") - local lhs = p.substring(0, at) - local j = me.to_int(p.substring(at+1, p.length())) - local cont = 1 - loop(cont == 1) { - // skip ws - local n4 = src.length() - loop(j < n4 && me.is_space(src.substring(j, j+1))) { j = j + 1 } - if j >= src.length() { cont = 0 } else { - local op = src.substring(j, j+1) - if op != "+" && op != "-" { cont = 0 } else { - // parse rhs - local q = me.parse_term(src, j+1) - local at2 = q.lastIndexOf("@") - local rhs = q.substring(0, at2) - j = me.to_int(q.substring(at2+1, q.length())) - lhs = "{\"type\":\"Binary\",\"op\":\"" + op + "\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" - } - } - } - return lhs + "@" + j - } - - to_int(s) { - // parse decimal int from string s - // 簡易に桁を読む(ここでは利用側が整数のみで使う) - // ただしここは内部専用で index を取り出すだけなので、s は数字のみ想定 - // 実装簡略化のため、長さ0なら0、それ以外は手動で畳み込み - local n = s.length() - if n == 0 { return 0 } - local i = 0 - local acc = 0 - loop(i < n) { - local d = s.substring(i, i+1) - local dv = 0 - if d == "1" { dv = 1 } else { - if d == "2" { dv = 2 } else { - if d == "3" { dv = 3 } else { - if d == "4" { dv = 4 } else { - if d == "5" { dv = 5 } else { - if d == "6" { dv = 6 } else { - if d == "7" { dv = 7 } else { - if d == "8" { dv = 8 } else { - if d == "9" { dv = 9 } - } - } - } - } - } - } - } - } - acc = acc * 10 + dv - i = i + 1 - } - return acc - } - - parse_program(src) { - // optional leading ws + optional 'return' - // skip leading ws - local i = 0 - local n0 = src.length() - loop(i < n0 && me.is_space(src.substring(i, i+1))) { i = i + 1 } - local j = i - local n = src.length() - if i + 6 <= n && src.substring(i, i+6) == "return" { j = i + 6 } - local p = me.parse_expr(src, j) - local at = p.lastIndexOf("@") - local ej = p.substring(0, at) - local body = "[{\"type\":\"Return\",\"expr\":" + ej + "}]" - return "{\"version\":0,\"kind\":\"Program\",\"body\":" + body + "}" - } - - read_all(path) { - local fb = new FileBox() - fb.open(path, "r") - local s = fb.read() - fb.close() - return s - } - - main(args) { - // usage: nyash --backend vm apps/selfhost/parser/ny_parser_v0/main.nyash - // Input source is read from tmp/ny_parser_input.ny (written by wrapper script) - local console = new ConsoleBox() - local src = null - local default_path = "tmp/ny_parser_input.ny" - src = me.read_all(default_path) - if src == null { src = "return 1+2*3" } - local json = me.parse_program(src) - console.println(json) - return 0 - } -} diff --git a/apps/selfhost/smokes/dep_smoke_child.nyash b/apps/selfhost/smokes/dep_smoke_child.nyash deleted file mode 100644 index f4e2ab3f..00000000 --- a/apps/selfhost/smokes/dep_smoke_child.nyash +++ /dev/null @@ -1,7 +0,0 @@ -// child file -box Child { - hello() { - return 1 - } -} - diff --git a/apps/selfhost/smokes/dep_smoke_cycle_a.nyash b/apps/selfhost/smokes/dep_smoke_cycle_a.nyash deleted file mode 100644 index d3f050fe..00000000 --- a/apps/selfhost/smokes/dep_smoke_cycle_a.nyash +++ /dev/null @@ -1,6 +0,0 @@ -// cycle A -> B -> A -using "dep_smoke_cycle_b.nyash" - -box A { - id() { return 1 } -} diff --git a/apps/selfhost/smokes/dep_smoke_cycle_b.nyash b/apps/selfhost/smokes/dep_smoke_cycle_b.nyash deleted file mode 100644 index 220c43be..00000000 --- a/apps/selfhost/smokes/dep_smoke_cycle_b.nyash +++ /dev/null @@ -1,6 +0,0 @@ -// cycle B -> A -using "dep_smoke_cycle_a.nyash" - -box B { - id() { return 2 } -} diff --git a/apps/selfhost/smokes/dep_smoke_root.nyash b/apps/selfhost/smokes/dep_smoke_root.nyash deleted file mode 100644 index c9151118..00000000 --- a/apps/selfhost/smokes/dep_smoke_root.nyash +++ /dev/null @@ -1,13 +0,0 @@ -// root smoke for include-only tree -using "dep_smoke_child.nyash" - -box Root { - main() { - // a string containing include "should_not_match.nyash" - local s = "text include \"dummy.nyash\" text" - // a comment with include "ignored.nyash" - // include "ignored.nyash" - # include "ignored2.nyash" - return 0 - } -} diff --git a/apps/selfhost/tools/dep_tree.nyash b/apps/selfhost/tools/dep_tree.nyash deleted file mode 100644 index 7e1a9588..00000000 --- a/apps/selfhost/tools/dep_tree.nyash +++ /dev/null @@ -1,253 +0,0 @@ -// dep_tree.nyash — Build dependency info for a Nyash script (include + using/module) - -static box DepTree { - init { visited } - - // Public API: build tree for entry path - build(entry_path) { - me.visited = new MapBox() - return me.node(entry_path) - } - - // Read entire file as string via FileBox - read_file(path) { - local fb = new FileBox() - local ok = fb.open(path, "r") - if ok == false { return null } - local content = fb.read() - fb.close() - return content - } - - // Extract include paths from source: include "./path.nyash" - extract_includes(src) { - local out = new ArrayBox() - if src == null { return out } - local i = 0 - local n = src.length() - loop(i < n) { - local j = src.indexOf("include \"", i) - if j < 0 { break } - local k = j + 9 // after include " - local q = src.indexOf("\"", k) - if q < 0 { break } - out.push(src.substring(k, q)) - i = q + 1 - } - return out - } - - // Extract using directives (script lines): - // using ns - // using ns as Alias - // using "path" as Name - // and comment form: // @using ns[ as Alias] - extract_usings(src) { - local out = new ArrayBox() - if src == null { return out } - local lines = me.split_lines(src) - local i = 0 - loop(i < lines.length()) { - local line = lines.get(i).trim() - local t = line - if t.startsWith("// @using ") { t = t.substring(10, t.length()).trim() } - else if t.startsWith("using ") { t = t.substring(6, t.length()).trim() } - else { i = i + 1; continue } - - // optional trailing semicolon - if t.endsWith(";") { t = t.substring(0, t.length()-1).trim() } - - local rec = new MapBox() - // Split alias - local as_pos = t.indexOf(" as ") - local target = t - local alias = null - if as_pos >= 0 { - target = t.substring(0, as_pos).trim() - alias = t.substring(as_pos+4, t.length()).trim() - } - rec.set("target", target) - if alias != null { rec.set("alias", alias) } - // classify - if target.startsWith("\"") || target.startsWith("./") || target.startsWith("/") || target.endsWith(".nyash") { - rec.set("kind", "path") - // strip quotes - if target.startsWith("\"") { rec.set("target", target.substring(1, target.length()-1)) } - } else { - rec.set("kind", "ns") - } - out.push(rec) - i = i + 1 - } - return out - } - - // Extract modules mapping from // @module ns=path - extract_modules(src) { - local out = new ArrayBox() - if src != null { - local lines = me.split_lines(src) - local i = 0 - loop(i < lines.length()) { - local line = lines.get(i).trim() - if line.startsWith("// @module ") { - local rest = line.substring(11, line.length()).trim() - local eq = rest.indexOf("=") - if eq > 0 { - local ns = rest.substring(0, eq).trim() - local path = rest.substring(eq+1, rest.length()).trim() - path = me.strip_quotes(path) - local m = new MapBox(); m.set("ns", ns); m.set("path", path); out.push(m) - } - } - i = i + 1 - } - } - return out - } - - // Build a node: { path, includes:[...], using:[...], modules:[...], children:[...] } - node(path) { - if me.visited.has(path) { return me.leaf(path) } - me.visited.set(path, true) - - local m = new MapBox(); m.set("path", path) - local src = me.read_file(path) - if src == null { m.set("error", "read_fail"); me.ensure_arrays(m); return m } - - local base_dir = me.dirname(path) - - // includes - local incs = me.extract_includes(src) - m.set("includes", incs) - // usings - local us = me.extract_usings(src) - m.set("using", us) - // modules mapping (script-level) - local mods = me.extract_modules(src) - m.set("modules", mods) - - // children = includes + resolved using(path) + resolved using(ns via search paths) - local children = new ArrayBox() - // include children - local i = 0 - loop(i < incs.length()) { - local p = incs.get(i) - local child_path = me.resolve_path(base_dir, p) - children.push(me.node(child_path)) - i = i + 1 - } - // using(path) children - i = 0 - loop(i < us.length()) { - local u = us.get(i) - if u.get("kind") == "path" { - local p = u.get("target") - local child_path = me.resolve_path(base_dir, p) - children.push(me.node(child_path)) - } - i = i + 1 - } - // using(ns) children resolved via search paths - local search = me.default_using_paths() - i = 0 - loop(i < us.length()) { - local u = us.get(i) - if u.get("kind") == "ns" { - local ns = u.get("target") - local rel = ns.replace(".", "/") + ".nyash" - local found = me.search_in_paths(base_dir, search, rel) - if found != null { children.push(me.node(found)) } - else { - // annotate unresolved - u.set("unresolved", true) - u.set("hint", rel) - } - } - i = i + 1 - } - - m.set("children", children) - return m - } - - // Helpers - ensure_arrays(m) { m.set("includes", new ArrayBox()); m.set("using", new ArrayBox()); m.set("modules", new ArrayBox()); m.set("children", new ArrayBox()) } - - default_using_paths() { - // Best-effort defaults prioritized for selfhost - local arr = new ArrayBox() - arr.push("apps/selfhost"); arr.push("apps"); arr.push("lib"); arr.push(".") - return arr - } - - split_lines(src) { - local out = new ArrayBox() - local i = 0; local n = src.length(); local start = 0 - loop(i <= n) { - if i == n || src.substring(i, i+1) == "\n" { - out.push(src.substring(start, i)) - start = i + 1 - } - i = i + 1 - } - return out - } - - strip_quotes(s) { - if s == null { return null } - if s.length() >= 2 && s.substring(0,1) == "\"" && s.substring(s.length()-1, s.length()) == "\"" { - return s.substring(1, s.length()-1) - } - return s - } - - dirname(path) { - local pb = new PathBox(); - local d = pb.dirname(path) - if d != null { return d } - local i = path.lastIndexOf("/") - if i < 0 { return "." } - return path.substring(0, i) - } - - resolve_path(base, rel) { - if rel.indexOf("/") == 0 { return rel } - if rel.startsWith("./") || rel.startsWith("../") { - local pb = new PathBox(); - local j = pb.join(base, rel) - if j != null { return j } - return base + "/" + rel - } - return rel - } - - search_in_paths(base, paths, rel) { - // try relative to file first - local pb = new PathBox(); - local j = pb.join(base, rel) - if me.file_exists(j) { return j } - // then search list - local i = 0 - loop(i < paths.length()) { - local p = paths.get(i) - local cand = pb.join(p, rel) - if me.file_exists(cand) { return cand } - i = i + 1 - } - return null - } - - file_exists(path) { - // Use FileBox.open in read mode as exists check - local fb = new FileBox(); - local ok = fb.open(path, "r") - if ok == false { return false } - fb.close(); return true - } - - leaf(path) { - local m = new MapBox(); m.set("path", path); m.set("children", new ArrayBox()); m.set("note", "visited") - return m - } -} diff --git a/apps/selfhost/tools/dep_tree_main.nyash b/apps/selfhost/tools/dep_tree_main.nyash deleted file mode 100644 index 2518036d..00000000 --- a/apps/selfhost/tools/dep_tree_main.nyash +++ /dev/null @@ -1,19 +0,0 @@ -// dep_tree_main.nyash — entry script to print JSON tree - -using "./apps/selfhost/tools/dep_tree.nyash" as DepTree -using "./apps/selfhost/tools/dep_tree.nyash" - -static box Main { - main(args) { - local console = new ConsoleBox() - local path = null - if args != null && args.length() >= 1 { path = args.get(0) } - if path == null || path == "" { - // default sample - path = "apps/selfhost/ny-parser-nyash/main.nyash" - } - local tree = DepTree.build(path) - console.println(tree.toJson()) - return 0 - } -} diff --git a/apps/selfhost/tools/dep_tree_min_string.nyash b/apps/selfhost/tools/dep_tree_min_string.nyash deleted file mode 100644 index bc6acee1..00000000 --- a/apps/selfhost/tools/dep_tree_min_string.nyash +++ /dev/null @@ -1,159 +0,0 @@ -// dep_tree_min_string.nyash — minimal include-only dependency tree (no Array/Map plugins) - -static box Main { - has_in_stack(stack, p) { - // check if stack contains "\n" + p + "\n" - local t = "\n" + p + "\n" - local n = stack.length() - local m = t.length() - if m == 0 { return 0 } - local i = 0 - loop(i + m <= n) { - if stack.substring(i, i+m) == t { return 1 } - i = i + 1 - } - return 0 - } - read_all(path) { - local fb = new FileBox() - local ok = fb.open(path, "r") - if ok == false { return null } - local s = fb.read() - fb.close() - return s - } - - dirname(path) { - local pb = new PathBox() - local d = pb.dirname(path) - if d != null { return d } - local i = path.lastIndexOf("/") - if i < 0 { return "." } - return path.substring(0, i) - } - - join(base, rel) { - local pb = new PathBox() - local j = pb.join(base, rel) - if j != null { return j } - return base + "/" + rel - } - - esc_json(s) { - // very small escaper: replace \ and " - 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 - } - - node_json(path, stack, depth) { - // safety valve: max depth - if depth >= 64 { - return "{\\\"path\\\":\\\"" + me.esc_json(path) + "\\\",\\\"includes\\\":[],\\\"children\\\":[]}" - } - local src = me.read_all(path) - if src == null { - return "{\\\"path\\\":\\\"" + me.esc_json(path) + "\\\",\\\"includes\\\":[],\\\"children\\\":[]}" - } - local base = me.dirname(path) - local incs = "" - local inc_first = 1 - local children = "" - local child_first = 1 - local i = 0 - local n = src.length() - local in_str = 0 - local in_cmt = 0 - loop(i < n) { - local ch = src.substring(i, i+1) - // handle line comments (// or #) - if in_cmt == 1 { - if ch == "\n" { in_cmt = 0 } - i = i + 1 - } else if in_str == 1 { - if ch == "\"" { - // if previous is not backslash, close - if i == 0 { in_str = 0 } else { - local prev = src.substring(i-1, i) - if prev != "\\" { in_str = 0 } - } - } - i = i + 1 - } else if ch == "/" && i + 1 < n && src.substring(i+1, i+2) == "/" { - // start // comment - in_cmt = 1 - i = i + 2 - } else if ch == "#" { - // start # comment - in_cmt = 1 - i = i + 1 - } else if ch == "\"" { - // enter string - in_str = 1 - i = i + 1 - } else if i + 9 <= n && src.substring(i, i+9) == "include \"" { - // look for include "..." - local j = i + 9 - // find closing quote (respect escapes) without using break - local found = 0 - loop(j < n && found == 0) { - if src.substring(j, j+1) == "\"" { - local prev = src.substring(j-1, j) - if prev != "\\" { found = 1 } else { j = j + 1 } - } else { - j = j + 1 - } - } - if found == 1 { - local p = src.substring(i+9, j) - if inc_first == 1 { - incs = incs + "\"" + me.esc_json(p) + "\"" - inc_first = 0 - } else { - incs = incs + ",\"" + me.esc_json(p) + "\"" - } - local child_path = me.join(base, p) - // cycle detection: if child_path already in stack, do not recurse - local cj = null - if me.has_in_stack(stack, child_path) == 1 { - cj = "{\\\"path\\\":\\\"" + me.esc_json(child_path) + "\\\",\\\"includes\\\":[],\\\"children\\\":[]}" - } else { - cj = me.node_json(child_path, stack + child_path + "\n", depth + 1) - } - if child_first == 1 { - children = children + cj - child_first = 0 - } else { - children = children + "," + cj - } - i = j + 1 - } else { - i = i + 1 - } - } else { - i = i + 1 - } - } - return "{\\\"path\\\":\\\"" + me.esc_json(path) + "\\\",\\\"includes\\\":[" + incs + "],\\\"children\\\":[" + children + "]}" - } - - main(args) { - local console = new ConsoleBox() - // Determine entry path (avoid stdin to keep VM path simple) - local entry = null - if args != null && args.length() >= 1 { entry = args.get(0) } - if entry == null || entry == "" { entry = "apps/selfhost/ny-parser-nyash/main.nyash" } - local tree = me.node_json(entry, "\n" + entry + "\n", 0) - local out = "{\\\"version\\\":1,\\\"root_path\\\":\\\"" + me.esc_json(entry) + "\\\",\\\"tree\\\":" + tree + "}" - console.println(out) - return 0 - } -} diff --git a/apps/selfhost/tools/dep_tree_simple.nyash b/apps/selfhost/tools/dep_tree_simple.nyash deleted file mode 100644 index c08d4a81..00000000 --- a/apps/selfhost/tools/dep_tree_simple.nyash +++ /dev/null @@ -1,265 +0,0 @@ -// dep_tree_simple.nyash — dependency tree (include + using/module) in a single static box - -static box Main { - // ---- file utils ---- - read_all(path) { - local fb = new FileBox() - local ok = fb.open(path, "r") - if ok == false { return null } - local s = fb.read() - fb.close() - return s - } - - file_exists(path) { - local fb = new FileBox() - local ok = fb.open(path, "r") - if ok == false { return false } - fb.close() - return true - } - - dirname(path) { - local pb = new PathBox() - local d = pb.dirname(path) - if d != null { return d } - local i = path.lastIndexOf("/") - if i < 0 { return "." } - return path.substring(0, i) - } - - join(base, rel) { - local pb = new PathBox() - local j = pb.join(base, rel) - if j != null { return j } - return base + "/" + rel - } - - // ---- text utils ---- - split_lines(src) { - // return { arr, len } - local pair = new MapBox() - local out = new ArrayBox() - local len = 0 - local i = 0 - local n = src.length() - local start = 0 - loop(true) { - if i == n { out.push(src.substring(start, i)) len = len + 1 pair.set("arr", out) pair.set("len", len) return pair } - local ch = src.substring(i, i+1) - if ch == "\n" { out.push(src.substring(start, i)) len = len + 1 start = i + 1 } - i = i + 1 - } - pair.set("arr", out) - pair.set("len", len) - return pair - } - - // ---- scanners ---- - scan_includes(src) { - local pair = new MapBox() - local out = new ArrayBox() - local out_len = 0 - if src == null { pair.set("arr", out) pair.set("len", out_len) return pair } - local lp = me.split_lines(src) - local lines = lp.get("arr") - local lines_len = lp.get("len") - local i = 0 - loop(i < lines_len) { - local t = lines.get(i).trim() - if t.startsWith("include \"") { - local rest = t.substring(9, t.length()) - local j = 0 - local q = -1 - loop(j < rest.length()) { - if rest.substring(j, j+1) == "\"" { q = j j = rest.length() } - j = j + 1 - } - if q >= 0 { out.push(rest.substring(0, q)) out_len = out_len + 1 } - } - i = i + 1 - } - pair.set("arr", out) - pair.set("len", out_len) - return pair - } - - scan_usings(src) { - // return { arr, len } - local pair = new MapBox() - local out = new ArrayBox() - local out_len = 0 - if src == null { pair.set("arr", out) pair.set("len", out_len) return pair } - local lp = me.split_lines(src) - local lines = lp.get("arr") - local lines_len = lp.get("len") - local i = 0 - loop(i < lines_len) { - local t0 = lines.get(i).trim() - local matched = false - local t = t0 - if t0.startsWith("// @using ") { t = t0.substring(10, t0.length()) matched = true } else { - if t0.startsWith("using ") { t = t0.substring(6, t0.length()) matched = true } - } - if matched { - local as_pos = t.indexOf(" as ") - local target = t - local alias = null - if as_pos >= 0 { target = t.substring(0, as_pos).trim() alias = t.substring(as_pos+4, t.length()).trim() } - local rec = new MapBox() - rec.set("target", target) - if alias != null { rec.set("alias", alias) } - if target.startsWith("./") || target.startsWith("/") || target.endsWith(".nyash") { rec.set("kind", "path") } else { rec.set("kind", "namespace") } - out.push(rec) - out_len = out_len + 1 - } - i = i + 1 - } - pair.set("arr", out) - pair.set("len", out_len) - return pair - } - - scan_modules(src) { - // return { arr, len } - local pair = new MapBox() - local out = new ArrayBox() - local out_len = 0 - if src == null { pair.set("arr", out) pair.set("len", out_len) return pair } - local lp = me.split_lines(src) - local lines = lp.get("arr") - local lines_len = lp.get("len") - local i = 0 - loop(i < lines_len) { - local t = lines.get(i).trim() - if t.startsWith("// @module ") { - local rest = t.substring(11, t.length()) - local eq = rest.indexOf("=") - if eq > 0 { - local ns = rest.substring(0, eq).trim() - local path = rest.substring(eq+1, t.length()).trim() - local m = new MapBox() - m.set("namespace", ns) - m.set("path", path) - out.push(m) - out_len = out_len + 1 - } - } - i = i + 1 - } - pair.set("arr", out) - pair.set("len", out_len) - return pair - } - - default_using_paths() { - local a = new ArrayBox() - a.push("apps/selfhost") - a.push("apps") - a.push("lib") - a.push(".") - return a - } - - resolve_ns(base_dir, ns) { - local rel = ns.replace(".", "/") + ".nyash" - local cand0 = me.join(base_dir, rel) - if me.file_exists(cand0) { return cand0 } - local paths = me.default_using_paths() - local paths_len = 4 - local i = 0 - loop(i < paths_len) { - local cand = me.join(paths.get(i), rel) - if me.file_exists(cand) { return cand } - i = i + 1 - } - return null - } - - node_for(path, visited) { - if visited.has(path) { - local m = new MapBox() - m.set("path", path) - m.set("children", new ArrayBox()) - m.set("includes", new ArrayBox()) - m.set("uses", new ArrayBox()) - m.set("modules", new ArrayBox()) - m.set("note", "visited") - return m - } - visited.set(path, true) - local out = new MapBox() - out.set("path", path) - local src = me.read_all(path) - if src == null { - out.set("error", "read_fail") - out.set("includes", new ArrayBox()) - out.set("uses", new ArrayBox()) - out.set("modules", new ArrayBox()) - out.set("children", new ArrayBox()) - return out - } - local base = me.dirname(path) - local incp = me.scan_includes(src) - local incs = incp.get("arr") - local incs_len = incp.get("len") - local usp = me.scan_usings(src) - local uses = usp.get("arr") - local uses_len = usp.get("len") - local modp = me.scan_modules(src) - local mods = modp.get("arr") - local mods_len = modp.get("len") - out.set("includes", incs) - out.set("uses", uses) - out.set("modules", mods) - local mod_map = new MapBox() - local mi = 0 - loop(mi < mods_len) { - local mm = mods.get(mi) - mod_map.set(mm.get("namespace"), mm.get("path")) - mi = mi + 1 - } - local children = new ArrayBox() - local i = 0 - loop(i < incs_len) { - local child_path = me.join(base, incs.get(i)) - children.push(me.node_for(child_path, visited)) - i = i + 1 - } - i = 0 - loop(i < uses_len) { - local u = uses.get(i) - if u.get("kind") == "path" { - local p = me.join(base, u.get("target")) - if me.file_exists(p) { u.set("resolved", p) children.push(me.node_for(p, visited)) } else { u.set("unresolved", true) u.set("hint", p) } - } else { - local tgt = u.get("target") - local via = mod_map.get(tgt) - if via != null { - if me.file_exists(via) { u.set("resolved", via) children.push(me.node_for(via, visited)) } else { u.set("unresolved", true) u.set("hint", via) } - } else { - local found = me.resolve_ns(base, tgt) - if found != null { u.set("resolved", found) children.push(me.node_for(found, visited)) } else { u.set("unresolved", true) u.set("hint", tgt) } - } - } - i = i + 1 - } - out.set("children", children) - return out - } - - main(args) { - local console = new ConsoleBox() - local entry = null - if args != null && args.length() >= 1 { entry = args.get(0) } - if entry == null || entry == "" { entry = "apps/selfhost/ny-parser-nyash/main.nyash" } - local visited = new MapBox() - local tree = me.node_for(entry, visited) - local root = new MapBox() - root.set("version", 1) - root.set("root_path", entry) - root.set("tree", tree) - console.println(root.toJson()) - return 0 - } -} diff --git a/apps/selfhost/vm/README.md b/apps/selfhost/vm/README.md deleted file mode 100644 index d2a1ec3a..00000000 --- a/apps/selfhost/vm/README.md +++ /dev/null @@ -1,14 +0,0 @@ -Layer Guard — selfhost/vm - -Scope and responsibility -- Minimal Ny-based executors and helpers for self‑hosting experiments. -- Responsibilities: trial executors (MIR JSON v0), tiny helpers (scan/binop/compare), smoke drivers. -- Forbidden: full parser implementation, heavy runtime logic, code generation. - -Imports policy (SSOT) -- Dev/CI: file-using allowed; drivers may embed JSON for tiny smokes. -- Prod: prefer `nyash.toml` mapping under `[modules.selfhost.*]`. - -Notes -- MirVmMin covers: const/binop/compare/ret (M2). Branch/jump/phi are later. -- Keep changes minimal and spec‑neutral; new behavior is gated by new tests. diff --git a/apps/selfhost/vm/boxes/json_cur.nyash b/apps/selfhost/vm/boxes/json_cur.nyash deleted file mode 100644 index b85de8e5..00000000 --- a/apps/selfhost/vm/boxes/json_cur.nyash +++ /dev/null @@ -1,61 +0,0 @@ -// Mini-VM JSON cursor helpers (extracted) -// One static box per file per using/include policy -static box MiniJsonCur { - _is_digit(ch) { if ch == "0" { return 1 } if ch == "1" { return 1 } if ch == "2" { return 1 } if ch == "3" { return 1 } if ch == "4" { return 1 } if ch == "5" { return 1 } if ch == "6" { return 1 } if ch == "7" { return 1 } if ch == "8" { return 1 } if ch == "9" { return 1 } return 0 } - // Skip whitespace from pos; return first non-ws index or -1 - next_non_ws(s, pos) { - local i = pos - local n = s.length() - loop (i < n) { - local ch = s.substring(i, i+1) - if ch != " " && ch != "\n" && ch != "\r" && ch != "\t" { return i } - i = i + 1 - } - return -1 - } - // Read a quoted string starting at pos '"'; returns decoded string (no state) - read_quoted_from(s, pos) { - local i = pos - if s.substring(i, i+1) != "\"" { return "" } - i = i + 1 - local out = "" - local n = s.length() - loop (i < n) { - local ch = s.substring(i, i+1) - if ch == "\"" { break } - if ch == "\\" { - i = i + 1 - ch = s.substring(i, i+1) - } - out = out + ch - i = i + 1 - } - return out - } - // Read consecutive digits from pos - read_digits_from(s, pos) { - local out = "" - local i = pos - // guard against invalid position (null/negative) - if i == null { return out } - if i < 0 { return out } - loop (true) { - local ch = s.substring(i, i+1) - if ch == "" { break } - // inline digit check to avoid same-box method dispatch - if ch == "0" { out = out + ch i = i + 1 continue } - if ch == "1" { out = out + ch i = i + 1 continue } - if ch == "2" { out = out + ch i = i + 1 continue } - if ch == "3" { out = out + ch i = i + 1 continue } - if ch == "4" { out = out + ch i = i + 1 continue } - if ch == "5" { out = out + ch i = i + 1 continue } - if ch == "6" { out = out + ch i = i + 1 continue } - if ch == "7" { out = out + ch i = i + 1 continue } - if ch == "8" { out = out + ch i = i + 1 continue } - if ch == "9" { out = out + ch i = i + 1 continue } - break - } - return out - } -} - diff --git a/apps/selfhost/vm/boxes/mini_vm_core.nyash b/apps/selfhost/vm/boxes/mini_vm_core.nyash deleted file mode 100644 index 184cd2f4..00000000 --- a/apps/selfhost/vm/boxes/mini_vm_core.nyash +++ /dev/null @@ -1,774 +0,0 @@ -using selfhost.vm.boxes.json_cur as MiniJson -using selfhost.common.mini_vm_scan as MiniVmScan -using selfhost.common.mini_vm_binop as MiniVmBinOp -using selfhost.common.mini_vm_compare as MiniVmCompare -using selfhost.vm.boxes.mini_vm_prints as MiniVmPrints - -static box MiniVm { - _is_digit(ch) { - if ch == "0" { return 1 } - if ch == "1" { return 1 } - if ch == "2" { return 1 } - if ch == "3" { return 1 } - if ch == "4" { return 1 } - if ch == "5" { return 1 } - if ch == "6" { return 1 } - if ch == "7" { return 1 } - if ch == "8" { return 1 } - if ch == "9" { return 1 } - return 0 - } - _str_to_int(s) { return new MiniVmScan()._str_to_int(s) } - _int_to_str(n) { return new MiniVmScan()._int_to_str(n) } - read_digits(json, pos) { return new MiniJson().read_digits_from(json, pos) } - // Read a JSON string starting at position pos (at opening quote); returns the decoded string - read_json_string(json, pos) { return new MiniJson().read_quoted_from(json, pos) } - // helper: find needle from position pos - index_of_from(hay, needle, pos) { return new MiniVmScan().index_of_from(hay, needle, pos) } - // helper: next non-whitespace character index from pos - next_non_ws(json, pos) { return new MiniJson().next_non_ws(json, pos) } - // ——— Helpers (as box methods) ——— - - // Minimal: Print(BinaryOp) with operator "+"; supports string+string and int+int - // try_print_binop_at moved to MiniVmBinOp - - // Greedy fallback: detect BinaryOp int+int by pattern regardless of field order nuances - // try_print_binop_int_greedy moved to MiniVmBinOp - - // Fallback: within the current Print's expression BinaryOp object, scan for two numeric values and sum - // try_print_binop_sum_any moved to MiniVmBinOp - - // Deterministic: within the first Print.expression BinaryOp('+'), - // find exactly two numeric values from successive '"value":' fields and sum. - // Stops after collecting two ints; bounded strictly by the expression object. - // try_print_binop_sum_expr_values moved to MiniVmBinOp - - // Simpler deterministic fallback: after the first BinaryOp '+', - // scan forward for two successive 'value' fields and sum their integer digits. - // This avoids brace matching and remains bounded by two finds. - // try_print_binop_sum_after_bop moved to MiniVmBinOp - - // Direct typed BinaryOp(int+int) matcher using explicit left/right literal paths - try_print_binop_typed_direct(json) { - local k_left = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local k_right = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local lp = json.indexOf(k_left) - if lp < 0 { return -1 } - local ld = read_digits(json, lp + k_left.length()) - if ld == "" { return -1 } - local rp = index_of_from(json, k_right, lp + k_left.length()) - if rp < 0 { return -1 } - local rd = read_digits(json, rp + k_right.length()) - if rd == "" { return -1 } - print(_int_to_str(_str_to_int(ld) + _str_to_int(rd))) - return rp + k_right.length() - } - - // Tokenized typed extractor: search left/right blocks then type/value pairs - try_print_binop_typed_tokens(json) { - local k_bo = "\"kind\":\"BinaryOp\"" - local bpos = json.indexOf(k_bo) - if bpos < 0 { return -1 } - local lp = index_of_from(json, "\"left\":", bpos) - if lp < 0 { return -1 } - local kt = "\"type\":\"int\"" - local kv = "\"value\":" - local tp1 = index_of_from(json, kt, lp) - if tp1 < 0 { return -1 } - local vp1 = index_of_from(json, kv, tp1) - if vp1 < 0 { return -1 } - local ld = read_digits(json, vp1 + kv.length()) - if ld == "" { return -1 } - local rp = index_of_from(json, "\"right\":", lp) - if rp < 0 { return -1 } - local tp2 = index_of_from(json, kt, rp) - if tp2 < 0 { return -1 } - local vp2 = index_of_from(json, kv, tp2) - if vp2 < 0 { return -1 } - local rd = read_digits(json, vp2 + kv.length()) - if rd == "" { return -1 } - print(_int_to_str(_str_to_int(ld) + _str_to_int(rd))) - return rp - } - - // Fast value-pair extractor: find left/right then first value digits after each - try_print_binop_value_pairs(json) { - local k_bo = "\"kind\":\"BinaryOp\"" - local bpos = json.indexOf(k_bo) - if bpos < 0 { return -1 } - local kl = "\"left\":" - local kv = "\"value\":" - local lp = index_of_from(json, kl, bpos) - if lp < 0 { return -1 } - local v1 = index_of_from(json, kv, lp) - if v1 < 0 { return -1 } - local ld = read_digits(json, v1 + kv.length()) - if ld == "" { return -1 } - local rp = index_of_from(json, "\"right\":", lp) - if rp < 0 { return -1 } - local v2 = index_of_from(json, kv, rp) - if v2 < 0 { return -1 } - local rd = read_digits(json, v2 + kv.length()) - if rd == "" { return -1 } - print(_int_to_str(_str_to_int(ld) + _str_to_int(rd))) - return v2 + kv.length() - } - - // Minimal: Print(Compare) for integers. Prints 1/0 for true/false. - // try_print_compare_at moved to MiniVmCompare - // Extract first Print literal from JSON v0 Program and return its string representation - parse_first_print_literal(json) { - // Find a Print statement - local k_print = "\"kind\":\"Print\"" - local p = json.indexOf(k_print) - if p < 0 { return null } - // Find value type in the expression following Print - local k_type = "\"type\":\"" - local tpos = json.indexOf(k_type) - if tpos < 0 { return null } - tpos = tpos + k_type.length() - // Read type name until next quote - local t_end = index_of_from(json, "\"", tpos) - if t_end < 0 { return null } - local ty = json.substring(tpos, t_end) - // Find value field - local k_val = "\"value\":" - local vpos = index_of_from(json, k_val, t_end) - if vpos < 0 { return null } - vpos = vpos + k_val.length() - if ty == "int" || ty == "i64" || ty == "integer" { - // read digits via MiniJson - local digits = new MiniJson().read_digits_from(json, vpos) - return digits - } - if ty == "string" { - // read quoted via MiniJson - local i = index_of_from(json, "\"", vpos) - if i < 0 { return null } - return new MiniJson().read_quoted_from(json, i) - } - // Other types not supported yet - return null - } - // helper: find balanced bracket range [ ... ] starting at idx (points to '[') - find_balanced_array_end(json, idx) { return new MiniVmScan().find_balanced_array_end(json, idx) } - // helper: find balanced object range { ... } starting at idx (points to '{') - find_balanced_object_end(json, idx) { return new MiniVmScan().find_balanced_object_end(json, idx) } - // Print all Print-Literal values within [start,end] (inclusive slice indices) - print_prints_in_slice(json, start, end) { return new MiniVmPrints().print_prints_in_slice(json, start, end) } - // Process top-level If with literal condition; print branch prints. Returns printed count. - process_if_once(json) { return new MiniVmPrints().process_if_once(json) } - print_all_print_literals(json) { return new MiniVmPrints().print_all_print_literals(json) } - parse_first_int(json) { - local key = "\"value\":{\"type\":\"int\",\"value\":" - local idx = json.lastIndexOf(key) - if idx < 0 { return "0" } - local start = idx + key.length() - return read_digits(json, start) - } - // Fallback: find first BinaryOp and return sum of two numeric values as string; empty if not found - parse_first_binop_sum(json) { - local k_bo = "\"kind\":\"BinaryOp\"" - local bpos = json.indexOf(k_bo) - if bpos < 0 { return "" } - // typed pattern inside left/right.literal.value: {"type":"int","value":} - local k_typed = "\"type\":\"int\",\"value\":" - // first number - local p1 = index_of_from(json, k_typed, bpos) - if p1 < 0 { return "" } - local d1 = read_digits(json, p1 + k_typed.length()) - if d1 == "" { return "" } - // second number - local p2 = index_of_from(json, k_typed, p1 + k_typed.length()) - if p2 < 0 { return "" } - local d2 = read_digits(json, p2 + k_typed.length()) - if d2 == "" { return "" } - return _int_to_str(_str_to_int(d1) + _str_to_int(d2)) - } - // Linear pass: sum all numbers outside of quotes (fast, finite) - sum_numbers_no_quotes(json) { return new MiniVmScan().sum_numbers_no_quotes(json) } - // Naive: sum all digit runs anywhere (for simple BinaryOp JSON) - sum_all_digits_naive(json) { return new MiniVmScan().sum_all_digits_naive(json) } - // Sum first two integers outside quotes; returns string or empty if not found - sum_first_two_numbers(json) { return new MiniVmScan().sum_first_two_numbers(json) } - - // Sum two integers near a BinaryOp '+' token; bounded window to keep steps low - sum_two_numbers_near_plus(json) { - local k_plus = "\"operator\":\"+\"" - local op = json.indexOf(k_plus) - if op < 0 { return "" } - local n = json.length() - local start = op - 120 - if start < 0 { start = 0 } - local limit = op + 240 - if limit > n { limit = n } - local i = start - local found = 0 - local a = 0 - loop (i < limit) { - local ch = json.substring(i, i+1) - if ch == "\"" { - // skip to next quote within window - local j = index_of_from(json, "\"", i+1) - if j < 0 || j > limit { break } - i = j + 1 - continue - } - local d = read_digits(json, i) - if d { - if found == 0 { - a = _str_to_int(d) - found = 1 - } else { - local b = _str_to_int(d) - return _int_to_str(a + b) - } - i = i + d.length() - continue - } - i = i + 1 - } - return "" - } - // Fallback: sum all bare numbers (not inside quotes) in the JSON; return string or empty if none - sum_all_numbers(json) { - local cur = new MiniJson() - local i = 0 - local n = json.length() - local sum = 0 - loop (i < n) { - local ch = json.substring(i, i+1) - if ch == "\"" { - // skip quoted string - local s = cur.read_quoted_from(json, i) - i = i + s.length() + 2 - continue - } - // try digits - local d = cur.read_digits_from(json, i) - if d != "" { sum = sum + _str_to_int(d) i = i + d.length() continue } - i = i + 1 - } - if sum == 0 { return "" } - return _int_to_str(sum) - } - // (reserved) helper for future robust binop scan - run(json) { - // entry: attempt minimal quick shapes first, then broader routes - // Quick path: Program-level Print of a single Literal string/int - if json.indexOf("\"kind\":\"Program\"") >= 0 && json.indexOf("\"kind\":\"Print\"") >= 0 { - // Literal string - if json.indexOf("\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"string\"") >= 0 { - local ks = "\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"string\",\"value\":\"" - local ps = json.indexOf(ks) - if ps >= 0 { - local si = ps + ks.length() - local sj = json.indexOf("\"", si) - if sj >= 0 { print(json.substring(si, sj)) return 0 } - } - } - // Literal int - if json.indexOf("\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\"") >= 0 { - local ki = "\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local pi = json.indexOf(ki) - if pi >= 0 { - local ii = pi + ki.length() - // digits until closing brace - local ie = json.indexOf("}", ii) - if ie < 0 { ie = ii } - local d = json.substring(ii, ie) - if d { print(d) return 0 } - } - } - } - // Single-purpose fast path for smoke: if BinaryOp '+' exists, try expression-bounded extractor first. - if json.indexOf("\"BinaryOp\"") >= 0 && json.indexOf("\"operator\":\"+\"") >= 0 { - // Bind to first Print and extract value×2 within expression bounds - local k_print = "\"kind\":\"Print\"" - local p = index_of_from(json, k_print, 0) - if p >= 0 { - local np0 = new MiniVmBinOp().try_print_binop_sum_expr_values(json, json.length(), p) - if np0 > 0 { return 0 } - } - // Typed direct inside BinaryOp object (fast and finite) - local k_bo = "\"kind\":\"BinaryOp\"" - local bpos = json.indexOf(k_bo) - if bpos >= 0 { - local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local li = index_of_from(json, k_lint, bpos) - if li >= 0 { - local ld = read_digits(json, li + k_lint.length()) - if ld != "" { - local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local ri = index_of_from(json, k_rint, li + k_lint.length()) - if ri >= 0 { - local rd = read_digits(json, ri + k_rint.length()) - if rd != "" { print(_int_to_str(_str_to_int(ld) + _str_to_int(rd))) return 0 } - } - } - } - } - // As a final bounded fallback under BinaryOp '+', sum first two numbers outside quotes - { - local s2 = sum_first_two_numbers(json) - if s2 { print(s2) return 0 } - } - // (skip near-operator windowed scan to avoid high step counts under PyVM) - } - // Prefer If(literal) branch handling first - local ifc = process_if_once(json) - if ifc > 0 { return 0 } - // Quick conservative path: if BinaryOp exists, sum bare numbers outside quotes - // (limited to simple BinaryOp(int,int) JSON) - if json.indexOf("\"BinaryOp\"") >= 0 { - // Prefer expression-bounded scan first - local k_print = "\"kind\":\"Print\"" - local p = index_of_from(json, k_print, 0) - if p >= 0 { - // Deterministic: sum the first two numbers from successive 'value' fields - local np0 = new MiniVmBinOp().try_print_binop_sum_expr_values(json, json.length(), p) - if np0 > 0 { return 0 } - } - // Brace-free deterministic fallback tied to the first BinaryOp - { - local np1 = new MiniVmBinOp().try_print_binop_sum_after_bop(json) - if np1 > 0 { return 0 } - } - // avoid global number-sum fallback to keep steps bounded - } - // 0) direct typed BinaryOp '+' fast-path (explicit left/right literal ints) - local k_bo = "\"kind\":\"BinaryOp\"" - local k_plus = "\"operator\":\"+\"" - if json.indexOf(k_bo) >= 0 && json.indexOf(k_plus) >= 0 { - local np = try_print_binop_typed_direct(json) - if np > 0 { return 0 } - np = try_print_binop_typed_tokens(json) - if np > 0 { return 0 } - np = try_print_binop_value_pairs(json) - if np > 0 { return 0 } - // (skip bounded-window fallback around '+') - } - // 0) quick path: BinaryOp(int+int) typed fast-path - local k_bo = "\"kind\":\"BinaryOp\"" - local bpos = json.indexOf(k_bo) - if bpos >= 0 { - // typed left/right ints inside BinaryOp - local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local li = index_of_from(json, k_lint, bpos) - if li >= 0 { - local ld = read_digits(json, li + k_lint.length()) - if ld != "" { - local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local ri = index_of_from(json, k_rint, li + k_lint.length()) - if ri >= 0 { - local rd = read_digits(json, ri + k_rint.length()) - if rd != "" { - print(_int_to_str(_str_to_int(ld) + _str_to_int(rd))) - return 0 - } - } - } - } - // fallback: sum two numeric values within the first Print.expression BinaryOp object - local k_print = "\"kind\":\"Print\"" - local p = index_of_from(json, k_print, 0) - if p >= 0 { - local k_expr = "\"expression\":{" - local epos = index_of_from(json, k_expr, p) - if epos > 0 { - local obj_start = index_of_from(json, "{", epos) - local obj_end = find_balanced_object_end(json, obj_start) - if obj_start > 0 && obj_end > 0 { - local k_bo2 = "\"kind\":\"BinaryOp\"" - local b2 = index_of_from(json, k_bo2, obj_start) - if b2 > 0 && b2 < obj_end { - local k_v = "\"value\":" - local p1 = index_of_from(json, k_v, obj_start) - local d1 = "" - loop (p1 > 0 && p1 < obj_end) { - d1 = new MiniJson().read_digits_from(json, p1 + k_v.length()) - if d1 != "" { break } - p1 = index_of_from(json, k_v, p1 + k_v.length()) - } - if d1 != "" { - local p2 = index_of_from(json, k_v, p1 + k_v.length()) - local d2 = "" - loop (p2 > 0 && p2 < obj_end) { - d2 = new MiniJson().read_digits_from(json, p2 + k_v.length()) - if d2 != "" { break } - p2 = index_of_from(json, k_v, p2 + k_v.length()) - } - if d2 != "" { - local ai = _str_to_int(d1) - local bi = _str_to_int(d2) - print(_int_to_str(ai + bi)) - return 0 - } - } - } - } - } - } - // fallback: parse-first within BinaryOp scope by scanning two numeric values - local ssum = new MiniVmBinOp().parse_first_binop_sum(json) - if ssum { print(ssum) return 0 } - } - // Attempt expression-local BinaryOp sum via existing helper on first Print - { - local k_print = "\"kind\":\"Print\"" - local p = index_of_from(json, k_print, 0) - if p >= 0 { - local np = new MiniVmBinOp().try_print_binop_sum_any(json, json.length(), p) - if np > 0 { return 0 } - } - } - // 0-c) quick path: Compare(lhs int, rhs int) - local k_cp = "\"kind\":\"Compare\"" - local cpos = json.indexOf(k_cp) - if cpos >= 0 { - // operation - local k_op = "\"operation\":\"" - local opos = index_of_from(json, k_op, cpos) - if opos > 0 { - local oi = opos + k_op.length() - local oj = index_of_from(json, "\"", oi) - if oj > 0 { - local op = json.substring(oi, oj) - // lhs value - local k_lhs = "\"lhs\":{\"kind\":\"Literal\"" - local hl = index_of_from(json, k_lhs, oj) - if hl > 0 { - local k_v = "\"value\":" - local hv = index_of_from(json, k_v, hl) - if hv > 0 { - local a = read_digits(json, hv + k_v.length()) - // rhs value - local k_rhs = "\"rhs\":{\"kind\":\"Literal\"" - local hr = index_of_from(json, k_rhs, hl) - if hr > 0 { - local rv = index_of_from(json, k_v, hr) - if rv > 0 { - local b = read_digits(json, rv + k_v.length()) - if a && b { - local ai = _str_to_int(a) - local bi = _str_to_int(b) - local res = 0 - if op == "<" { if ai < bi { res = 1 } } - if op == "==" { if ai == bi { res = 1 } } - if op == "<=" { if ai <= bi { res = 1 } } - if op == ">" { if ai > bi { res = 1 } } - if op == ">=" { if ai >= bi { res = 1 } } - if op == "!=" { if ai != bi { res = 1 } } - print(res) - return 0 - } - } - } - } - } - } - } - } - // Scan global prints (flat programs) - local pc = print_all_print_literals(json) - // 2) as a robustness fallback, handle first BinaryOp sum within first Print.expression - if pc == 0 { - local k_print = "\"kind\":\"Print\"" - local p = index_of_from(json, k_print, 0) - if p >= 0 { - local k_expr = "\"expression\":{" - local epos = index_of_from(json, k_expr, p) - if epos > 0 { - local obj_start = index_of_from(json, "{", epos) - local obj_end = find_balanced_object_end(json, obj_start) - if obj_start > 0 && obj_end > 0 { - local k_bo = "\"kind\":\"BinaryOp\"" - local bpos = index_of_from(json, k_bo, obj_start) - if bpos > 0 && bpos < obj_end { - // sum two numeric values inside this expression object - local cur = new MiniJson() - local k_v = "\"value\":" - local p1 = index_of_from(json, k_v, obj_start) - local d1 = "" - loop (p1 > 0 && p1 < obj_end) { - d1 = cur.read_digits_from(json, p1 + k_v.length()) - if d1 != "" { break } - p1 = index_of_from(json, k_v, p1 + k_v.length()) - } - if d1 != "" { - local p2 = index_of_from(json, k_v, p1 + k_v.length()) - local d2 = "" - loop (p2 > 0 && p2 < obj_end) { - d2 = cur.read_digits_from(json, p2 + k_v.length()) - if d2 != "" { break } - p2 = index_of_from(json, k_v, p2 + k_v.length()) - } - if d2 != "" { - local ai = _str_to_int(d1) - local bi = _str_to_int(d2) - print(_int_to_str(ai + bi)) - pc = 1 - } - } - } - } - } - } - } - if pc == 0 { - // last resort: typed pattern-wide sum, then safe number sum outside quotes, else single int literal - local s = new MiniVmBinOp().parse_first_binop_sum(json) - if s { print(s) } else { - local ts = sum_numbers_no_quotes(json) - if ts { print(ts) } else { - local n = parse_first_int(json) - print(n) - } - } - } - return 0 - } - - // Pure helper: collect minimal print outputs (literals only) into an array - collect_prints(json) { - // Ported from self-contained smoke (Hardened minimal scanner) - local out = new ArrayBox() - local pos = 0 - local guard = 0 - // DEV trace: flip to 1 for one-run diagnosis; keep 0 for normal - local trace = 0 - if trace == 1 { print("[collect][start] method entry") } - local k_print = "\"kind\":\"Print\"" - loop (true) { - guard = guard + 1 - if guard > 200 { - if trace == 1 { print("[collect][guard_break] guard="+guard) } - if trace == 1 { print("[collect][loop_exit] guard="+guard+" out.size="+out.size()) } - if trace == 1 { print("[collect][return] out.size="+out.size()) } - return out - } - local p = index_of_from(json, k_print, pos) - if trace == 1 { print("[collect][loop] pos="+pos+" p="+p+" guard="+guard) } - if p < 0 { - if trace == 1 { print("[collect][p_break] p="+p) } - if trace == 1 { print("[collect][loop_exit] guard="+guard+" out.size="+out.size()) } - if trace == 1 { print("[collect][return] out.size="+out.size()) } - return out - } - // bound current Print slice to [this, next) - local obj_start = p - local next_p = index_of_from(json, k_print, p + k_print.length()) - local obj_end = json.length() - if next_p > 0 { obj_end = next_p } - if trace == 1 { print("[collect][p] "+p) print("[collect][next_p] "+next_p) print("[collect][slice_end] "+obj_end) } - if trace == 1 { - local k_expr = "\"expression\":{" - local epos_dbg = index_of_from(json, k_expr, obj_start) - print("[scan][expr] "+epos_dbg) - local fc_dbg = index_of_from(json, "\"kind\":\"FunctionCall\"", obj_start) - print("[scan][fc] "+fc_dbg) - local bo_dbg = index_of_from(json, "\"kind\":\"BinaryOp\"", obj_start) - print("[scan][bo] "+bo_dbg) - local cp_dbg = index_of_from(json, "\"kind\":\"Compare\"", obj_start) - print("[scan][cp] "+cp_dbg) - local ts_dbg = index_of_from(json, "\"type\":\"string\"", obj_start) - print("[scan][ts] "+ts_dbg) - local ti_dbg = index_of_from(json, "\"type\":\"int\"", obj_start) - print("[scan][ti] "+ti_dbg) - // positions for tight patterns used by branches - local ks_pat = "\"type\":\"string\",\"value\":\"" - print("[scan][ks] "+index_of_from(json, ks_pat, obj_start)) - local ki_pat = "\"type\":\"int\",\"value\":" - print("[scan][ki] "+index_of_from(json, ki_pat, obj_start)) - } - - // 1) FunctionCall echo/itoa (single literal or empty args) - { - // Limit search within Print.expression object for stability - local k_expr = "\"expression\":{" - local epos = index_of_from(json, k_expr, obj_start) - if epos > 0 { if epos < obj_end { - local expr_start = index_of_from(json, "{", epos) - if expr_start > 0 { if expr_start < obj_end { - local expr_end = new MiniVmScan().find_balanced_object_end(json, expr_start) - if expr_end > 0 { if expr_end <= obj_end { - if trace == 1 { print("[collect][expr] "+expr_start+","+expr_end) } - local k_fc = "\"kind\":\"FunctionCall\"" - local fcp = index_of_from(json, k_fc, expr_start) - if trace == 1 { print("[collect][fc_in_expr] "+fcp+" (bounds "+expr_start+","+expr_end+")") } - if fcp > 0 { if fcp < expr_end { - if trace == 1 { print("[collect][fc_found] entering function call handler") } - local kn = "\"name\":\"" - local np = index_of_from(json, kn, fcp) - if trace == 1 { print("[collect][name_search] "+np+" (obj_end "+obj_end+")") } - if np > 0 { if np < obj_end { - local ni = np + kn.length() - local nj = index_of_from(json, "\"", ni) - if trace == 1 { print("[collect][name_bounds] "+ni+","+nj+" (expr_end "+expr_end+")") } - if nj > 0 { if nj <= expr_end { - local fname = json.substring(ni, nj) - if trace == 1 { print("[collect][fname] '"+fname+"'") } - local ka = "\"arguments\":[" - local ap = index_of_from(json, ka, nj) - if ap <= 0 { - local ka0 = "\"arguments\":" - local ap0 = index_of_from(json, ka0, nj) - if ap0 >= 0 { if ap0 < expr_end { ap = ap0 } } - } - if ap >= 0 { if ap < expr_end { - // detect empty args [] quickly: no type token inside balanced array - local arr_start = index_of_from(json, "[", ap) - if arr_start >= 0 { if arr_start < expr_end { - local arr_end = new MiniVmScan().find_balanced_array_end(json, arr_start) - if arr_end >= 0 { if arr_end <= expr_end { - local kt = "\"type\":\"" - local atpos = index_of_from(json, kt, arr_start) - if trace == 1 { print("[collect][empty_check] atpos="+atpos+" arr_bounds=["+arr_start+","+arr_end+"]") } - if atpos < 0 || atpos >= arr_end { - if trace == 1 { print("[collect][empty_args] fname='"+fname+"'") } - if fname == "echo" { out.push("") pos = obj_end continue } - if fname == "itoa" { out.push("0") pos = obj_end continue } - } - }}}} - // string arg - local ks = "\"type\":\"string\",\"value\":\"" - local ps = index_of_from(json, ks, ap) - if ps > 0 { if ps < expr_end { - local si = ps + ks.length() - local sj = index_of_from(json, "\"", si) - if sj > 0 { if sj <= expr_end { - local sval = json.substring(si, sj) - if fname == "echo" { out.push(sval) pos = obj_end + 1 continue } - }} - }} - // int arg - local ki = "\"type\":\"int\",\"value\":" - local pi = index_of_from(json, ki, ap) - if pi > 0 { if pi < expr_end { - local ival = read_digits(json, pi + ki.length()) - if ival != "" { if fname == "itoa" { out.push(ival) pos = obj_end + 1 continue } else { if fname == "echo" { out.push(ival) pos = obj_end + 1 continue } } } - }} - }} - }} - }} - }}} - }} - }} - } - - // 2) BinaryOp(int '+' int) - { - local k_expr = "\"expression\":{" - local epos = index_of_from(json, k_expr, obj_start) - if epos > 0 { if epos < obj_end { - local k_bo = "\"kind\":\"BinaryOp\"" - local bpos = index_of_from(json, k_bo, epos) - if bpos > 0 { if bpos < obj_end { - if index_of_from(json, "\"operator\":\"+\"", bpos) > 0 { - local k_l = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local k_r = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local lp = index_of_from(json, k_l, bpos) - if lp > 0 { if lp < obj_end { - local ld = read_digits(json, lp + k_l.length()) - if ld != "" { - local rp = index_of_from(json, k_r, lp + k_l.length()) - if rp > 0 { if rp < obj_end { - local rd = read_digits(json, rp + k_r.length()) - if rd != "" { if trace == 1 { print("[hit][bo-typed] "+ld+"+"+rd) } out.push(_int_to_str(_str_to_int(ld) + _str_to_int(rd))) pos = p + k_print.length() continue } - }} - } - }} - // fallback: two successive 'value' digits within expression bounds - local k_v = "\"value\":" - local v1 = index_of_from(json, k_v, epos) - if v1 > 0 { if v1 < obj_end { - local d1 = new MiniJson().read_digits_from(json, v1 + k_v.length()) - if d1 != "" { - local v2 = index_of_from(json, k_v, v1 + k_v.length()) - if v2 > 0 { if v2 < obj_end { - local d2 = new MiniJson().read_digits_from(json, v2 + k_v.length()) - if d2 != "" { if trace == 1 { print("[hit][bo-fallback] "+d1+"+"+d2) } out.push(_int_to_str(_str_to_int(d1) + _str_to_int(d2))) pos = p + k_print.length() continue } - }} - } - }} - } - }} - }} - } - - // 3) Compare(lhs/rhs ints) - { - local k_cp = "\"kind\":\"Compare\"" - local cpos = index_of_from(json, k_cp, obj_start) - if cpos > 0 { if cpos < obj_end { - local k_op = "\"operation\":\"" - local opos = index_of_from(json, k_op, cpos) - if opos > 0 { if opos < obj_end { - local oi = opos + k_op.length() - local oj = index_of_from(json, "\"", oi) - if oj > 0 { if oj <= obj_end { - local op = json.substring(oi, oj) - local k_v = "\"value\":" - local lhs_v = index_of_from(json, k_v, oj) - if lhs_v > 0 { if lhs_v < obj_end { - local la = read_digits(json, lhs_v + k_v.length()) - if la != "" { - local rhs_v = index_of_from(json, k_v, lhs_v + k_v.length()) - if rhs_v > 0 { if rhs_v < obj_end { - local rb = read_digits(json, rhs_v + k_v.length()) - if rb != "" { - local ai = _str_to_int(la) - local bi = _str_to_int(rb) - local res = 0 - if op == "<" { if ai < bi { res = 1 } } - if op == "==" { if ai == bi { res = 1 } } - if op == "<=" { if ai <= bi { res = 1 } } - if op == ">" { if ai > bi { res = 1 } } - if op == ">=" { if ai >= bi { res = 1 } } - if op == "!=" { if ai != bi { res = 1 } } - out.push(_int_to_str(res)) - pos = p + k_print.length() - continue - } - }} - } - }} - }} - }} - }} - } - - // (FunctionCall branch moved earlier) - - // 4) Literal string - { - local ks = "\"type\":\"string\",\"value\":\"" - local ps = index_of_from(json, ks, obj_start) - if ps > 0 { if ps < obj_end { - local si = ps + ks.length() - local sj = index_of_from(json, "\"", si) - if sj > 0 { if sj <= obj_end { - if trace == 1 { print("[hit][str]") } - out.push(json.substring(si, sj)) pos = p + k_print.length() continue - }} - }} - } - // 5) Literal int - { - local ki = "\"type\":\"int\",\"value\":" - local pi = index_of_from(json, ki, obj_start) - if pi > 0 { if pi < obj_end { - local digits = read_digits(json, pi + ki.length()) - if digits != "" { if trace == 1 { print("[hit][i-lit] "+digits) } out.push(digits) pos = p + k_print.length() continue } - }} - } - // Unknown: skip this Print object entirely to avoid stalls and mis-detection - // Use coarse slice end (next Print position) when available; fallback to k_print-length step - pos = obj_end + 1 - if pos <= p { pos = p + k_print.length() } - } - if trace == 1 { print("[collect][loop_exit] guard="+guard+" out.size="+out.size()) } - if trace == 1 { print("[collect][return] out.size="+out.size()) } - return out - } -} diff --git a/apps/selfhost/vm/boxes/mini_vm_prints.nyash b/apps/selfhost/vm/boxes/mini_vm_prints.nyash deleted file mode 100644 index cc35fd82..00000000 --- a/apps/selfhost/vm/boxes/mini_vm_prints.nyash +++ /dev/null @@ -1,531 +0,0 @@ -using selfhost.common.mini_vm_scan as MiniVmScan -using selfhost.common.mini_vm_binop as MiniVmBinOp -using selfhost.common.mini_vm_compare as MiniVmCompare -// Use the JSON adapter facade for cursor ops (next_non_ws, digits) -using selfhost.vm.boxes.json_cur as MiniJsonLoader - -static box MiniVmPrints { - // dev trace flag (0=OFF) - _trace_enabled() { return 0 } - // fallback toggle for legacy heuristics (0=OFF, 1=ON) - _fallback_enabled() { return 0 } - // literal string within Print - try_print_string_value_at(json, end, print_pos) { - local scan = new MiniVmScan() - local k_val = "\"value\":\"" - local s = scan.index_of_from(json, k_val, print_pos) - if s < 0 || s >= end { return -1 } - local i = s + k_val.length() - local j = scan.index_of_from(json, "\"", i) - if j <= 0 || j > end { return -1 } - print(json.substring(i, j)) - return j + 1 - } - - // literal int within Print (typed) - try_print_int_value_at(json, end, print_pos) { - local scan = new MiniVmScan() - local k_expr = "\"expression\":{" - local epos = scan.index_of_from(json, k_expr, print_pos) - if epos <= 0 || epos >= end { return -1 } - local obj_start = scan.index_of_from(json, "{", epos) - if obj_start <= 0 || obj_start >= end { return -1 } - local obj_end = scan.find_balanced_object_end(json, obj_start) - if obj_end <= 0 || obj_end > end { return -1 } - // robust: look for explicit int type within expression object - local k_tint = "\"type\":\"int\"" - local tpos = scan.index_of_from(json, k_tint, obj_start) - if tpos <= 0 || tpos >= obj_end { return -1 } - local k_val2 = "\"value\":" - local v2 = scan.index_of_from(json, k_val2, tpos) - if v2 <= 0 || v2 >= obj_end { return -1 } - local digits = scan.read_digits(json, v2 + k_val2.length()) - if digits == "" { return -1 } - print(digits) - return obj_end + 1 - } - - // minimal FunctionCall printer for echo/itoa - try_print_functioncall_at(json, end, print_pos) { - local scan = new MiniVmScan() - local k_fc = "\"kind\":\"FunctionCall\"" - local fcp = scan.index_of_from(json, k_fc, print_pos) - if fcp <= 0 || fcp >= end { return -1 } - local k_name = "\"name\":\"" - local npos = scan.index_of_from(json, k_name, fcp) - if npos <= 0 || npos >= end { return -1 } - local ni = npos + k_name.length() - local nj = scan.index_of_from(json, "\"", ni) - if nj <= 0 || nj > end { return -1 } - local fname = json.substring(ni, nj) - local k_args = "\"arguments\":[" - local apos = scan.index_of_from(json, k_args, nj) - if apos <= 0 || apos >= end { return -1 } - local arr_start = scan.index_of_from(json, "[", apos) - local arr_end = scan.find_balanced_array_end(json, arr_start) - if arr_start <= 0 || arr_end <= 0 || arr_end > end { return -1 } - // handle empty args [] - local nn = new MiniJsonLoader().next_non_ws(json, arr_start+1) - if nn > 0 && nn <= arr_end { - if json.substring(nn, nn+1) == "]" { - if fname == "echo" { print("") return arr_end + 1 } - if fname == "itoa" { print("0") return arr_end + 1 } - return -1 - } - } - // first arg type - local k_t = "\"type\":\"" - local atpos = scan.index_of_from(json, k_t, arr_start) - if atpos <= 0 || atpos >= arr_end { - if fname == "echo" { print("") return arr_end + 1 } - if fname == "itoa" { print("0") return arr_end + 1 } - return -1 - } - atpos = atpos + k_t.length() - local at_end = scan.index_of_from(json, "\"", atpos) - if at_end <= 0 || at_end > arr_end { return -1 } - local aty = json.substring(atpos, at_end) - if aty == "string" { - local k_sval = "\"value\":\"" - local svalp = scan.index_of_from(json, k_sval, at_end) - if svalp <= 0 || svalp >= arr_end { return -1 } - local si = svalp + k_sval.length() - local sj = scan.index_of_from(json, "\"", si) - if sj <= 0 || sj > arr_end { return -1 } - local sval = json.substring(si, sj) - if fname == "echo" { print(sval) return sj + 1 } - return -1 - } - if aty == "int" || aty == "i64" || aty == "integer" { - local k_ival = "\"value\":" - local ivalp = scan.index_of_from(json, k_ival, at_end) - if ivalp <= 0 || ivalp >= arr_end { return -1 } - local digits = scan.read_digits(json, ivalp + k_ival.length()) - if fname == "itoa" || fname == "echo" { print(digits) return ivalp + k_ival.length() } - return -1 - } - return -1 - } - // Print all Print-Literal values within [start,end] - print_prints_in_slice(json, start, end) { - // Preferred route: JSON Box (plugin) – robust and structure-aware - // If plugin is available, parse and traverse Program.statements and print. - // Fall back to text scanner when plugin is unavailable or parse fails. - { - // Attempt plugin route in a guarded block - @printed = 0 - @ok = 0 - @dbg = _trace_enabled() - // new JsonDocBox()/JsonNodeBox are provided by the JSON plugin - @doc = new JsonDocBox() - doc.parse(json) - if dbg == 1 { - @perr = doc.error() - if perr == "" { print("[json] parse ok") } else { print("[json] parse err=" + perr) } - } - @root = doc.root() - if dbg == 1 { - @rkind = root.kind() - print("[json] root.kind=" + rkind) - } - if root { - @stmts = root.get("statements") - if dbg == 1 { - @skind = stmts.kind() - @ssize = stmts.size() - print("[json] stmts.kind=" + skind + " size=" + new MiniVmScan()._int_to_str(ssize)) - } - if stmts { - @n = stmts.size() - @i = 0 - loop (i < n) { - if dbg == 1 { - print("[json] loop i=" + new MiniVmScan()._int_to_str(i) + "/" + new MiniVmScan()._int_to_str(n)) - if i > 1000 { print("[json] debug guard: break loop at i>1000") break } - } - @node = stmts.at(i) - if !node { i = i + 1 continue } - @expr = node.get("expression") - if !expr { i = i + 1 continue } - @k = expr.get("kind").str() - if dbg == 1 { print("[json] expr.kind=" + k) } - if k == "Literal" { - @val = expr.get("value") - if val { - @ty = val.get("type").str() - if ty == "string" { print(val.get("value").str()) } else { print(val.get("value").int()) } - } - printed = printed + 1 - i = i + 1 - continue - } - if k == "FunctionCall" { - @name = expr.get("name").str() - if dbg == 1 { print("[json] func name=" + name) } - @args = expr.get("arguments") - if !args { i = i + 1 continue } - @asz = args.size() - if asz <= 0 { - if name == "echo" { print("") } - if name == "itoa" { print("0") } - printed = printed + 1 - i = i + 1 - continue - } - @arg0v = args.at(0).get("value") - if name == "echo" { - if arg0v { - @t = arg0v.get("type").str() - if t == "string" { print(arg0v.get("value").str()) } else { print(arg0v.get("value").int()) } - } - printed = printed + 1 - if dbg == 1 { print("[json] before inc i=" + new MiniVmScan()._int_to_str(i)) } - i = i + 1 - if dbg == 1 { print("[json] after inc i=" + new MiniVmScan()._int_to_str(i)) } - continue - } - if name == "itoa" { - if arg0v { print(arg0v.get("value").int()) } - printed = printed + 1 - if dbg == 1 { print("[json] before inc i=" + new MiniVmScan()._int_to_str(i)) } - i = i + 1 - if dbg == 1 { print("[json] after inc i=" + new MiniVmScan()._int_to_str(i)) } - continue - } - printed = printed + 1 - if dbg == 1 { print("[json] before inc i=" + new MiniVmScan()._int_to_str(i)) } - i = i + 1 - if dbg == 1 { print("[json] after inc i=" + new MiniVmScan()._int_to_str(i)) } - continue - } - if k == "Compare" { - @op = expr.get("operation").str() - @lhs = expr.get("lhs").get("value").get("value").int() - @rhs = expr.get("rhs").get("value").get("value").int() - if op == "<" { if lhs < rhs { print(1) } else { print(0) } } - if op == "==" { if lhs == rhs { print(1) } else { print(0) } } - if op == "<=" { if lhs <= rhs { print(1) } else { print(0) } } - if op == ">" { if lhs > rhs { print(1) } else { print(0) } } - if op == ">=" { if lhs >= rhs { print(1) } else { print(0) } } - if op == "!=" { if lhs != rhs { print(1) } else { print(0) } } - printed = printed + 1 - i = i + 1 - continue - } - if k == "BinaryOp" { - @op = expr.get("operator").str() - if op == "+" { - @left = expr.get("left").get("value").get("value").int() - @right = expr.get("right").get("value").get("value").int() - print(left + right) - printed = printed + 1 - i = i + 1 - continue - } - } - // Unknown expression kind: treat as a no-op; do not count - i = i + 1 - } - ok = 1 - } - } - // Prefer plugin result whenever JSON route ran (ok==1). Even if printed==0, - // return early to avoid falling back to the heuristic scanner which can loop - // on malformed inputs or seam-edge cases. - if dbg == 1 { print("[json] plugin_ok=" + new MiniVmScan()._int_to_str(ok) + " printed=" + new MiniVmScan()._int_to_str(printed)) } - if ok == 1 { return printed } - } - - // Fallback: text scanner(開発用) - if _trace_enabled() == 1 { print("[json] fallback engaged") } - local scan = new MiniVmScan() - local bin = new MiniVmBinOp() - local cmp = new MiniVmCompare() - local pos = start - local printed = 0 - local guard = 0 - loop (true) { - guard = guard + 1 - if guard > 200 { break } - local k_print = "\"kind\":\"Print\"" - local p = scan.index_of_from(json, k_print, pos) - if p < 0 || p > end { break } - // bound current Print object (coarse): use next Print marker as slice end to avoid deep brace scan - local p_obj_start = scan.index_of_from(json, "{", p) - // coarse slice end by next Print marker - local next_p = scan.index_of_from(json, k_print, p + k_print.length()) - local p_slice_end = end - if next_p > 0 { p_slice_end = next_p } - // avoid heavy find_balanced_object_end; use coarse p_slice_end-1 as object end - local p_obj_end = p_slice_end - 1 - if p_obj_start <= 0 { p_obj_end = p + k_print.length() } - // Fast path: handle within [p, p_slice_end) without deep brace scans - { - local did = 0 - // FunctionCall echo/itoa - local k_fc = "\"kind\":\"FunctionCall\"" - local fcp = scan.index_of_from(json, k_fc, p) - if fcp > 0 { if fcp < p_slice_end { - local k_name = "\"name\":\"" - local npos = scan.index_of_from(json, k_name, fcp) - if npos > 0 { if npos < p_slice_end { - local ni = npos + k_name.length() - local nj = scan.index_of_from(json, "\"", ni) - if nj > 0 { if nj <= p_slice_end { - local fname = json.substring(ni, nj) - local k_args = "\"arguments\":[" - local apos = scan.index_of_from(json, k_args, nj) - if apos > 0 { if apos < p_slice_end { - // quick value-based parse first (avoid type walk) - { - local k_sval = "\"value\":\"" - local vs = scan.index_of_from(json, k_sval, apos) - if vs > 0 { if vs < p_slice_end { - local si = vs + k_sval.length() - local sj = scan.index_of_from(json, "\"", si) - if sj > 0 { if sj <= p_slice_end { - local sval = json.substring(si, sj) - if fname == "echo" { print(sval) printed = printed + 1 did = 1 pos = p_slice_end continue } - }} - }} - local k_ival = "\"value\":" - local vi = scan.index_of_from(json, k_ival, apos) - if vi > 0 { if vi < p_slice_end { - local digits = scan.read_digits(json, vi + k_ival.length()) - if digits != "" { if fname == "itoa" || fname == "echo" { print(digits) printed = printed + 1 did = 1 pos = p_slice_end continue } } - }} - } - // empty args - local nwn = new MiniJsonLoader().next_non_ws(json, apos + k_args.length()) - if nwn == apos + k_args.length() { - if fname == "echo" { print("") printed = printed + 1 did = 1 pos = p_slice_end continue } - if fname == "itoa" { print("0") printed = printed + 1 did = 1 pos = p_slice_end continue } - } - local k_t = "\"type\":\"" - local atpos = scan.index_of_from(json, k_t, apos) - if atpos > 0 { if atpos < p_slice_end { - local ati = atpos + k_t.length() - local atj = scan.index_of_from(json, "\"", ati) - if atj > 0 { if atj <= p_slice_end { - local aty = json.substring(ati, atj) - if aty == "string" { - local k_sval = "\"value\":\"" - local svalp = scan.index_of_from(json, k_sval, atj) - if svalp > 0 { if svalp < p_slice_end { - local si = svalp + k_sval.length() - local sj = scan.index_of_from(json, "\"", si) - if sj > 0 { if sj <= p_slice_end { - local sval = json.substring(si, sj) - if fname == "echo" { print(sval) printed = printed + 1 did = 1 pos = p_slice_end continue } - }} - }} - } - if aty == "int" || aty == "i64" || aty == "integer" { - local k_ival = "\"value\":" - local ivalp = scan.index_of_from(json, k_ival, atj) - if ivalp > 0 { if ivalp < p_slice_end { - local digits = scan.read_digits(json, ivalp + k_ival.length()) - if fname == "itoa" || fname == "echo" { print(digits) printed = printed + 1 did = 1 pos = p_slice_end continue } - }} - } - }} - } - } - }} - }} - }} - }} - // Compare within slice - local k_cp = "\"kind\":\"Compare\"" - local cpos = scan.index_of_from(json, k_cp, p) - if cpos > 0 { if cpos < p_slice_end { - local k_op = "\"operation\":\"" - local opos = scan.index_of_from(json, k_op, cpos) - if opos > 0 { if opos < p_slice_end { - local oi = opos + k_op.length() - local oj = scan.index_of_from(json, "\"", oi) - if oj > 0 { if oj <= p_slice_end { - local op = json.substring(oi, oj) - local k_lhs = "\"lhs\":{\"kind\":\"Literal\"" - local hl = scan.index_of_from(json, k_lhs, oj) - if hl > 0 { if hl < p_slice_end { - local k_v = "\"value\":" - local hv = scan.index_of_from(json, k_v, hl) - if hv > 0 { if hv < p_slice_end { - local a = scan.read_digits(json, hv + k_v.length()) - local k_rhs = "\"rhs\":{\"kind\":\"Literal\"" - local hr = scan.index_of_from(json, k_rhs, hl) - if hr > 0 { if hr < p_slice_end { - local rv = scan.index_of_from(json, k_v, hr) - if rv > 0 { if rv < p_slice_end { - local b = scan.read_digits(json, rv + k_v.length()) - if a && b { - local ai = scan._str_to_int(a) - local bi = scan._str_to_int(b) - local res = 0 - if op == "<" { if ai < bi { res = 1 } } - if op == "==" { if ai == bi { res = 1 } } - if op == "<=" { if ai <= bi { res = 1 } } - if op == ">" { if ai > bi { res = 1 } } - if op == ">=" { if ai >= bi { res = 1 } } - if op == "!=" { if ai != bi { res = 1 } } - print(res) - printed = printed + 1 - did = 1 - pos = p_slice_end - continue - } - }} - }} - }} - }} - }} - }} - }} - // BinaryOp '+' (typed ints) within slice - if scan.index_of_from(json, "\"kind\":\"BinaryOp\"", p) > 0 { if scan.index_of_from(json, "\"operator\":\"+\"", p) > 0 { - local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local lp = scan.index_of_from(json, k_lint, p) - if lp > 0 { if lp < p_slice_end { - local ld = scan.read_digits(json, lp + k_lint.length()) - if ld != "" { - local rp = scan.index_of_from(json, k_rint, lp + k_lint.length()) - if rp > 0 { if rp < p_slice_end { - local rd = scan.read_digits(json, rp + k_rint.length()) - if rd != "" { print(new MiniVmScan()._int_to_str(new MiniVmScan()._str_to_int(ld) + new MiniVmScan()._str_to_int(rd))) printed = printed + 1 did = 1 pos = p_slice_end continue } - }} - } - }} - }} - // Literal string within slice - { - local k_val = "\"value\":\"" - local s = scan.index_of_from(json, k_val, p) - if s > 0 { if s < p_slice_end { - local i = s + k_val.length() - local j = scan.index_of_from(json, "\"", i) - if j > 0 { if j <= p_slice_end { - print(json.substring(i, j)) - printed = printed + 1 - did = 1 - pos = p_slice_end - continue - }} - }} - } - // Literal int within slice - { - local k_tint = "\"type\":\"int\"" - local tpos = scan.index_of_from(json, k_tint, p) - if tpos > 0 { if tpos < p_slice_end { - local k_val2 = "\"value\":" - local v2 = scan.index_of_from(json, k_val2, tpos) - if v2 > 0 { if v2 < p_slice_end { - local digits = scan.read_digits(json, v2 + k_val2.length()) - if digits != "" { print(digits) printed = printed + 1 did = 1 pos = p_slice_end continue } - }} - }} - } - if did == 1 { pos = p_slice_end + 1 continue } - } - // 0) BinaryOp typed/expr(重スキャン回避のため無効化。必要なら下の軽量パスを使用) - // 1) BinaryOp fallbacks(開発用トグル。既定OFF) - if (new MiniVmPrints()._fallback_enabled() == 1) { - local nextp = bin.try_print_binop_sum_any(json, end, p) - if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue } - nextp = bin.try_print_binop_at(json, end, p) - if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue } - nextp = bin.try_print_binop_int_greedy(json, end, p) - if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue } - nextp = bin.try_print_binop_sum_any(json, end, p) - if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue } - // Inline typed sum within this Print BinaryOp('+') - { - local k_expr = "\"expression\":{" - local epos = scan.index_of_from(json, k_expr, p) - if epos > 0 { if epos < p_obj_end { - if scan.index_of_from(json, "\"kind\":\"BinaryOp\"", epos) > 0 { - if scan.index_of_from(json, "\"operator\":\"+\"", epos) > 0 { - local k_l = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local k_r = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local lp = scan.index_of_from(json, k_l, epos) - if lp > 0 { if lp < p_obj_end { - local ld = scan.read_digits(json, lp + k_l.length()) - if ld != "" { - local rp = scan.index_of_from(json, k_r, lp + k_l.length()) - if rp > 0 { if rp < p_obj_end { - local rd = scan.read_digits(json, rp + k_r.length()) - if rd != "" { print(new MiniVmScan()._int_to_str(new MiniVmScan()._str_to_int(ld) + new MiniVmScan()._str_to_int(rd))) printed = printed + 1 pos = p_obj_end + 1 continue } - }} - } - }} - } - } - }} - } - } - // 2) Compare - nextp = cmp.try_print_compare_at(json, end, p) - if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue } - // 3) FunctionCall(既定: 軽量スライス限定パスで処理済み。重い版は呼ばない) - // nextp = new MiniVmPrints().try_print_functioncall_at(json, end, p) - // if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue } - // 4) literal string - nextp = new MiniVmPrints().try_print_string_value_at(json, end, p) - if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue } - // 5) literal int via type(重走査を避けるため無効化。スライス限定の軽量パスで処理済み) - // nextp = new MiniVmPrints().try_print_int_value_at(json, end, p) - // if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue } - // 5b) literal int(簡易フォールバック;既定OFF) - if (new MiniVmPrints()._fallback_enabled() == 1) { - local ki = "\"type\":\"int\",\"value\":" - local pi = scan.index_of_from(json, ki, p) - if pi > 0 { if pi < p_slice_end { - local digits = scan.read_digits(json, pi + ki.length()) - if digits != "" { print(digits) printed = printed + 1 pos = p_slice_end continue } - }} - // Unknown shape: skip this Print object entirely to avoid stalls - pos = p_obj_end + 1 - if pos <= p { pos = p + k_print.length() } - } else { - // 既定は最小前進(次の探索へ) - pos = p + k_print.length() - } - } - return printed - } - - // Process top-level If with literal condition; print branch prints. Returns printed count. - process_if_once(json) { - local scan = new MiniVmScan() - local k_if = "\"kind\":\"If\"" - local p = scan.index_of_from(json, k_if, 0) - if p < 0 { return 0 } - local k_cond = "\"condition\"" - local cpos = scan.index_of_from(json, k_cond, p) - if cpos < 0 { return 0 } - local k_val = "\"value\":" - local vpos = scan.index_of_from(json, k_val, cpos) - if vpos < 0 { return 0 } - local val_digits = scan.read_digits(json, vpos + k_val.length()) - local truthy = 0 - if val_digits { if val_digits != "0" { truthy = 1 } } - local k_then = "\"then_body\"" - local k_else = "\"else_body\"" - local bkey = k_then - if truthy == 0 { bkey = k_else } - local bpos = scan.index_of_from(json, bkey, cpos) - if bpos < 0 { return 0 } - local arr_start = scan.index_of_from(json, "[", bpos) - if arr_start < 0 { return 0 } - local arr_end = new MiniVmScan().find_balanced_array_end(json, arr_start) - if arr_end < 0 { return 0 } - return new MiniVmPrints().print_prints_in_slice(json, arr_start, arr_end) - } - - // Print all Print-Literal values in Program.statements (string/int only; MVP) - print_all_print_literals(json) { - return new MiniVmPrints().print_prints_in_slice(json, 0, json.length()) - } -} diff --git a/apps/selfhost/vm/boxes/mir_vm_m2.nyash b/apps/selfhost/vm/boxes/mir_vm_m2.nyash deleted file mode 100644 index 5e57c9aa..00000000 --- a/apps/selfhost/vm/boxes/mir_vm_m2.nyash +++ /dev/null @@ -1,112 +0,0 @@ -// mir_vm_m2.nyash — Ny製の最小MIR(JSON v0)実行器(M2: const/binop/ret) - -static box MirVmM2 { - _str_to_int(s) { - local i = 0 - local n = s.length() - local acc = 0 - loop (i < n) { - local ch = s.substring(i, i+1) - if ch == "0" { acc = acc * 10 + 0 i = i + 1 continue } - if ch == "1" { acc = acc * 10 + 1 i = i + 1 continue } - if ch == "2" { acc = acc * 10 + 2 i = i + 1 continue } - if ch == "3" { acc = acc * 10 + 3 i = i + 1 continue } - if ch == "4" { acc = acc * 10 + 4 i = i + 1 continue } - if ch == "5" { acc = acc * 10 + 5 i = i + 1 continue } - if ch == "6" { acc = acc * 10 + 6 i = i + 1 continue } - if ch == "7" { acc = acc * 10 + 7 i = i + 1 continue } - if ch == "8" { acc = acc * 10 + 8 i = i + 1 continue } - if ch == "9" { acc = acc * 10 + 9 i = i + 1 continue } - break - } - return acc - } - _int_to_str(n) { - if n == 0 { return "0" } - local v = n - local out = "" - loop (v > 0) { - local d = v % 10 - local ch = "0" - if d == 1 { ch = "1" } else { if d == 2 { ch = "2" } else { if d == 3 { ch = "3" } else { if d == 4 { ch = "4" } else { if d == 5 { ch = "5" } else { if d == 6 { ch = "6" } else { if d == 7 { ch = "7" } else { if d == 8 { ch = "8" } else { if d == 9 { ch = "9" } } } } } } } } - out = ch + out - v = v / 10 - } - return out - } - _find_int_in(seg, keypat) { - local p = seg.indexOf(keypat) - if p < 0 { return null } - p = p + keypat.length() - local i = p - local out = "" - loop(true) { - local ch = seg.substring(i, i+1) - if ch == "" { break } - if ch == "0" || ch == "1" || ch == "2" || ch == "3" || ch == "4" || ch == "5" || ch == "6" || ch == "7" || ch == "8" || ch == "9" { out = out + ch i = i + 1 } else { break } - } - if out == "" { return null } - return me._str_to_int(out) - } - _find_str_in(seg, keypat) { - local p = seg.indexOf(keypat) - if p < 0 { return "" } - p = p + keypat.length() - local q = seg.indexOf(""", p) - if q < 0 { return "" } - return seg.substring(p, q) - } - _get(regs, id) { if regs.has(id) { return regs.get(id) } return 0 } - _set(regs, id, v) { regs.set(id, v) } - _bin(kind, a, b) { - if kind == "Add" { return a + b } - if kind == "Sub" { return a - b } - if kind == "Mul" { return a * b } - if kind == "Div" { if b == 0 { return 0 } else { return a / b } } - return 0 - } - run(json) { - local regs = new MapBox() - local pos = json.indexOf(""instructions":[") - if pos < 0 { - print("0") - return 0 - } - local cur = pos - loop(true) { - local op_pos = json.indexOf(""op":"", cur) - if op_pos < 0 { break } - local name_start = op_pos + 6 - local name_end = json.indexOf(""", name_start) - if name_end < 0 { break } - local opname = json.substring(name_start, name_end) - local next_pos = json.indexOf(""op":"", name_end) - if next_pos < 0 { next_pos = json.length() } - local seg = json.substring(op_pos, next_pos) - if opname == "const" { - local dst = me._find_int_in(seg, ""dst":") - local val = me._find_int_in(seg, ""value":{"type":"i64","value":") - if dst != null and val != null { me._set(regs, "" + dst, val) } - } else { if opname == "binop" { - local dst = me._find_int_in(seg, ""dst":") - local kind = me._find_str_in(seg, ""op_kind":"") - local lhs = me._find_int_in(seg, ""lhs":") - local rhs = me._find_int_in(seg, ""rhs":") - if dst != null and lhs != null and rhs != null { - local a = me._get(regs, "" + lhs) - local b = me._get(regs, "" + rhs) - me._set(regs, "" + dst, me._bin(kind, a, b)) - } - } else { if opname == "ret" { - local v = me._find_int_in(seg, ""value":") - if v == null { v = 0 } - local out = me._get(regs, "" + v) - print(me._int_to_str(out)) - return 0 - } } } - cur = next_pos - } - print("0") - return 0 - } -} diff --git a/apps/selfhost/vm/boxes/mir_vm_min.nyash b/apps/selfhost/vm/boxes/mir_vm_min.nyash deleted file mode 100644 index 29a57cc0..00000000 --- a/apps/selfhost/vm/boxes/mir_vm_min.nyash +++ /dev/null @@ -1,309 +0,0 @@ -// mir_vm_min.nyash — Ny製の最小MIR(JSON v0)実行器(const→retのみ) -// 目的: M2スケルトン。仕様は既定OFFに影響しない新規アプリのみ。 -// 入力: MIR(JSON v0) 文字列。形式例: -// { -// "functions":[{"name":"main","params":[],"blocks":[{"id":0,"instructions":[ -// {"op":"const","dst":1,"value":{"type":"i64","value":42}}, -// {"op":"ret","value":1} -// ]}]}] -// } -// 振る舞い: -// - M1: 最初の const i64 の値を読み取り print -// - M2: const/binop/compare/ret を最小実装(簡易スキャンで安全に解釈) - -static box MirVmMin { - // Public entry used by parity tests (calls into minimal runner) - run(mjson) { - local v = me._run_min(mjson) - print(me._int_to_str(v)) - return v - } - // 最小限のスキャン関数(依存ゼロ版) - index_of_from(hay, needle, pos) { - if pos < 0 { pos = 0 } - local n = hay.length() - if pos >= n { return -1 } - local m = needle.length() - if m <= 0 { return pos } - local i = pos - local limit = n - m - loop (i <= limit) { - local seg = hay.substring(i, i + m) - if seg == needle { return i } - i = i + 1 - } - return -1 - } - read_digits(text, pos) { - local out = "" - local i = pos - loop (true) { - local s = text.substring(i, i+1) - if s == "" { break } - if s == "0" || s == "1" || s == "2" || s == "3" || s == "4" || s == "5" || s == "6" || s == "7" || s == "8" || s == "9" { - out = out + s - i = i + 1 - } else { break } - } - return out - } - _str_to_int(s) { - local i = 0 - local n = s.length() - local acc = 0 - loop (i < n) { - local ch = s.substring(i, i+1) - if ch == "0" { acc = acc * 10 + 0 i = i + 1 continue } - if ch == "1" { acc = acc * 10 + 1 i = i + 1 continue } - if ch == "2" { acc = acc * 10 + 2 i = i + 1 continue } - if ch == "3" { acc = acc * 10 + 3 i = i + 1 continue } - if ch == "4" { acc = acc * 10 + 4 i = i + 1 continue } - if ch == "5" { acc = acc * 10 + 5 i = i + 1 continue } - if ch == "6" { acc = acc * 10 + 6 i = i + 1 continue } - if ch == "7" { acc = acc * 10 + 7 i = i + 1 continue } - if ch == "8" { acc = acc * 10 + 8 i = i + 1 continue } - if ch == "9" { acc = acc * 10 + 9 i = i + 1 continue } - break - } - return acc - } - _int_to_str(n) { - if n == 0 { return "0" } - local v = n - local out = "" - local digits = "0123456789" - loop (v > 0) { - local d = v % 10 - local ch = digits.substring(d, d+1) - out = ch + out - v = v / 10 - } - return out - } - - // MVP: 最初の const i64 の値を抽出 - _extract_first_const_i64(text) { - if text == null { return 0 } - // "op":"const" を探す - local p = text.indexOf("\"op\":\"const\"") - if p < 0 { return 0 } - // そこから "\"value\":{\"type\":\"i64\",\"value\":" を探す - local key = "\"value\":{\"type\":\"i64\",\"value\":" - local q = me.index_of_from(text, key, p) - if q < 0 { return 0 } - q = q + key.length() - // 連続する数字を読む - local digits = me.read_digits(text, q) - if digits == "" { return 0 } - return me._str_to_int(digits) - } - - // --- M2 追加: 最小 MIR 実行(const/binop/compare/ret) --- - _get_map(regs, key) { if regs.has(key) { return regs.get(key) } return 0 } - _set_map(regs, key, val) { regs.set(key, val) } - _find_int_in(seg, keypat) { - local p = seg.indexOf(keypat) - if p < 0 { return null } - p = p + keypat.length() - local i = p - local out = "" - loop(true) { - local ch = seg.substring(i, i+1) - if ch == "" { break } - if ch == "0" || ch == "1" || ch == "2" || ch == "3" || ch == "4" || ch == "5" || ch == "6" || ch == "7" || ch == "8" || ch == "9" { out = out + ch i = i + 1 } else { break } - } - if out == "" { return null } - return me._str_to_int(out) - } - _find_str_in(seg, keypat) { - local p = seg.indexOf(keypat) - if p < 0 { return "" } - p = p + keypat.length() - local q = me.index_of_from(seg, "\"", p) - if q < 0 { return "" } - return seg.substring(p, q) - } - // --- JSON segment helpers (brace/bracket aware, minimal) --- - _seek_obj_start(text, from_pos) { - // scan backward to the nearest '{' - local i = from_pos - loop(true) { - i = i - 1 - if i < 0 { return 0 } - local ch = text.substring(i, i+1) - if ch == "{" { return i } - } - return 0 - } - _seek_obj_end(text, obj_start) { - // starting at '{', find matching '}' using depth counter - local i = obj_start - local depth = 0 - loop(true) { - local ch = text.substring(i, i+1) - if ch == "" { break } - if ch == "{" { depth = depth + 1 } - else { if ch == "}" { depth = depth - 1 } } - if depth == 0 { return i + 1 } - i = i + 1 - } - return i - } - _seek_array_end(text, array_after_bracket_pos) { - // given pos right after '[', find the matching ']' - local i = array_after_bracket_pos - local depth = 1 - loop(true) { - local ch = text.substring(i, i+1) - if ch == "" { break } - if ch == "[" { depth = depth + 1 } - else { if ch == "]" { depth = depth - 1 } } - if depth == 0 { return i } - i = i + 1 - } - return i - } - _map_binop_symbol(sym) { - if sym == "+" { return "Add" } - if sym == "-" { return "Sub" } - if sym == "*" { return "Mul" } - if sym == "/" { return "Div" } - if sym == "%" { return "Mod" } - return "" } - _map_cmp_symbol(sym) { - if sym == "==" { return "Eq" } - if sym == "!=" { return "Ne" } - if sym == "<" { return "Lt" } - if sym == "<=" { return "Le" } - if sym == ">" { return "Gt" } - if sym == ">=" { return "Ge" } - return "" } - _eval_binop(kind, a, b) { - if kind == "Add" { return a + b } - if kind == "Sub" { return a - b } - if kind == "Mul" { return a * b } - if kind == "Div" { if b == 0 { return 0 } else { return a / b } } - if kind == "Mod" { if b == 0 { return 0 } else { return a % b } } - return 0 } - _eval_cmp(kind, a, b) { - if kind == "Eq" { if a == b { return 1 } else { return 0 } } - if kind == "Ne" { if a != b { return 1 } else { return 0 } } - if kind == "Lt" { if a < b { return 1 } else { return 0 } } - if kind == "Gt" { if a > b { return 1 } else { return 0 } } - if kind == "Le" { if a <= b { return 1 } else { return 0 } } - if kind == "Ge" { if a >= b { return 1 } else { return 0 } } - return 0 - } - // Locate start of instructions array for given block id - _block_insts_start(mjson, bid) { - local key = "\"id\":" + me._int_to_str(bid) - local p = mjson.indexOf(key) - if p < 0 { return -1 } - local q = me.index_of_from(mjson, "\"instructions\":[", p) - if q < 0 { return -1 } - // "\"instructions\":[" is 16 chars → return pos right after '[' - return q + 16 - } - _block_insts_end(mjson, insts_start) { - // Bound to the end bracket of this block's instructions array - return me._seek_array_end(mjson, insts_start) - } - _run_min(mjson) { - local regs = new MapBox() - // Control flow: start at block 0, process until ret - local bb = 0 - loop(true) { - local pos = me._block_insts_start(mjson, bb) - if pos < 0 { return me._extract_first_const_i64(mjson) } - local block_end = me._block_insts_end(mjson, pos) - // Single-pass over instructions: segment each op object precisely and evaluate - local scan = pos - local moved = 0 - loop(true) { - // find next op field within this block - local opos = me.index_of_from(mjson, "\"op\":\"", scan) - if opos < 0 || opos >= block_end { break } - // find exact JSON object bounds for this instruction - // Determine object start as the last '{' between pos..opos - local i = pos - local obj_start = opos - loop(i <= opos) { - local ch0 = mjson.substring(i, i+1) - if ch0 == "{" { obj_start = i } - i = i + 1 - } - local obj_end = me._seek_obj_end(mjson, obj_start) - if obj_end > block_end { obj_end = block_end } - local seg = mjson.substring(obj_start, obj_end) - - // dispatch by op name (v0/v1 tolerant) - local opname = me._find_str_in(seg, "\"op\":\"") - if opname == "const" { - local cdst = me._find_int_in(seg, "\"dst\":") - local cval = me._find_int_in(seg, "\"value\":{\"type\":\"i64\",\"value\":") - if cdst != null and cval != null { me._set_map(regs, "" + cdst, cval) } - } else { - if opname == "binop" { - local bdst = me._find_int_in(seg, "\"dst\":") - local bkind = me._find_str_in(seg, "\"op_kind\":\"") - if bkind == "" { bkind = me._map_binop_symbol(me._find_str_in(seg, "\"operation\":\"")) } - local blhs = me._find_int_in(seg, "\"lhs\":") - local brhs = me._find_int_in(seg, "\"rhs\":") - if bdst != null and blhs != null and brhs != null { - local a = me._get_map(regs, "" + blhs) - local b = me._get_map(regs, "" + brhs) - local r = me._eval_binop(bkind, a, b) - me._set_map(regs, "" + bdst, r) - } - } else { - if opname == "compare" { - local kdst = me._find_int_in(seg, "\"dst\":") - local kkind = me._find_str_in(seg, "\"cmp\":\"") - if kkind == "" { kkind = me._map_cmp_symbol(me._find_str_in(seg, "\"operation\":\"")) } - local klhs = me._find_int_in(seg, "\"lhs\":") - local krhs = me._find_int_in(seg, "\"rhs\":") - if kdst != null and klhs != null and krhs != null { - local a = me._get_map(regs, "" + klhs) - local b = me._get_map(regs, "" + krhs) - local r = me._eval_cmp(kkind, a, b) - me._set_map(regs, "" + kdst, r) - } - } else { - if opname == "jump" { - local tgt = me._find_int_in(seg, "\"target\":") - if tgt != null { bb = tgt scan = block_end moved = 1 break } - } else { - if opname == "branch" { - local cond = me._find_int_in(seg, "\"cond\":") - local then_id = me._find_int_in(seg, "\"then\":") - local else_id = me._find_int_in(seg, "\"else\":") - local cval = 0 - if cond != null { cval = me._get_map(regs, "" + cond) } - if cval != 0 { bb = then_id } else { bb = else_id } - scan = block_end - moved = 1 - break - } else { - if opname == "ret" { - local rv = me._find_int_in(seg, "\"value\":") - if rv == null { rv = 0 } - return me._get_map(regs, "" + rv) - } - } - } - } - } - } - - // advance to the end of this instruction object - scan = obj_end - } - // No ret encountered in this block; if control moved, continue with new bb - if moved == 1 { continue } - // Fallback when ret not found at all in processed blocks - return me._extract_first_const_i64(mjson) - } - return me._extract_first_const_i64(mjson) - } - -} diff --git a/apps/selfhost/vm/boxes/seam_inspector.nyash b/apps/selfhost/vm/boxes/seam_inspector.nyash deleted file mode 100644 index bc9aec7a..00000000 --- a/apps/selfhost/vm/boxes/seam_inspector.nyash +++ /dev/null @@ -1,249 +0,0 @@ -// SeamInspector — analyze inlined code seam and duplicates -// Usage: import and call report(text) or analyze_dump_file(path) - -static box SeamInspector { - // Count brace delta ignoring simple strings ("...") and escapes - _brace_delta_ignoring_strings(text, start, end) { - @i = start - @n = end - @delta = 0 - loop (i < n) { - @ch = text.substring(i, i+1) - if ch == "\"" { - i = i + 1 - loop (i < n) { - @c = text.substring(i, i+1) - if c == "\\" { i = i + 2 continue } - if c == "\"" { i = i + 1 break } - i = i + 1 - } - continue - } - if ch == "{" { delta = delta + 1 } - if ch == "}" { delta = delta - 1 } - i = i + 1 - } - return delta - } - - // Find index of exact token in plain text from position - _index_of_from(h, needle, pos) { - if pos < 0 { pos = 0 } - @n = h.length() - if pos >= n { return -1 } - @m = needle.length() - if m <= 0 { return pos } - @i = pos - @limit = n - m - loop (i <= limit) { - if h.substring(i, i+m) == needle { return i } - i = i + 1 - } - return -1 - } - - // Find matching closing brace starting at '{' - _find_balanced_object_end(text, idx) { - if text.substring(idx, idx+1) != "{" { return -1 } - @i = idx - @n = text.length() - @depth = 0 - loop (i < n) { - @ch = text.substring(i, i+1) - if ch == "\"" { - i = i + 1 - loop (i < n) { - @c = text.substring(i, i+1) - if c == "\\" { i = i + 2 continue } - if c == "\"" { i = i + 1 break } - i = i + 1 - } - continue - } - if ch == "{" { depth = depth + 1 } - if ch == "}" { depth = depth - 1 if depth == 0 { return i } } - i = i + 1 - } - return -1 - } - - // Scan boxes: return array of {name, start, end} - _scan_boxes(text) { - @i = 0 - @n = text.length() - @res = new ArrayBox() - @tok = "static box " - loop (i < n) { - @p = _index_of_from(text, tok, i) - if p < 0 { break } - @j = p + tok.length() - // read identifier - @name = "" - loop (j < n) { - @c = text.substring(j, j+1) - // ASCII alpha-num or '_' - if c == "_" { name = name + c j = j + 1 continue } - // digits - if c == "0" or c == "1" or c == "2" or c == "3" or c == "4" or c == "5" or c == "6" or c == "7" or c == "8" or c == "9" { name = name + c j = j + 1 continue } - // letters - if (c >= "A" and c <= "Z") or (c >= "a" and c <= "z") { name = name + c j = j + 1 continue } - break - } - // skip to '{' - loop (j < n) { - @c2 = text.substring(j, j+1) - if c2 == "{" { break } - j = j + 1 - } - @end = _find_balanced_object_end(text, j) - if end < 0 { end = j } - @obj = new MapBox() - obj.set("name", name) - obj.set("start", _int_to_str(p)) - obj.set("end", _int_to_str(end)) - res.push(obj) - i = end + 1 - } - return res - } - - // Print duplicate boxes by name - _report_duplicate_boxes(text) { - @boxes = _scan_boxes(text) - @cnt = new MapBox() - @names = new ArrayBox() - @i = 0 - loop (i < boxes.size()) { - @name = boxes.get(i).get("name") - @cur = cnt.get(name) - if cur == null { cnt.set(name, "1") names.push(name) } else { cnt.set(name, _int_to_str(_str_to_int(cur) + 1)) } - i = i + 1 - } - @j = 0 - loop (j < names.size()) { - @k = names.get(j) - @v = cnt.get(k) - if _str_to_int(v) > 1 { print("dup_box " + k + " x" + v) } - j = j + 1 - } - return 0 - } - - // Inside a given box, count function name duplicates (simple scan: name(...){ ) - _report_duplicate_functions_in_box(text, box_name) { - @boxes = _scan_boxes(text) - @i = 0 - @fnmap = new MapBox() - @fnames = new ArrayBox() - loop (i < boxes.size()) { - @b = boxes.get(i) - if b.get("name") == box_name { - @s = _str_to_int(b.get("start")) - @e = _str_to_int(b.get("end")) - @j = s - loop (j < e) { - // find identifier start at line head-ish (naive) - // pattern: ident '(' ... '{' - @k = j - // skip spaces/newlines - loop (k < e) { - @ch = text.substring(k, k+1) - if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" { k = k + 1 continue } - break - } - if k >= e { break } - // read ident - @name = "" - @p = k - @c0 = text.substring(p, p+1) - if (c0 >= "A" and c0 <= "Z") or (c0 >= "a" and c0 <= "z") or c0 == "_" { - loop (p < e) { - @c = text.substring(p, p+1) - if (c >= "A" and c <= "Z") or (c >= "a" and c <= "z") or (c >= "0" and c <= "9") or c == "_" { name = name + c p = p + 1 continue } - break - } - // must be a function definition: ident '(' ... ')' ws* '{' - if text.substring(p, p+1) == "(" { - // find matching ')' with a simple counter (strings ignored for simplicity) - @d = 0 - @r = p - loop (r < e) { - @cc = text.substring(r, r+1) - if cc == "(" { d = d + 1 r = r + 1 continue } - if cc == ")" { - d = d - 1 - r = r + 1 - if d <= 0 { break } - continue - } - if cc == "\"" { - // skip string inside params - r = r + 1 - loop (r < e) { - @c2 = text.substring(r, r+1) - if c2 == "\\" { r = r + 2 continue } - if c2 == "\"" { r = r + 1 break } - r = r + 1 - } - continue - } - r = r + 1 - } - // skip ws - loop (r < e) { - @ws = text.substring(r, r+1) - if ws == " " or ws == "\t" or ws == "\r" or ws == "\n" { r = r + 1 continue } - break - } - // definition only if next is '{' - if r < e and text.substring(r, r+1) == "{" { - @cur = fnmap.get(name) - if cur == null { fnmap.set(name, "1") fnames.push(name) } else { fnmap.set(name, _int_to_str(_str_to_int(cur) + 1)) } - } - } - } - // advance to next line - @nl = _index_of_from(text, "\n", k+1) - if nl < 0 || nl > e { break } - j = nl + 1 - } - break - } - i = i + 1 - } - @x = 0 - loop (x < fnames.size()) { - @nm = fnames.get(x) - @ct = fnmap.get(nm) - if _str_to_int(ct) > 1 { print("dup_fn " + box_name + "." + nm + " x" + ct) } - x = x + 1 - } - return 0 - } - - // Report summary - report(text) { - // find Main - @m = _index_of_from(text, "static box Main {", 0) - @delta = -9999 - if m > 0 { delta = _brace_delta_ignoring_strings(text, 0, m) } - print("prelude_brace_delta=" + _int_to_str(delta)) - - // duplicate boxes - _report_duplicate_boxes(text) - - // specific hot-spot - _report_duplicate_functions_in_box(text, "MiniVmPrints") - return 0 - } - - // Load dump file and report - analyze_dump_file(path) { - @fb = new FileBox() - @f = fb.open(path) - if f == null { print("warn: cannot open " + path) return 0 } - @text = f.read() - f.close() - return me.report(text) - } -} diff --git a/apps/selfhost/vm/boxes/vm_kernel_box.nyash b/apps/selfhost/vm/boxes/vm_kernel_box.nyash deleted file mode 100644 index 84c015c9..00000000 --- a/apps/selfhost/vm/boxes/vm_kernel_box.nyash +++ /dev/null @@ -1,32 +0,0 @@ -// vm_kernel_box.nyash — NYABI Kernel (skeleton, dev-only; not wired) -// Scope: Provide policy/decision helpers behind an explicit OFF toggle. -// Notes: This box is not referenced by the VM by default. - -static box VmKernelBox { - // Report version and supported features. - caps() { - // v0 draft: features are informative only. - return "{\"version\":0,\"features\":[\"policy\"]}" - } - - // Decide stringify strategy for a given type. - // Returns: "direct" | "rewrite_stringify" | "fallback" - stringify_policy(typeName) { - if typeName == "VoidBox" { return "rewrite_stringify" } - return "fallback" - } - - // Decide equals strategy for two types. - // Returns: "object" | "value" | "fallback" - equals_policy(lhsType, rhsType) { - if lhsType == rhsType { return "value" } - return "fallback" - } - - // Batch resolve method dispatch plans. - // Input/Output via tiny JSON strings (draft). Returns "{\"plans\":[]}" for now. - resolve_method_batch(reqs_json) { - return "{\"plans\":[]}" - } -} - diff --git a/apps/selfhost/vm/collect_empty_args_smoke.nyash b/apps/selfhost/vm/collect_empty_args_smoke.nyash deleted file mode 100644 index db30647a..00000000 --- a/apps/selfhost/vm/collect_empty_args_smoke.nyash +++ /dev/null @@ -1,59 +0,0 @@ -// Self-contained dev smoke for FunctionCall empty-args -// Goal: echo() -> empty line, itoa() -> 0 - -static box MiniVm { - // simple substring find from position - index_of_from(hay, needle, pos) { - if pos < 0 { pos = 0 } - if pos >= hay.length() { return -1 } - local tail = hay.substring(pos, hay.length()) - local rel = tail.indexOf(needle) - if rel < 0 { return -1 } else { return pos + rel } - } - - // collect only FunctionCall with empty arguments [] for echo/itoa - collect_prints(json) { - local out = new ArrayBox() - local pos = 0 - local guard = 0 - loop (true) { - guard = guard + 1 - if guard > 16 { break } - local k_fc = "\"kind\":\"FunctionCall\"" - local p = index_of_from(json, k_fc, pos) - if p < 0 { break } - // name - local k_n = "\"name\":\"" - local np = index_of_from(json, k_n, p) - if np < 0 { break } - local ni = np + k_n.length() - local nj = index_of_from(json, "\"", ni) - if nj < 0 { break } - local fname = json.substring(ni, nj) - // args [] detection - local k_a = "\"arguments\":[" - local ap = index_of_from(json, k_a, nj) - if ap < 0 { break } - local rb = index_of_from(json, "]", ap) - if rb < 0 { break } - // no content between '[' and ']' - if rb == ap + k_a.length() { - if fname == "echo" { out.push("") } - if fname == "itoa" { out.push("0") } - } - pos = rb + 1 - } - return out - } -} - -static box Main { - main(args) { - local json = "{\"kind\":\"Program\",\"statements\":[{\"kind\":\"Print\",\"expression\":{\"kind\":\"FunctionCall\",\"name\":\"echo\",\"arguments\":[]}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"FunctionCall\",\"name\":\"itoa\",\"arguments\":[]}}]}" - - local arr = new MiniVm().collect_prints(json) - local i = 0 - loop (i < arr.size()) { print(arr.get(i)) i = i + 1 } - return 0 - } -} diff --git a/apps/selfhost/vm/collect_empty_args_using_smoke.nyash b/apps/selfhost/vm/collect_empty_args_using_smoke.nyash deleted file mode 100644 index 33f862cc..00000000 --- a/apps/selfhost/vm/collect_empty_args_using_smoke.nyash +++ /dev/null @@ -1,14 +0,0 @@ -using selfhost.vm.boxes.mini_vm_core as MiniVm - -static box Main { - main(args) { - local json = "{\"kind\":\"Program\",\"statements\":[{\"kind\":\"Print\",\"expression\":{\"kind\":\"FunctionCall\",\"name\":\"echo\",\"arguments\":[]}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"FunctionCall\",\"name\":\"itoa\",\"arguments\":[]}}]}" - - local arr = new MiniVm().collect_prints(json) - print("DEBUG: arr.size=" + arr.size()) - local i = 0 - loop (i < arr.size()) { print(arr.get(i)) i = i + 1 } - return 0 - } -} - diff --git a/apps/selfhost/vm/collect_literal_eval.nyash b/apps/selfhost/vm/collect_literal_eval.nyash deleted file mode 100644 index 6127d77a..00000000 --- a/apps/selfhost/vm/collect_literal_eval.nyash +++ /dev/null @@ -1,30 +0,0 @@ -// Minimal self-contained eval (no using): collect the first Print(Literal int) and print it -static box Main { - // helper: find from position - index_of_from(hay, needle, pos) { - if pos < 0 { pos = 0 } - if pos >= hay.length() { return -1 } - local tail = hay.substring(pos, hay.length()) - local rel = tail.indexOf(needle) - if rel < 0 { return -1 } else { return pos + rel } - } - main(args) { - local json = "{\"kind\":\"Program\",\"statements\":[{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":42}}}]}" - // naive collect: first Print of Literal int - local ki = "\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local p = json.indexOf(ki) - if p >= 0 { - local i = p + ki.length() - local j = i - loop (true) { - local ch = json.substring(j, j+1) - if ch == "" { break } - if ch == "0" || ch == "1" || ch == "2" || ch == "3" || ch == "4" || ch == "5" || ch == "6" || ch == "7" || ch == "8" || ch == "9" { j = j + 1 continue } - break - } - local digits = json.substring(i, j) - if digits { print(digits) } - } - return 0 - } -} diff --git a/apps/selfhost/vm/collect_mixed_smoke.nyash b/apps/selfhost/vm/collect_mixed_smoke.nyash deleted file mode 100644 index 25a1005a..00000000 --- a/apps/selfhost/vm/collect_mixed_smoke.nyash +++ /dev/null @@ -1,282 +0,0 @@ -static box Main { - // --- minimal helpers (self-contained) --- - index_of_from(hay, needle, pos) { - if pos < 0 { pos = 0 } - if pos >= hay.length() { return -1 } - local tail = hay.substring(pos, hay.length()) - local rel = tail.indexOf(needle) - if rel < 0 { return -1 } - return pos + rel - } - _is_digit(ch) { - if ch == "0" { return 1 } - if ch == "1" { return 1 } - if ch == "2" { return 1 } - if ch == "3" { return 1 } - if ch == "4" { return 1 } - if ch == "5" { return 1 } - if ch == "6" { return 1 } - if ch == "7" { return 1 } - if ch == "8" { return 1 } - if ch == "9" { return 1 } - return 0 - } - read_digits(s, pos) { - if pos < 0 { return "" } - local n = s.length() - if pos >= n { return "" } - local i = pos - local out_start = -1 - loop (i < n) { - local ch = s.substring(i, i+1) - if _is_digit(ch) == 1 { if out_start < 0 { out_start = i } i = i + 1 continue } else { break } - } - if out_start < 0 { return "" } - return s.substring(out_start, i) - } - find_balanced_object_end(json, idx) { - if idx < 0 { return -1 } - local n = json.length() - if idx >= n { return -1 } - local depth = 0 - local in_str = 0 - local i = idx - local iter = 0 - loop (i < n) { - iter = iter + 1 - if iter > 5000 { return -1 } - local ch = json.substring(i, i+1) - if in_str == 1 { - if ch == "\\" { i = i + 2 continue } - if ch == "\"" { in_str = 0 } - i = i + 1 - continue - } - if ch == "\"" { in_str = 1 i = i + 1 continue } - if ch == "{" { depth = depth + 1 } - if ch == "}" { depth = depth - 1 if depth == 0 { return i + 1 } } - i = i + 1 - } - return -1 - } - // --- core: collect Print outputs in order --- - collect_prints(json) { - local out = new ArrayBox() - local pos = 0 - local guard = 0 - local k_print = "\"kind\":\"Print\"" - loop (true) { - guard = guard + 1 - if guard > 200 { break } - local p = index_of_from(json, k_print, pos) - if p < 0 { break } - // bound current Print slice as [current_print, next_print) - local obj_start = p - local next_p = index_of_from(json, k_print, p + k_print.length()) - local obj_end = json.length() - if next_p > 0 { obj_end = next_p } - - // 1) BinaryOp(int '+' int) - { - local k_expr = "\"expression\":{" - local epos = index_of_from(json, k_expr, obj_start) - if epos > 0 { if epos < obj_end { - local k_bo = "\"kind\":\"BinaryOp\"" - local bpos = index_of_from(json, k_bo, epos) - if bpos > 0 { if bpos < obj_end { - local opok = index_of_from(json, "\"operator\":\"+\"", bpos) - if opok > 0 { - // typed left/right literal ints - local k_l = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local k_r = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" - local lp = index_of_from(json, k_l, bpos) - if lp > 0 { if lp < obj_end { - local ld = read_digits(json, lp + k_l.length()) - if ld != "" { - local rp = index_of_from(json, k_r, lp + k_l.length()) - if rp > 0 { if rp < obj_end { - local rd = read_digits(json, rp + k_r.length()) - if rd != "" { out.push(_int_to_str(_str_to_int(ld) + _str_to_int(rd))) pos = p + k_print.length() continue } - }} - } - }} - // fallback: scan two successive '"value":' digits within expression bounds - local k_v = "\"value\":" - local v1 = index_of_from(json, k_v, epos) - if v1 > 0 { if v1 < obj_end { - local d1 = read_digits(json, v1 + k_v.length()) - if d1 != "" { - local v2 = index_of_from(json, k_v, v1 + k_v.length()) - if v2 > 0 { if v2 < obj_end { - local d2 = read_digits(json, v2 + k_v.length()) - if d2 != "" { out.push(_int_to_str(_str_to_int(d1) + _str_to_int(d2))) pos = p + k_print.length() continue } - }} - } - }} - } - }} - }} - } - - // 2) Compare(lhs/rhs ints): prints 1/0 - { - local k_cp = "\"kind\":\"Compare\"" - local cpos = index_of_from(json, k_cp, obj_start) - if cpos > 0 { if cpos < obj_end { - local k_op = "\"operation\":\"" - local opos = index_of_from(json, k_op, cpos) - if opos > 0 { if opos < obj_end { - local oi = opos + k_op.length() - local oj = index_of_from(json, "\"", oi) - if oj > 0 { if oj <= obj_end { - local op = json.substring(oi, oj) - local k_v = "\"value\":" - local lhs_v = index_of_from(json, k_v, oj) - if lhs_v > 0 { if lhs_v < obj_end { - local la = read_digits(json, lhs_v + k_v.length()) - if la != "" { - local rhs_v = index_of_from(json, k_v, lhs_v + k_v.length()) - if rhs_v > 0 { if rhs_v < obj_end { - local rb = read_digits(json, rhs_v + k_v.length()) - if rb != "" { - local ai = _str_to_int(la) - local bi = _str_to_int(rb) - local res = 0 - if op == "<" { if ai < bi { res = 1 } } - if op == "==" { if ai == bi { res = 1 } } - if op == "<=" { if ai <= bi { res = 1 } } - if op == ">" { if ai > bi { res = 1 } } - if op == ">=" { if ai >= bi { res = 1 } } - if op == "!=" { if ai != bi { res = 1 } } - out.push(_int_to_str(res)) - pos = p + k_print.length() - continue - } - }} - } - }} - }} - }} - }} - } - - // 3) FunctionCall echo/itoa (single literal arg) - { - local k_fc = "\"kind\":\"FunctionCall\"" - local fcp = index_of_from(json, k_fc, obj_start) - if fcp > 0 { if fcp < obj_end { - local kn = "\"name\":\"" - local np = index_of_from(json, kn, fcp) - if np > 0 { if np < obj_end { - local ni = np + kn.length() - local nj = index_of_from(json, "\"", ni) - if nj > 0 { if nj <= obj_end { - local fname = json.substring(ni, nj) - local ka = "\"arguments\":[" - local ap = index_of_from(json, ka, nj) - if ap > 0 { if ap < obj_end { - // string arg - local ks = "\"type\":\"string\",\"value\":\"" - local ps = index_of_from(json, ks, ap) - if ps > 0 { if ps < obj_end { - local si = ps + ks.length() - local sj = index_of_from(json, "\"", si) - if sj > 0 { if sj <= obj_end { - local sval = json.substring(si, sj) - if fname == "echo" { out.push(sval) pos = p + k_print.length() continue } - }} - }} - // int arg - local ki = "\"type\":\"int\",\"value\":" - local pi = index_of_from(json, ki, ap) - if pi > 0 { if pi < obj_end { - local ival = read_digits(json, pi + ki.length()) - if ival != "" { if fname == "itoa" { out.push(ival) pos = p + k_print.length() continue } else { if fname == "echo" { out.push(ival) pos = p + k_print.length() continue } } } - }} - }} - }} - }} - }} - } - - // 4) Literal string - { - local ks = "\"type\":\"string\",\"value\":\"" - local ps = index_of_from(json, ks, obj_start) - if ps > 0 { if ps < obj_end { - local si = ps + ks.length() - local sj = index_of_from(json, "\"", si) - if sj > 0 { if sj <= obj_end { out.push(json.substring(si, sj)) pos = p + k_print.length() continue }} - }} - } - // 5) Literal int - { - local ki = "\"type\":\"int\",\"value\":" - local pi = index_of_from(json, ki, obj_start) - if pi > 0 { if pi < obj_end { - local digits = read_digits(json, pi + ki.length()) - if digits != "" { out.push(digits) pos = p + k_print.length() continue } - }} - } - // Unknown: skip ahead - pos = p + k_print.length() - if pos <= p { pos = p + 1 } - } - return out - } - // int<->str (non-negative only) - _str_to_int(s) { - local n = 0 - local i = 0 - loop (i < s.length()) { - local ch = s.substring(i, i+1) - n = n * 10 - if ch == "0" { n = n + 0 } - if ch == "1" { n = n + 1 } - if ch == "2" { n = n + 2 } - if ch == "3" { n = n + 3 } - if ch == "4" { n = n + 4 } - if ch == "5" { n = n + 5 } - if ch == "6" { n = n + 6 } - if ch == "7" { n = n + 7 } - if ch == "8" { n = n + 8 } - if ch == "9" { n = n + 9 } - i = i + 1 - } - return n - } - _int_to_str(n) { - if n == 0 { return "0" } - local s = new ArrayBox() - local x = n - loop (x > 0) { - local d = x % 10 - if d == 0 { s.push("0") } - if d == 1 { s.push("1") } - if d == 2 { s.push("2") } - if d == 3 { s.push("3") } - if d == 4 { s.push("4") } - if d == 5 { s.push("5") } - if d == 6 { s.push("6") } - if d == 7 { s.push("7") } - if d == 8 { s.push("8") } - if d == 9 { s.push("9") } - x = (x - d) / 10 - } - local out = new ArrayBox() - local i = s.size() - 1 - loop (i >= 0) { out.push(s.get(i)) i = i - 1 } - local j = 0 - local acc = "" - loop (j < out.size()) { acc = acc + out.get(j) j = j + 1 } - return acc - } - main(args) { - local json = "{\"kind\":\"Program\",\"statements\":[{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"string\",\"value\":\"A\"}}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"FunctionCall\",\"name\":\"echo\",\"arguments\":[{\"kind\":\"Literal\",\"value\":{\"type\":\"string\",\"value\":\"B\"}}]}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"FunctionCall\",\"name\":\"itoa\",\"arguments\":[{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":7}}]}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"Compare\",\"operation\":\"<\",\"lhs\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":1}},\"rhs\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":2}}}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"BinaryOp\",\"operator\":\"+\",\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":3}},\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":4}}}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":5}}}]}" - - local arr = collect_prints(json) - local i = 0 - loop (i < arr.size()) { print(arr.get(i)) i = i + 1 } - return 0 - } -} diff --git a/apps/selfhost/vm/collect_mixed_using_smoke.nyash b/apps/selfhost/vm/collect_mixed_using_smoke.nyash deleted file mode 100644 index 178ec4b7..00000000 --- a/apps/selfhost/vm/collect_mixed_using_smoke.nyash +++ /dev/null @@ -1,11 +0,0 @@ -using selfhost.vm.boxes.mini_vm_core as MiniVm -using selfhost.vm.boxes.mini_vm_prints as MiniVmPrints - -static box Main { - main(args) { - local json = "{\"kind\":\"Program\",\"statements\":[{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"string\",\"value\":\"A\"}}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"FunctionCall\",\"name\":\"echo\",\"arguments\":[{\"kind\":\"Literal\",\"value\":{\"type\":\"string\",\"value\":\"B\"}}]}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"FunctionCall\",\"name\":\"itoa\",\"arguments\":[{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":7}}]}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"Compare\",\"operation\":\"<\",\"lhs\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":1}},\"rhs\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":2}}}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"BinaryOp\",\"operator\":\"+\",\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":3}},\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":4}}}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":5}}}]}" - - new MiniVmPrints().print_prints_in_slice(json, 0, json.length()) - return 0 - } -} diff --git a/apps/selfhost/vm/collect_prints_loader_smoke.nyash b/apps/selfhost/vm/collect_prints_loader_smoke.nyash deleted file mode 100644 index ad25013c..00000000 --- a/apps/selfhost/vm/collect_prints_loader_smoke.nyash +++ /dev/null @@ -1,18 +0,0 @@ -using selfhost.vm.core as MiniVm - -static box Main { - main(args) { - // Mixed shapes (loader-centric) - // 1) echo() with empty args -> "" - // 2) string literal with quotes inside - // 3) itoa() with empty args -> "0" - // 4) BinaryOp 8+9 - // 5) int literal 4 - local json = "{\"kind\":\"Program\",\"statements\":[{\"kind\":\"Print\",\"expression\":{\"kind\":\"FunctionCall\",\"name\":\"echo\",\"arguments\":[]}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"string\",\"value\":\"C\"}}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"FunctionCall\",\"name\":\"itoa\",\"arguments\":[]}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"BinaryOp\",\"operator\":\"+\",\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":8}},\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":9}}}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":4}}}]}" - - local arr = new MiniVm().collect_prints(json) - local i = 0 - loop (i < arr.size()) { print(arr.get(i)) i = i + 1 } - return 0 - } -} diff --git a/apps/selfhost/vm/json_loader.nyash b/apps/selfhost/vm/json_loader.nyash deleted file mode 100644 index 453ddf84..00000000 --- a/apps/selfhost/vm/json_loader.nyash +++ /dev/null @@ -1,51 +0,0 @@ -// MiniJsonLoader (Stage-B scaffold) -// Purpose: centralize minimal JSON cursor ops for Mini-VM. -// Implementation note: For now we delegate to local MiniJsonCur-compatible -// helpers. In a later step, this can be swapped to use `apps/libs/json_cur.nyash` -// (JsonCursorBox) without touching Mini-VM call sites. - -static box MiniJsonLoader { - read_quoted_from(s, pos) { - // Local fallback (same behavior as MiniJsonCur.read_quoted_from) - // Keep in sync with Mini-VM until libs adoption gate is enabled. - local i = pos - if s.substring(i, i+1) != "\"" { return "" } - i = i + 1 - local out = "" - local n = s.length() - loop (i < n) { - local ch = s.substring(i, i+1) - if ch == "\"" { break } - if ch == "\\" { i = i + 1 ch = s.substring(i, i+1) } - out = out + ch - i = i + 1 - } - return out - } - read_digits_from(s, pos) { - local out = "" - local i = pos - if i == null { return out } - if i < 0 { return out } - loop (true) { - local ch = s.substring(i, i+1) - if ch == "" { break } - if ch == "0" || ch == "1" || ch == "2" || ch == "3" || ch == "4" || ch == "5" || ch == "6" || ch == "7" || ch == "8" || ch == "9" { - out = out + ch - i = i + 1 - } else { break } - } - return out - } - next_non_ws(s, pos) { - local i = pos - local n = s.length() - loop (i < n) { - local ch = s.substring(i, i+1) - if ch != " " && ch != "\n" && ch != "\r" && ch != "\t" { return i } - i = i + 1 - } - return -1 - } -} - diff --git a/apps/selfhost/vm/mini_vm.nyash b/apps/selfhost/vm/mini_vm.nyash deleted file mode 100644 index f22525c4..00000000 --- a/apps/selfhost/vm/mini_vm.nyash +++ /dev/null @@ -1,12 +0,0 @@ -// Thin entry: delegate to core MiniVm -// Using is pre-inlined by runner; keep entry minimal for maintainability. -using selfhost.vm.core as MiniVm - -static box Main { - main(args) { - @json = "{\"kind\":\"Program\",\"statements\":[{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":42}}}]}" - if args { if args.size() > 0 { @s = args.get(0) if s { json = s } } } - return new MiniVm().run(json) - } -} - diff --git a/apps/selfhost/vm/mini_vm_if_branch.nyash b/apps/selfhost/vm/mini_vm_if_branch.nyash deleted file mode 100644 index 99a9b4a4..00000000 --- a/apps/selfhost/vm/mini_vm_if_branch.nyash +++ /dev/null @@ -1,59 +0,0 @@ -// Mini-VM: function-based entry for branching -// Local static box (duplicated from mini_vm_lib for now to avoid include gate issues) -static box MiniVm { - _is_digit(ch) { return ch == "0" || ch == "1" || ch == "2" || ch == "3" || ch == "4" || ch == "5" || ch == "6" || ch == "7" || ch == "8" || ch == "9" } - read_digits(json, pos) { - @out = "" - loop (true) { - @s = json.substring(pos, pos+1) - if s == "" { break } - if _is_digit(s) { out = out + s pos = pos + 1 } else { break } - } - return out - } - parse_first_int(json) { - @key = "\"value\":{\"type\":\"int\",\"value\":" - @idx = json.lastIndexOf(key) - if idx < 0 { return "0" } - @start = idx + key.length() - return read_digits(json, start) - } - run_branch(json) { - @n = parse_first_int(json) - if n == "0" || n == "1" || n == "2" || n == "3" || n == "4" { print("10") return 0 } - print("20") - return 0 - } -} - -// Program entry: embedded JSON (value=1 → print 10; else → 20) -static box Main { - main(args) { - @vm = new MiniVm() - @json = "{\"kind\":\"Program\",\"statements\":[{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":1}}}]}" - // If provided, override by argv[0] - if args { - if args.size() > 0 { - @s = args.get(0) - if s { json = s } - } - } - return vm.run_branch(json) - } -} - -// Top-level fallback entry for current runner -function main(args) { - @vm = new MiniVm() - @json = "{\"kind\":\"Program\",\"statements\":[{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":1}}}]}" - if args { - if args.size() > 0 { - @s = args.get(0) - if s { json = s } - } - } - @n = vm.parse_first_int(json) - if n == "0" || n == "1" || n == "2" || n == "3" || n == "4" { print("10") return 0 } - print("20") - return 0 -} diff --git a/apps/selfhost/vm/mini_vm_lib.nyash b/apps/selfhost/vm/mini_vm_lib.nyash deleted file mode 100644 index 3e6810e8..00000000 --- a/apps/selfhost/vm/mini_vm_lib.nyash +++ /dev/null @@ -1,33 +0,0 @@ -// Mini-VM library (function-based) with a tiny JSON extractor -// Safe MVP: no real JSON parsing; string scan for first int literal only - -static box MiniVm { - _is_digit(ch) { return ch == "0" || ch == "1" || ch == "2" || ch == "3" || ch == "4" || ch == "5" || ch == "6" || ch == "7" || ch == "8" || ch == "9" } - - // Read consecutive digits starting at pos - read_digits(json, pos) { - @out = "" - loop (true) { - @s = json.substring(pos, pos+1) - if s == "" { break } - if _is_digit(s) { out = out + s pos = pos + 1 } else { break } - } - return out - } - - // Extract the first integer literal from our AST JSON v0 subset - parse_first_int(json) { - @key = "\"value\":{\"type\":\"int\",\"value\":" - @idx = json.lastIndexOf(key) - if idx < 0 { return "0" } - @start = idx + key.length() - return read_digits(json, start) - } - - // Execute a minimal program: print the extracted integer and exit code 0 - run(json) { - @n = parse_first_int(json) - print(n) - return 0 - } -} diff --git a/apps/selfhost/vm/mir_min_entry.nyash b/apps/selfhost/vm/mir_min_entry.nyash deleted file mode 100644 index c9a149b6..00000000 --- a/apps/selfhost/vm/mir_min_entry.nyash +++ /dev/null @@ -1,15 +0,0 @@ -// mir_min_entry.nyash — MirVmMin の薄いエントリ -// 引数があれば JSON を第1引数から受け取る。無ければデフォルトの const→ret (42)。 - -using selfhost.vm.mir_min as MirVmMin - -static box Main { - main(args) { - // 既定の最小 MIR(JSON v0) - local json = "{\"functions\":[{\"name\":\"main\",\"params\":[],\"blocks\":[{\"id\":0,\"instructions\":[{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":42}},{\"op\":\"ret\",\"value\":1}]}]}]}" - if args != null { if args.size() > 0 { local s = args.get(0) if s != null { json = s } } } - local v = MirVmMin._run_min(json) - print(MirVmMin._int_to_str(v)) - return 0 - } -} diff --git a/apps/selfhost/vm/run_core_wrapper.nyash b/apps/selfhost/vm/run_core_wrapper.nyash deleted file mode 100644 index 3169e10a..00000000 --- a/apps/selfhost/vm/run_core_wrapper.nyash +++ /dev/null @@ -1,16 +0,0 @@ -using selfhost.vm.core as MiniVm - -static box Main { - main(args) { - @json = "{\"kind\":\"Program\",\"statements\":[{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":42}}}]}" - if args { if args.size() > 0 { @s = args.get(0) if s { json = s } } } - print("pre") - print(json.length()) - print(json.indexOf("\"kind\":\"Program\"")) - print(json.indexOf("\"kind\":\"Print\"")) - print(json.indexOf("\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\"")) - @code = new MiniVm().run(json) - print("post") - return code - } -}