Files
hakorune/apps/selfhost-vm/mini_vm.nyash

1509 lines
56 KiB
Plaintext
Raw Normal View History

// Mini-VM: function-based entry using library
// Minimal JSON cursor helpers (developer preview)
// Note: naive and partial; sufficient for Mini-VM MVP patterns.
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
}
}
// Adapter for JSON cursor operations. In StageB we centralize calls here
// so we can later delegate to libs (`apps/libs/json_cur.nyash`) without
// touching call sites. For now it wraps the local 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)
}
}
// Local static box (duplicated from mini_vm_lib for now to avoid include gate issues)
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
}
_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
// use MiniJson adapter inline
local n = s.length()
local acc = 0
loop (i < n) {
local ch = s.substring(i, i+1)
// inline digit decode to avoid same-box method dispatch
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_digits(json, pos) {
local out = ""
loop (true) {
local s = json.substring(pos, pos+1)
if s == "" { break }
// inline digit check to avoid same-box method dispatch
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
}
// Read a JSON string starting at position pos (at opening quote); returns the decoded string
read_json_string(json, pos) {
// Expect opening quote
local i = pos
local out = ""
local n = json.length()
if json.substring(i, i+1) == "\"" { i = i + 1 } else { return "" }
loop (i < n) {
local ch = json.substring(i, i+1)
if ch == "\"" { i = i + 1 break }
if ch == "\\" {
// handle simple escapes for \ and "
local nx = json.substring(i+1, i+2)
if nx == "\"" { out = out + "\"" i = i + 2 continue }
if nx == "\\" { out = out + "\\" i = i + 2 continue }
// Unknown escape: skip backslash and take next as-is
i = i + 1
continue
}
out = out + ch
i = i + 1
}
return out
}
// 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: next non-whitespace character index from pos
next_non_ws(json, pos) {
local i = pos
local n = json.length()
loop (i < n) {
local ch = json.substring(i, i+1)
if ch != " " && ch != "\n" && ch != "\r" && ch != "\t" { return i }
i = i + 1
}
return -1
}
// ——— Helpers (as box methods) ———
try_print_string_value_at(json, end, print_pos) {
local k_val = "\"value\":\""
local s = index_of_from(json, k_val, print_pos)
if s < 0 || s >= end { return -1 }
local i = s + k_val.length()
local j = index_of_from(json, "\"", i)
if j <= 0 || j > end { return -1 }
print(json.substring(i, j))
return j + 1
}
try_print_int_value_at(json, end, print_pos) {
// Bind to this Print's expression object and require kind==Literal
local k_expr = "\"expression\":{"
local epos = index_of_from(json, k_expr, print_pos)
if epos <= 0 || epos >= end { return -1 }
local obj_start = index_of_from(json, "{", epos)
if obj_start <= 0 || obj_start >= end { return -1 }
local obj_end = find_balanced_object_end(json, obj_start)
if obj_end <= 0 || obj_end > end { return -1 }
local k_kind = "\"kind\":\"Literal\""
local kpos = index_of_from(json, k_kind, obj_start)
if kpos <= 0 || kpos >= obj_end { return -1 }
local k_type = "\"type\":\""
local tpos = index_of_from(json, k_type, kpos)
if tpos <= 0 || tpos >= obj_end { return -1 }
tpos = tpos + k_type.length()
local t_end = index_of_from(json, "\"", tpos)
if t_end <= 0 || t_end > obj_end { return -1 }
local ty = json.substring(tpos, t_end)
if (ty != "int" && ty != "i64" && ty != "integer") { return -1 }
local k_val2 = "\"value\":"
local v2 = index_of_from(json, k_val2, t_end)
if v2 <= 0 || v2 >= obj_end { return -1 }
local digits = read_digits(json, v2 + k_val2.length())
if digits == "" { return -1 }
print(digits)
return obj_end + 1
}
try_print_functioncall_at(json, end, print_pos) {
local k_fc = "\"kind\":\"FunctionCall\""
local fcp = index_of_from(json, k_fc, print_pos)
if fcp <= 0 || fcp >= end { return -1 }
// name
local k_name = "\"name\":\""
local npos = index_of_from(json, k_name, fcp)
if npos <= 0 || npos >= end { return -1 }
local ni = npos + k_name.length()
local nj = index_of_from(json, "\"", ni)
if nj <= 0 || nj > end { return -1 }
local fname = json.substring(ni, nj)
// args
local k_args = "\"arguments\":["
local apos = index_of_from(json, k_args, nj)
if apos <= 0 || apos >= end { return -1 }
local arr_start = index_of_from(json, "[", apos)
local arr_end = find_balanced_array_end(json, arr_start)
if arr_start <= 0 || arr_end <= 0 || arr_end > end { return -1 }
// handle empty args []
local nn = 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 = 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 = 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 = index_of_from(json, k_sval, at_end)
if svalp <= 0 || svalp >= arr_end { return -1 }
local si = svalp + k_sval.length()
local sj = 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 = index_of_from(json, k_ival, at_end)
if ivalp <= 0 || ivalp >= arr_end { return -1 }
local digits = read_digits(json, ivalp + k_ival.length())
if fname == "itoa" || fname == "echo" { print(digits) return ivalp + k_ival.length() }
return -1
}
return -1
}
// Minimal: Print(BinaryOp) with operator "+"; supports string+string and int+int
try_print_binop_at(json, end, print_pos) {
local k_bo = "\"kind\":\"BinaryOp\""
local bpos = index_of_from(json, k_bo, print_pos)
if bpos <= 0 || bpos >= end { return -1 }
// bound this BinaryOp object by matching braces
// Prefer the enclosing expression object: "expression":{ ... BinaryOp ... }
local k_expr = "\"expression\":{"
local expr_pos = index_of_from(json, k_expr, print_pos)
local obj_start = -1
if expr_pos > 0 && expr_pos < end {
obj_start = index_of_from(json, "{", expr_pos)
} else {
// fallback to the next '{' after kind, may be left-object; acceptable but less robust
obj_start = index_of_from(json, "{", bpos)
}
local obj_end = find_balanced_object_end(json, obj_start)
if obj_start <= 0 || obj_end <= 0 || obj_end > end { return -1 }
// operator
local k_op = "\"operator\":\"+\""
local opos = index_of_from(json, k_op, bpos)
if opos <= 0 || opos >= obj_end { return -1 }
// string + string パターン(カーソル+単純キー走査)
local cur = new MiniJsonCur()
local k_left_lit = "\"left\":{\"kind\":\"Literal\""
local lhdr = index_of_from(json, k_left_lit, opos)
if lhdr > 0 && lhdr < obj_end {
// find left value string
local k_sval = "\"value\":\""
local lvp = 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 {
// find right literal header then value
local k_right_lit = "\"right\":{\"kind\":\"Literal\""
local rhdr = index_of_from(json, k_right_lit, li + lval.length())
if rhdr > 0 && rhdr < obj_end {
local rvp = 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 パターンMiniJson を用いて value 数字を抽出)
// left literal value
local k_l = "\"left\":{\"kind\":\"Literal\""
local lpos = index_of_from(json, k_l, opos)
if lpos <= 0 || lpos >= obj_end { return -1 }
// typed fast-path within object bounds
local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
local li2 = index_of_from(json, k_lint, opos)
if li2 <= 0 || li2 >= obj_end { return -1 }
local ldigits = read_digits(json, li2 + k_lint.length())
if ldigits == "" { return -1 }
// right literal value
local k_r = "\"right\":{\"kind\":\"Literal\""
local rpos = 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 = index_of_from(json, k_rint, lpos)
if ri2 <= 0 || ri2 >= obj_end { return -1 }
local rdigits = read_digits(json, ri2 + k_rint.length())
if rdigits == "" { return -1 }
// sum
local ai = _str_to_int(ldigits)
local bi = _str_to_int(rdigits)
print(_int_to_str(ai + bi))
return obj_end + 1
// fallback: scan two numeric values inside BinaryOp object
local k_v2 = "\"value\":"
local p1 = index_of_from(json, k_v2, obj_start)
if p1 > 0 && p1 < obj_end {
local cur2 = new MiniJsonCur()
local d1 = cur2.read_digits_from(json, p1 + k_v2.length())
if d1 {
local p2 = index_of_from(json, k_v2, p1 + k_v2.length())
if p2 > 0 && p2 < obj_end {
local d2 = cur2.read_digits_from(json, p2 + k_v2.length())
if d2 {
print(_int_to_str(_str_to_int(d1) + _str_to_int(d2)))
return obj_end + 1
}
}
}
}
}
// Greedy fallback: detect BinaryOp int+int by pattern regardless of field order nuances
try_print_binop_int_greedy(json, end, print_pos) {
// disabled for now (was causing false positives)
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) {
// Bind expression object { ... }
local k_expr = "\"expression\":{"
local expr_pos = index_of_from(json, k_expr, print_pos)
if expr_pos <= 0 || expr_pos >= end { return -1 }
local obj_start = index_of_from(json, "{", expr_pos)
if obj_start <= 0 || obj_start >= end { return -1 }
local obj_end = find_balanced_object_end(json, obj_start)
if obj_end <= 0 || obj_end > end { return -1 }
// Must be BinaryOp '+' inside this expression
local k_bo = "\"kind\":\"BinaryOp\""
local bpos = index_of_from(json, k_bo, obj_start)
if bpos <= 0 || bpos >= obj_end { return -1 }
local k_plus = "\"operator\":\"+\""
local opos = index_of_from(json, k_plus, bpos)
if opos <= 0 || opos >= obj_end { return -1 }
// Within [obj_start, obj_end], collect all integer literals and sum the last two
local nums = []
local i = obj_start
loop (i < obj_end) {
// skip strings
if json.substring(i, i+1) == "\"" {
local j = index_of_from(json, "\"", i+1)
if j < 0 || j >= obj_end { break }
i = j + 1
continue
}
// digits
local d = 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 = _str_to_int(nums.get(nsz-2))
local b = _str_to_int(nums.get(nsz-1))
print(_int_to_str(a + b))
return obj_end + 1
}
// 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(json, end, print_pos) {
// Bind expression object { ... }
local k_expr = "\"expression\":{"
local expr_pos = index_of_from(json, k_expr, print_pos)
if expr_pos <= 0 || expr_pos >= end { return -1 }
local obj_start = index_of_from(json, "{", expr_pos)
if obj_start <= 0 || obj_start >= end { return -1 }
local obj_end = find_balanced_object_end(json, obj_start)
if obj_end <= 0 || obj_end > end { return -1 }
// Ensure BinaryOp '+'
local k_bo = "\"kind\":\"BinaryOp\""
local bpos = index_of_from(json, k_bo, obj_start)
if bpos <= 0 || bpos >= obj_end { return -1 }
local k_plus = "\"operator\":\"+\""
local opos = index_of_from(json, k_plus, bpos)
if opos <= 0 || opos >= obj_end { return -1 }
// Collect two integer values exactly from successive 'value' fields within bounds
local cur = new MiniJsonCur()
local k_v = "\"value\":"
local found = 0
local a = 0
local pos = index_of_from(json, k_v, obj_start)
loop (pos > 0 && pos < obj_end) {
// attempt to read digits right after '"value":'
local di = cur.read_digits_from(json, pos + k_v.length())
if di != "" {
if found == 0 { a = _str_to_int(di) found = 1 } else {
local b = _str_to_int(di)
print(_int_to_str(a + b))
return obj_end + 1
}
}
// advance to next 'value' key within object bounds
pos = index_of_from(json, k_v, pos + k_v.length())
if pos <= 0 || pos >= obj_end { break }
}
return -1
}
// 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(json) {
local k_bo = "\"kind\":\"BinaryOp\""
local bpos = json.indexOf(k_bo)
if bpos < 0 { return -1 }
local k_plus = "\"operator\":\"+\""
local opos = index_of_from(json, k_plus, bpos)
if opos < 0 { return -1 }
local k_v = "\"value\":"
// We know the structure around operator '+':
// left: { ... value: { type:int, value: <L> } }, right: { ... value: { type:int, value: <R> } }
// So the 2nd 'value' after operator is <L>, and the 4th is <R>.
local p = opos
local i = 0
// 1st value key (object)
p = index_of_from(json, k_v, p)
if p < 0 { return -1 }
i = i + 1
// 2nd value key (digits for left)
p = index_of_from(json, k_v, p + k_v.length())
if p < 0 { return -1 }
i = i + 1
local end1 = index_of_from(json, "}", p)
if end1 < 0 { return -1 }
local d1 = json.substring(p + k_v.length(), end1)
// 3rd value key (object in right)
p = index_of_from(json, k_v, p + k_v.length())
if p < 0 { return -1 }
i = i + 1
// 4th value key (digits for right)
p = index_of_from(json, k_v, p + k_v.length())
if p < 0 { return -1 }
i = i + 1
local end2 = index_of_from(json, "}", p)
if end2 < 0 { return -1 }
local d2 = json.substring(p + k_v.length(), end2)
// Print as integer to avoid relying on string concatenation
print(_str_to_int(d1) + _str_to_int(d2))
return end2 + 1
}
// 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(json, end, print_pos) {
local k_cp = "\"kind\":\"Compare\""
local cpos = index_of_from(json, k_cp, print_pos)
if cpos <= 0 || cpos >= end { return -1 }
local k_op = "\"operation\":\""
local opos = index_of_from(json, k_op, cpos)
if opos <= 0 || opos >= end {
// fallback key name
k_op = "\"operator\":\""
opos = index_of_from(json, k_op, cpos)
if opos <= 0 || opos >= end { return -1 }
}
local oi = opos + k_op.length()
local oj = index_of_from(json, "\"", oi)
if oj <= 0 || oj > end { return -1 }
local op = json.substring(oi, oj)
// Robust numeric lhs/rhs using cursor digits after value key
local cur = new MiniJsonCur()
// lhs
local k_lhs = "\"lhs\":{\"kind\":\"Literal\""
local hl = index_of_from(json, k_lhs, oj)
if hl <= 0 || hl >= end { return -1 }
local k_v = "\"value\":"
local hv = index_of_from(json, k_v, hl)
if hv <= 0 || hv >= end { return -1 }
local a = cur.read_digits_from(json, hv + k_v.length())
if a == "" { return -1 }
// rhs
local k_rhs = "\"rhs\":{\"kind\":\"Literal\""
local hr = index_of_from(json, k_rhs, hl)
if hr <= 0 || hr >= end { return -1 }
local rv = index_of_from(json, k_v, hr)
if rv <= 0 || rv >= end { return -1 }
local b = cur.read_digits_from(json, rv + k_v.length())
if b == "" { return -1 }
// Strict compare for <, ==, <=, >, >=, !=
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 rv + k_v.length()
}
// 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 directly
local digits = read_digits(json, vpos)
return digits
}
if ty == "string" {
// Find opening and closing quotes (no escape handling in MVP)
local i = index_of_from(json, "\"", vpos)
if i < 0 { return null }
local j = index_of_from(json, "\"", i+1)
if j < 0 { return null }
return json.substring(i+1, j)
}
// Other types not supported yet
return null
}
// 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
}
// Print all Print-Literal values within [start,end] (inclusive slice indices)
print_prints_in_slice(json, start, end) {
// Main loop with simple guard to avoid pathological hangs
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 = index_of_from(json, k_print, pos)
if p < 0 || p > end { break }
// avoid global digit-sum shortcuts to keep scans bounded and robust
// bound the current Print object to advance correctly
local p_obj_start = index_of_from(json, "{", p)
local p_obj_end = find_balanced_object_end(json, p_obj_start)
if p_obj_start <= 0 || p_obj_end <= 0 { p_obj_end = p + k_print.length() }
// Prefer structured expressions first (avoid matching inner literal fields)
// 1) BinaryOpsum_any → 厳密 → 貪欲intフォールバック
local nextp = try_print_binop_sum_any(json, end, p)
if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue }
nextp = try_print_binop_at(json, end, p)
if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue }
nextp = try_print_binop_int_greedy(json, end, p)
if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue }
nextp = try_print_binop_sum_any(json, end, p)
if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue }
// 2) Compare
nextp = try_print_compare_at(json, end, p)
if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue }
// 3) FunctionCall minimal
nextp = try_print_functioncall_at(json, end, p)
if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue }
// 4) literal string
nextp = 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 = try_print_int_value_at(json, end, p)
if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue }
// Skip if unknown shape
pos = p + k_print.length()
if pos <= p { pos = p + 1 }
}
return printed
}
// Process top-level If with literal condition; print branch prints. Returns printed count.
process_if_once(json) {
local k_if = "\"kind\":\"If\""
local p = index_of_from(json, k_if, 0)
if p < 0 { return 0 }
// condition value (assume int literal truthy)
local k_cond = "\"condition\""
local cpos = index_of_from(json, k_cond, p)
if cpos < 0 { return 0 }
local k_val = "\"value\":"
local vpos = index_of_from(json, k_val, cpos)
if vpos < 0 { return 0 }
local val_digits = read_digits(json, vpos + k_val.length())
local truthy = 0
if val_digits { if val_digits != "0" { truthy = 1 } }
// choose branch key
local k_then = "\"then_body\""
local k_else = "\"else_body\""
local bkey = k_then
if truthy == 0 { bkey = k_else }
local bpos = index_of_from(json, bkey, cpos)
if bpos < 0 { return 0 }
// find array start '[' then end
local arr_start = index_of_from(json, "[", bpos)
if arr_start < 0 { return 0 }
local arr_end = find_balanced_array_end(json, arr_start)
if arr_end < 0 { return 0 }
return 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 print_prints_in_slice(json, 0, json.length())
}
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":<digits>}
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) {
local i = 0
local n = json.length()
local total = 0
loop (i < n) {
local ch = json.substring(i, i+1)
if ch == "\"" {
// skip to next quote
local j = index_of_from(json, "\"", i+1)
if j < 0 { break }
i = j + 1
continue
}
// digits
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 (for simple BinaryOp JSON)
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 if not found
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 == "\"" {
// skip to next quote
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 ""
}
// 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 MiniJsonCur()
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) {
// 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 = 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 = 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 = 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 MiniJsonCur().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 MiniJsonCur().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 = 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 = 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 MiniJsonCur()
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 = 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
}
}
// 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)
}
}
// 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)
}