Files
hakorune/apps/selfhost/common/mini_vm_binop.nyash

278 lines
12 KiB
Plaintext

using selfhost.vm.json as MiniJson
using selfhost.vm.scan as MiniVmScan
static box MiniVmBinOp {
// Minimal: Print(BinaryOp) with operator "+"; supports string+string and int+int
try_print_binop_at(json, end, print_pos) {
local scan = new MiniVmScan()
local k_bo = "\"kind\":\"BinaryOp\""
local bpos = scan.index_of_from(json, k_bo, print_pos)
if bpos <= 0 || bpos >= end { return -1 }
// bound BinaryOp object (prefer expression object)
local k_expr = "\"expression\":{"
local expr_pos = scan.index_of_from(json, k_expr, print_pos)
local obj_start = -1
if expr_pos > 0 && expr_pos < end {
obj_start = scan.index_of_from(json, "{", expr_pos)
} else {
obj_start = scan.index_of_from(json, "{", bpos)
}
local obj_end = scan.find_balanced_object_end(json, obj_start)
if obj_start <= 0 || obj_end <= 0 || obj_end > end { return -1 }
// operator must be '+'
local k_op = "\"operator\":\"+\""
local opos = scan.index_of_from(json, k_op, bpos)
if opos <= 0 || opos >= obj_end { return -1 }
// string + string fast-path
local cur = new MiniJson()
local k_left_lit = "\"left\":{\"kind\":\"Literal\""
local lhdr = scan.index_of_from(json, k_left_lit, opos)
if lhdr > 0 && lhdr < obj_end {
local k_sval = "\"value\":\""
local lvp = scan.index_of_from(json, k_sval, lhdr)
if lvp > 0 && lvp < obj_end {
local li = lvp + k_sval.length()
local lval = cur.read_quoted_from(json, li)
if lval {
local k_right_lit = "\"right\":{\"kind\":\"Literal\""
local rhdr = scan.index_of_from(json, k_right_lit, li + lval.length())
if rhdr > 0 && rhdr < obj_end {
local rvp = scan.index_of_from(json, k_sval, rhdr)
if rvp > 0 && rvp < obj_end {
local ri = rvp + k_sval.length()
local rval = cur.read_quoted_from(json, ri)
if rval { print(lval + rval) return ri + rval.length() + 1 }
}
}
}
}
}
// int + int typed pattern
local k_l = "\"left\":{\"kind\":\"Literal\""
local lpos = scan.index_of_from(json, k_l, opos)
if lpos <= 0 || lpos >= obj_end { return -1 }
local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
local li2 = scan.index_of_from(json, k_lint, opos)
if li2 <= 0 || li2 >= obj_end { return -1 }
local ldigits = scan.read_digits(json, li2 + k_lint.length())
if ldigits == "" { return -1 }
local k_r = "\"right\":{\"kind\":\"Literal\""
local rpos = scan.index_of_from(json, k_r, lpos)
if rpos <= 0 || rpos >= obj_end { return -1 }
local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
local ri2 = scan.index_of_from(json, k_rint, lpos)
if ri2 <= 0 || ri2 >= obj_end { return -1 }
local rdigits = scan.read_digits(json, ri2 + k_rint.length())
if rdigits == "" { return -1 }
local ai = scan._str_to_int(ldigits)
local bi = scan._str_to_int(rdigits)
print(scan._int_to_str(ai + bi))
return obj_end + 1
}
// Greedy disabled (kept for parity)
try_print_binop_int_greedy(json, end, print_pos) { return -1 }
// Fallback: within the current Print's expression BinaryOp object, scan for two numeric values and sum
try_print_binop_sum_any(json, end, print_pos) {
local scan = new MiniVmScan()
local k_expr = "\"expression\":{"
local expr_pos = scan.index_of_from(json, k_expr, print_pos)
// If expression object cannot be bounded, fall back to typed-direct pattern within the current slice
if expr_pos <= 0 || expr_pos >= end {
// bound coarse slice to current Print by next Print marker
local k_print = "\"kind\":\"Print\""
local next_p = scan.index_of_from(json, k_print, print_pos + 1)
local slice_end = end
if next_p > 0 { slice_end = next_p }
local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
// only if BinaryOp is present in this slice
if scan.index_of_from(json, "\"kind\":\"BinaryOp\"", print_pos) > 0 {
local lp = scan.index_of_from(json, k_lint, print_pos)
if lp > 0 { if lp < slice_end {
local ld = scan.read_digits(json, lp + k_lint.length())
if ld != "" {
local rp = scan.index_of_from(json, k_rint, lp + k_lint.length())
if rp > 0 { if rp < slice_end {
local rd = scan.read_digits(json, rp + k_rint.length())
if rd != "" { print(scan._int_to_str(scan._str_to_int(ld) + scan._str_to_int(rd))) return 1 }
}}
}
}}
}
return -1
}
local obj_start = scan.index_of_from(json, "{", expr_pos)
if obj_start <= 0 || obj_start >= end { return -1 }
local obj_end = scan.find_balanced_object_end(json, obj_start)
if obj_end <= 0 || obj_end > end {
local k_print = "\"kind\":\"Print\""
local next_p = scan.index_of_from(json, k_print, print_pos + 1)
local obj_end2 = end
if next_p > 0 && next_p <= end { obj_end2 = next_p }
// typed-direct fallback in bounded region
local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
local lp = scan.index_of_from(json, k_lint, obj_start)
if lp > 0 { if lp < obj_end2 {
local ld = scan.read_digits(json, lp + k_lint.length())
if ld != "" {
local rp = scan.index_of_from(json, k_rint, lp + k_lint.length())
if rp > 0 { if rp < obj_end2 {
local rd = scan.read_digits(json, rp + k_rint.length())
if rd != "" { print(scan._int_to_str(scan._str_to_int(ld) + scan._str_to_int(rd))) return 1 }
}}
}
}}
return -1
}
local k_bo = "\"kind\":\"BinaryOp\""
local bpos = scan.index_of_from(json, k_bo, obj_start)
if bpos <= 0 || bpos >= obj_end {
// typed-direct fallback (within bounds window)
local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
local lp = scan.index_of_from(json, k_lint, obj_start)
if lp > 0 { if lp < obj_end {
local ld = scan.read_digits(json, lp + k_lint.length())
if ld != "" {
local rp = scan.index_of_from(json, k_rint, lp + k_lint.length())
if rp > 0 { if rp < obj_end {
local rd = scan.read_digits(json, rp + k_rint.length())
if rd != "" { print(scan._int_to_str(scan._str_to_int(ld) + scan._str_to_int(rd))) return 1 }
}}
}
}}
return -1
}
local k_plus = "\"operator\":\"+\""
local opos = scan.index_of_from(json, k_plus, bpos)
if opos <= 0 || opos >= obj_end {
// typed-direct fallback
local k_lint = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
local k_rint = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
local lp = scan.index_of_from(json, k_lint, obj_start)
if lp > 0 { if lp < obj_end {
local ld = scan.read_digits(json, lp + k_lint.length())
if ld != "" {
local rp = scan.index_of_from(json, k_rint, lp + k_lint.length())
if rp > 0 { if rp < obj_end {
local rd = scan.read_digits(json, rp + k_rint.length())
if rd != "" { print(scan._int_to_str(scan._str_to_int(ld) + scan._str_to_int(rd))) return 1 }
}}
}
}}
return -1
}
local nums = []
local i = obj_start
loop (i < obj_end) {
if json.substring(i, i+1) == "\"" {
local j = scan.index_of_from(json, "\"", i+1)
if j < 0 || j >= obj_end { break }
i = j + 1
continue
}
local d = scan.read_digits(json, i)
if d { nums.push(d) i = i + d.length() continue }
i = i + 1
}
local nsz = nums.size()
if nsz < 2 { return -1 }
local a = scan._str_to_int(nums.get(nsz-2))
local b = scan._str_to_int(nums.get(nsz-1))
print(scan._int_to_str(a + b))
return obj_end + 1
}
// Deterministic: within Print.expression BinaryOp('+'), pick two successive 'value' fields and sum
try_print_binop_sum_expr_values(json, end, print_pos) {
local scan = new MiniVmScan()
local cur = new MiniJson()
local k_expr = "\"expression\":{"
local expr_pos = scan.index_of_from(json, k_expr, print_pos)
if expr_pos <= 0 || expr_pos >= end { return -1 }
local obj_start = scan.index_of_from(json, "{", expr_pos)
if obj_start <= 0 || obj_start >= end { return -1 }
local obj_end = scan.find_balanced_object_end(json, obj_start)
if obj_end <= 0 || obj_end > end { return -1 }
local k_bo = "\"kind\":\"BinaryOp\""
local bpos = scan.index_of_from(json, k_bo, obj_start)
if bpos <= 0 || bpos >= obj_end { return -1 }
local k_plus = "\"operator\":\"+\""
local opos = scan.index_of_from(json, k_plus, bpos)
if opos <= 0 || opos >= obj_end { return -1 }
local k_v = "\"value\":"
local found = 0
local a = 0
local pos = scan.index_of_from(json, k_v, obj_start)
loop (pos > 0 && pos < obj_end) {
local di = cur.read_digits_from(json, pos + k_v.length())
if di != "" {
if found == 0 { a = scan._str_to_int(di) found = 1 } else {
local b = scan._str_to_int(di)
print(scan._int_to_str(a + b))
return obj_end + 1
}
}
pos = scan.index_of_from(json, k_v, pos + k_v.length())
if pos <= 0 || pos >= obj_end { break }
}
return -1
}
// Simpler: after operator '+', scan two successive 'value' fields and sum
try_print_binop_sum_after_bop(json) {
local scan = new MiniVmScan()
local k_bo = "\"kind\":\"BinaryOp\""
local bpos = json.indexOf(k_bo)
if bpos < 0 { return -1 }
local k_plus = "\"operator\":\"+\""
local opos = scan.index_of_from(json, k_plus, bpos)
if opos < 0 { return -1 }
local k_v = "\"value\":"
local p = opos
p = scan.index_of_from(json, k_v, p)
if p < 0 { return -1 }
p = scan.index_of_from(json, k_v, p + k_v.length())
if p < 0 { return -1 }
local end1 = scan.index_of_from(json, "}", p)
if end1 < 0 { return -1 }
local d1 = scan.read_digits(json, p + k_v.length())
if d1 == "" { return -1 }
p = scan.index_of_from(json, k_v, end1)
if p < 0 { return -1 }
p = scan.index_of_from(json, k_v, p + k_v.length())
if p < 0 { return -1 }
local end2 = scan.index_of_from(json, "}", p)
if end2 < 0 { return -1 }
local d2 = scan.read_digits(json, p + k_v.length())
if d2 == "" { return -1 }
local ai = scan._str_to_int(d1)
local bi = scan._str_to_int(d2)
print(scan._int_to_str(ai + bi))
return 0
}
// Fallback: find first BinaryOp and return sum of two numeric values as string
parse_first_binop_sum(json) {
local scan = new MiniVmScan()
local k_bo = "\"kind\":\"BinaryOp\""
local bpos = json.indexOf(k_bo)
if bpos < 0 { return "" }
local k_typed = "\"type\":\"int\",\"value\":"
local p1 = scan.index_of_from(json, k_typed, bpos)
if p1 < 0 { return "" }
local d1 = scan.read_digits(json, p1 + k_typed.length())
if d1 == "" { return "" }
local p2 = scan.index_of_from(json, k_typed, p1 + k_typed.length())
if p2 < 0 { return "" }
local d2 = scan.read_digits(json, p2 + k_typed.length())
if d2 == "" { return "" }
return scan._int_to_str(scan._str_to_int(d1) + scan._str_to_int(d2))
}
}