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

1509 lines
56 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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)
}