selfhost(pyvm): MiniVmPrints – prefer JSON route early-return (ok==1) to avoid fallback loops; keep default behavior unchanged elsewhere
This commit is contained in:
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,201 +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 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 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))
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,173 +0,0 @@
|
||||
// Mini-VM scanning and numeric helpers
|
||||
static box MiniVmScan {
|
||||
// helper: find needle from position pos
|
||||
index_of_from(hay, needle, pos) {
|
||||
local tail = hay.substring(pos, hay.length())
|
||||
local rel = tail.indexOf(needle)
|
||||
if rel < 0 { return -1 } else { return pos + rel }
|
||||
}
|
||||
|
||||
// helper: find balanced bracket range [ ... ] starting at idx (points to '[')
|
||||
find_balanced_array_end(json, idx) {
|
||||
local n = json.length()
|
||||
if json.substring(idx, idx+1) != "[" { return -1 }
|
||||
local depth = 0
|
||||
local i = idx
|
||||
loop (i < n) {
|
||||
local ch = json.substring(i, i+1)
|
||||
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) {
|
||||
local n = json.length()
|
||||
if json.substring(idx, idx+1) != "{" { return -1 }
|
||||
local depth = 0
|
||||
local i = idx
|
||||
loop (i < n) {
|
||||
local ch = json.substring(i, i+1)
|
||||
if ch == "{" { depth = depth + 1 }
|
||||
if ch == "}" {
|
||||
depth = depth - 1
|
||||
if depth == 0 { return i }
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
_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
|
||||
}
|
||||
_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" }
|
||||
local v = n
|
||||
local out = ""
|
||||
loop (v > 0) {
|
||||
local d = v % 10
|
||||
local ch = _digit_char(d)
|
||||
out = ch + out
|
||||
v = v / 10
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Read digit runs starting at pos
|
||||
read_digits(json, pos) {
|
||||
local out = ""
|
||||
loop (true) {
|
||||
local 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) {
|
||||
local i = 0
|
||||
local n = json.length()
|
||||
local total = 0
|
||||
loop (i < n) {
|
||||
local ch = json.substring(i, i+1)
|
||||
if ch == "\"" {
|
||||
local j = index_of_from(json, "\"", i+1)
|
||||
if j < 0 { break }
|
||||
i = j + 1
|
||||
continue
|
||||
}
|
||||
local 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) {
|
||||
local i = 0
|
||||
local n = json.length()
|
||||
local total = 0
|
||||
loop (i < n) {
|
||||
local 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) {
|
||||
local i = 0
|
||||
local n = json.length()
|
||||
local total = 0
|
||||
local found = 0
|
||||
loop (i < n) {
|
||||
local ch = json.substring(i, i+1)
|
||||
if ch == "\"" {
|
||||
local j = index_of_from(json, "\"", i+1)
|
||||
if j < 0 { break }
|
||||
i = j + 1
|
||||
continue
|
||||
}
|
||||
local 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 ""
|
||||
}
|
||||
}
|
||||
|
||||
249
apps/selfhost-vm/boxes/seam_inspector.nyash
Normal file
249
apps/selfhost-vm/boxes/seam_inspector.nyash
Normal file
@ -0,0 +1,249 @@
|
||||
// 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: <spaces> 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)
|
||||
}
|
||||
}
|
||||
59
apps/selfhost-vm/collect_empty_args_smoke.nyash
Normal file
59
apps/selfhost-vm/collect_empty_args_smoke.nyash
Normal file
@ -0,0 +1,59 @@
|
||||
// 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
|
||||
}
|
||||
}
|
||||
15
apps/selfhost-vm/collect_empty_args_using_smoke.nyash
Normal file
15
apps/selfhost-vm/collect_empty_args_using_smoke.nyash
Normal file
@ -0,0 +1,15 @@
|
||||
using selfhost.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)
|
||||
local i = 0
|
||||
loop (i < arr.size()) { print(arr.get(i)) i = i + 1 }
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
30
apps/selfhost-vm/collect_literal_eval.nyash
Normal file
30
apps/selfhost-vm/collect_literal_eval.nyash
Normal file
@ -0,0 +1,30 @@
|
||||
// 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
|
||||
}
|
||||
}
|
||||
282
apps/selfhost-vm/collect_mixed_smoke.nyash
Normal file
282
apps/selfhost-vm/collect_mixed_smoke.nyash
Normal file
@ -0,0 +1,282 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
18
apps/selfhost-vm/collect_prints_loader_smoke.nyash
Normal file
18
apps/selfhost-vm/collect_prints_loader_smoke.nyash
Normal file
@ -0,0 +1,18 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -1,309 +1,12 @@
|
||||
// Mini-VM: function-based entry using library
|
||||
|
||||
using selfhost.vm.json_cur as MiniJsonCur
|
||||
using selfhost.vm.json as MiniJson
|
||||
// Thin entry: delegate to core MiniVm
|
||||
// Using is pre-inlined by runner; keep entry minimal for maintainability.
|
||||
using selfhost.vm.core as MiniVm
|
||||
// Local static box (duplicated from mini_vm_lib for now to avoid include gate issues)
|
||||
// Program entry: prefer argv[0] JSON, fallback to embedded sample
|
||||
|
||||
static box Main {
|
||||
// Small helpers for quick JSON scans (avoid cross-box deps)
|
||||
index_of_from(hay, needle, pos) {
|
||||
local tail = hay.substring(pos, hay.length())
|
||||
local rel = tail.indexOf(needle)
|
||||
if rel < 0 { return -1 } else { 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
|
||||
}
|
||||
_digit_value(ch) {
|
||||
if ch == "0" { return 0 }
|
||||
if ch == "1" { return 1 }
|
||||
if ch == "2" { return 2 }
|
||||
if ch == "3" { return 3 }
|
||||
if ch == "4" { return 4 }
|
||||
if ch == "5" { return 5 }
|
||||
if ch == "6" { return 6 }
|
||||
if ch == "7" { return 7 }
|
||||
if ch == "8" { return 8 }
|
||||
if ch == "9" { return 9 }
|
||||
return 0
|
||||
}
|
||||
_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
|
||||
}
|
||||
main(args) {
|
||||
local json = "{\"kind\":\"Program\",\"statements\":[{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":42}}}]}"
|
||||
// If args provided, use the first as JSON source (guard None)
|
||||
if args {
|
||||
if args.size() > 0 {
|
||||
local s = args.get(0)
|
||||
if s { json = s }
|
||||
}
|
||||
}
|
||||
// Top-level fast paths for simple Print cases (Literal/FunctionCall/Compare/BinaryOp)
|
||||
// 0) If(literal int) then/else branch (string prints)
|
||||
if json.indexOf("\"If\"") >= 0 {
|
||||
local kc = "\"condition\""
|
||||
local pc = json.indexOf(kc)
|
||||
if pc >= 0 {
|
||||
local kv = "\"type\":\"int\",\"value\":"
|
||||
local pv = json.indexOf(kv, pc)
|
||||
if pv >= 0 {
|
||||
local vi = pv + kv.length()
|
||||
local ve = json.indexOf("}", vi)
|
||||
if ve >= 0 {
|
||||
local cond_str = json.substring(vi, ve)
|
||||
// parse int
|
||||
local a = 0
|
||||
local i = 0
|
||||
loop (i < cond_str.length()) {
|
||||
local ch = cond_str.substring(i, i+1)
|
||||
if ch == "0" { a = a*10 i = i + 1 continue }
|
||||
if ch == "1" { a = a*10+1 i = i + 1 continue }
|
||||
if ch == "2" { a = a*10+2 i = i + 1 continue }
|
||||
if ch == "3" { a = a*10+3 i = i + 1 continue }
|
||||
if ch == "4" { a = a*10+4 i = i + 1 continue }
|
||||
if ch == "5" { a = a*10+5 i = i + 1 continue }
|
||||
if ch == "6" { a = a*10+6 i = i + 1 continue }
|
||||
if ch == "7" { a = a*10+7 i = i + 1 continue }
|
||||
if ch == "8" { a = a*10+8 i = i + 1 continue }
|
||||
if ch == "9" { a = a*10+9 i = i + 1 continue }
|
||||
break
|
||||
}
|
||||
local truthy = 0
|
||||
if a != 0 { truthy = 1 }
|
||||
local bkey = "\"then_body\""
|
||||
if truthy == 0 { bkey = "\"else_body\"" }
|
||||
local pb = json.indexOf(bkey, ve)
|
||||
if pb >= 0 {
|
||||
// search first string literal value inside the chosen body
|
||||
local ts = "\"type\":\"string\",\"value\":\""
|
||||
local ps = json.indexOf(ts, pb)
|
||||
if ps >= 0 {
|
||||
local si = ps + ts.length()
|
||||
local sj = json.indexOf("\"", si)
|
||||
if sj >= 0 { print(json.substring(si, sj)) return 0 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 1) Print(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 }
|
||||
}
|
||||
}
|
||||
// 2) Print(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()
|
||||
// take until next non-digit or closing brace
|
||||
local ie = json.indexOf("}", ii)
|
||||
if ie < 0 { ie = ii }
|
||||
local d = json.substring(ii, ie)
|
||||
print(d)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
// 3) Print(FunctionCall) minimal (echo/itoa)
|
||||
if json.indexOf("\"FunctionCall\"") >= 0 {
|
||||
local pos = 0
|
||||
loop (true) {
|
||||
local kfc = "\"kind\":\"FunctionCall\""
|
||||
local fcp = json.indexOf(kfc, pos)
|
||||
if fcp < 0 { break }
|
||||
local kn = "\"name\":\""
|
||||
local pn = json.indexOf(kn, fcp)
|
||||
if pn < 0 { break }
|
||||
local ni = pn + kn.length()
|
||||
local nj = json.indexOf("\"", ni)
|
||||
if nj < 0 { break }
|
||||
local fname = json.substring(ni, nj)
|
||||
local ka = "\"arguments\":["
|
||||
local pa = json.indexOf(ka, nj)
|
||||
if pa < 0 { pos = nj + 1 continue }
|
||||
// string arg
|
||||
local ts = "\"type\":\"string\",\"value\":\""
|
||||
local ti = json.indexOf(ts, pa)
|
||||
if ti >= 0 {
|
||||
local si = ti + ts.length()
|
||||
local sj = json.indexOf("\"", si)
|
||||
if sj >= 0 {
|
||||
local sval = json.substring(si, sj)
|
||||
if fname == "echo" { print(sval) }
|
||||
pos = sj + 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
// int arg
|
||||
local ti2 = json.indexOf("\"type\":\"int\",\"value\":", pa)
|
||||
if ti2 >= 0 {
|
||||
local vi = ti2 + "\"type\":\"int\",\"value\":".length()
|
||||
local ve = json.indexOf("}", vi)
|
||||
if ve < 0 { ve = vi }
|
||||
local ival = json.substring(vi, ve)
|
||||
if fname == "itoa" || fname == "echo" { print(ival) }
|
||||
pos = ve + 1
|
||||
continue
|
||||
}
|
||||
pos = pn + 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
// 4) Print(Compare) minimal
|
||||
if json.indexOf("\"Compare\"") >= 0 {
|
||||
local ko = "\"operation\":\""
|
||||
local po = json.indexOf(ko)
|
||||
if po >= 0 {
|
||||
local oi = po + ko.length()
|
||||
local oj = json.indexOf("\"", oi)
|
||||
if oj >= 0 {
|
||||
local op = json.substring(oi, oj)
|
||||
local kv = "\"value\":\""
|
||||
// lhs int
|
||||
local kl = "\"lhs\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
|
||||
local pl = json.indexOf(kl, oj)
|
||||
if pl >= 0 {
|
||||
local li = pl + kl.length()
|
||||
local le = json.indexOf("}", li)
|
||||
if le >= 0 {
|
||||
local la = json.substring(li, le)
|
||||
// rhs int
|
||||
local kr = "\"rhs\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
|
||||
local pr = json.indexOf(kr, le)
|
||||
if pr >= 0 {
|
||||
local ri = pr + kr.length()
|
||||
local re = json.indexOf("}", ri)
|
||||
if re >= 0 {
|
||||
local rb = json.substring(ri, re)
|
||||
// compute
|
||||
local a = 0
|
||||
local i = 0
|
||||
loop (i < la.length()) { local ch = la.substring(i, i+1) if ch == "0" { a = a*10+0 i=i+1 continue } if ch == "1" { a=a*10+1 i=i+1 continue } if ch == "2" { a=a*10+2 i=i+1 continue } if ch == "3" { a=a*10+3 i=i+1 continue } if ch == "4" { a=a*10+4 i=i+1 continue } if ch == "5" { a=a*10+5 i=i+1 continue } if ch == "6" { a=a*10+6 i=i+1 continue } if ch == "7" { a=a*10+7 i=i+1 continue } if ch == "8" { a=a*10+8 i=i+1 continue } if ch == "9" { a=a*10+9 i=i+1 continue } break }
|
||||
local b = 0
|
||||
local j = 0
|
||||
loop (j < rb.length()) { local ch2 = rb.substring(j, j+1) if ch2 == "0" { b = b*10+0 j=j+1 continue } if ch2 == "1" { b=b*10+1 j=j+1 continue } if ch2 == "2" { b=b*10+2 j=j+1 continue } if ch2 == "3" { b=b*10+3 j=j+1 continue } if ch2 == "4" { b=b*10+4 j=j+1 continue } if ch2 == "5" { b=b*10+5 j=j+1 continue } if ch2 == "6" { b=b*10+6 j=j+1 continue } if ch2 == "7" { b=b*10+7 j=j+1 continue } if ch2 == "8" { b=b*10+8 j=j+1 continue } if ch2 == "9" { b=b*10+9 j=j+1 continue } break }
|
||||
local res = 0
|
||||
if op == "<" { if a < b { res = 1 } }
|
||||
if op == "==" { if a == b { res = 1 } }
|
||||
if op == "<=" { if a <= b { res = 1 } }
|
||||
if op == ">" { if a > b { res = 1 } }
|
||||
if op == ">=" { if a >= b { res = 1 } }
|
||||
if op == "!=" { if a != b { res = 1 } }
|
||||
print(res)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 5) BinaryOp(int+int) typed pattern twice and add(保険)
|
||||
if json.indexOf("\"BinaryOp\"") >= 0 && json.indexOf("\"operator\":\"+\"") >= 0 {
|
||||
local pat = "\"type\":\"int\",\"value\":"
|
||||
local p1 = json.indexOf(pat)
|
||||
if p1 >= 0 {
|
||||
// parse first integer by taking until next closing brace
|
||||
local i = p1 + pat.length()
|
||||
local end1 = json.indexOf("}", i)
|
||||
if end1 < 0 { end1 = i }
|
||||
local a_str = json.substring(i, end1)
|
||||
// convert a_str to int
|
||||
local a = 0
|
||||
local k = 0
|
||||
loop (k < a_str.length()) {
|
||||
local ch = a_str.substring(k, k+1)
|
||||
if ch == "0" { a = a * 10 + 0 k = k + 1 continue }
|
||||
if ch == "1" { a = a * 10 + 1 k = k + 1 continue }
|
||||
if ch == "2" { a = a * 10 + 2 k = k + 1 continue }
|
||||
if ch == "3" { a = a * 10 + 3 k = k + 1 continue }
|
||||
if ch == "4" { a = a * 10 + 4 k = k + 1 continue }
|
||||
if ch == "5" { a = a * 10 + 5 k = k + 1 continue }
|
||||
if ch == "6" { a = a * 10 + 6 k = k + 1 continue }
|
||||
if ch == "7" { a = a * 10 + 7 k = k + 1 continue }
|
||||
if ch == "8" { a = a * 10 + 8 k = k + 1 continue }
|
||||
if ch == "9" { a = a * 10 + 9 k = k + 1 continue }
|
||||
break
|
||||
}
|
||||
// parse second integer
|
||||
local p2 = json.lastIndexOf(pat)
|
||||
if p2 >= 0 && p2 != p1 {
|
||||
local j = p2 + pat.length()
|
||||
local end2 = json.indexOf("}", j)
|
||||
if end2 < 0 { end2 = j }
|
||||
local b_str = json.substring(j, end2)
|
||||
local b = 0
|
||||
local m = 0
|
||||
loop (m < b_str.length()) {
|
||||
local ch2 = b_str.substring(m, m+1)
|
||||
if ch2 == "0" { b = b * 10 + 0 m = m + 1 continue }
|
||||
if ch2 == "1" { b = b * 10 + 1 m = m + 1 continue }
|
||||
if ch2 == "2" { b = b * 10 + 2 m = m + 1 continue }
|
||||
if ch2 == "3" { b = b * 10 + 3 m = m + 1 continue }
|
||||
if ch2 == "4" { b = b * 10 + 4 m = m + 1 continue }
|
||||
if ch2 == "5" { b = b * 10 + 5 m = m + 1 continue }
|
||||
if ch2 == "6" { b = b * 10 + 6 m = m + 1 continue }
|
||||
if ch2 == "7" { b = b * 10 + 7 m = m + 1 continue }
|
||||
if ch2 == "8" { b = b * 10 + 8 m = m + 1 continue }
|
||||
if ch2 == "9" { b = b * 10 + 9 m = m + 1 continue }
|
||||
break
|
||||
}
|
||||
print(a + b)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fallback to full MiniVm runner
|
||||
local vm = new MiniVm()
|
||||
return vm.run(json)
|
||||
@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)
|
||||
}
|
||||
}
|
||||
|
||||
// Top-level fallback entry for current runner
|
||||
function main(args) {
|
||||
local json = "{\"kind\":\"Program\",\"statements\":[{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":42}}}]}"
|
||||
if args {
|
||||
if args.size() > 0 {
|
||||
local s = args.get(0)
|
||||
if s { json = s }
|
||||
}
|
||||
}
|
||||
local vm = new MiniVm()
|
||||
return vm.run(json)
|
||||
}
|
||||
|
||||
@ -3,23 +3,23 @@
|
||||
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) {
|
||||
local out = ""
|
||||
@out = ""
|
||||
loop (true) {
|
||||
local s = json.substring(pos, pos+1)
|
||||
@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) {
|
||||
local key = "\"value\":{\"type\":\"int\",\"value\":"
|
||||
local idx = json.lastIndexOf(key)
|
||||
@key = "\"value\":{\"type\":\"int\",\"value\":"
|
||||
@idx = json.lastIndexOf(key)
|
||||
if idx < 0 { return "0" }
|
||||
local start = idx + key.length()
|
||||
@start = idx + key.length()
|
||||
return read_digits(json, start)
|
||||
}
|
||||
run_branch(json) {
|
||||
local n = parse_first_int(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
|
||||
@ -29,12 +29,12 @@ static box MiniVm {
|
||||
// Program entry: embedded JSON (value=1 → print 10; else → 20)
|
||||
static box Main {
|
||||
main(args) {
|
||||
local vm = new MiniVm()
|
||||
local json = "{\"kind\":\"Program\",\"statements\":[{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":1}}}]}"
|
||||
@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 {
|
||||
local s = args.get(0)
|
||||
@s = args.get(0)
|
||||
if s { json = s }
|
||||
}
|
||||
}
|
||||
@ -44,15 +44,15 @@ static box Main {
|
||||
|
||||
// Top-level fallback entry for current runner
|
||||
function main(args) {
|
||||
local vm = new MiniVm()
|
||||
local json = "{\"kind\":\"Program\",\"statements\":[{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":1}}}]}"
|
||||
@vm = new MiniVm()
|
||||
@json = "{\"kind\":\"Program\",\"statements\":[{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":1}}}]}"
|
||||
if args {
|
||||
if args.size() > 0 {
|
||||
local s = args.get(0)
|
||||
@s = args.get(0)
|
||||
if s { json = s }
|
||||
}
|
||||
}
|
||||
local n = vm.parse_first_int(json)
|
||||
@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
|
||||
|
||||
@ -6,9 +6,9 @@ static box MiniVm {
|
||||
|
||||
// Read consecutive digits starting at pos
|
||||
read_digits(json, pos) {
|
||||
local out = ""
|
||||
@out = ""
|
||||
loop (true) {
|
||||
local s = json.substring(pos, pos+1)
|
||||
@s = json.substring(pos, pos+1)
|
||||
if s == "" { break }
|
||||
if _is_digit(s) { out = out + s pos = pos + 1 } else { break }
|
||||
}
|
||||
@ -17,16 +17,16 @@ static box MiniVm {
|
||||
|
||||
// Extract the first integer literal from our AST JSON v0 subset
|
||||
parse_first_int(json) {
|
||||
local key = "\"value\":{\"type\":\"int\",\"value\":"
|
||||
local idx = json.lastIndexOf(key)
|
||||
@key = "\"value\":{\"type\":\"int\",\"value\":"
|
||||
@idx = json.lastIndexOf(key)
|
||||
if idx < 0 { return "0" }
|
||||
local start = idx + key.length()
|
||||
@start = idx + key.length()
|
||||
return read_digits(json, start)
|
||||
}
|
||||
|
||||
// Execute a minimal program: print the extracted integer and exit code 0
|
||||
run(json) {
|
||||
local n = parse_first_int(json)
|
||||
@n = parse_first_int(json)
|
||||
print(n)
|
||||
return 0
|
||||
}
|
||||
|
||||
16
apps/selfhost-vm/run_core_wrapper.nyash
Normal file
16
apps/selfhost-vm/run_core_wrapper.nyash
Normal file
@ -0,0 +1,16 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user