Files
hakorune/apps/selfhost-vm/boxes/mini_vm_prints.nyash
Selfhosting Dev 27568eb4a6 json: add v2 JsonDoc/JsonNode plugin with runtime provider switch; vendored yyjson + FFI; loader resolve(name)->method_id; PyVM JSON shims; smokes + CI gate; disable MiniVmPrints fallbacks by default
- plugin_loader_v2: store per-Box resolve() from TypeBox FFI; add resolve_method_id() and use in invoke_instance_method
- plugin_loader_unified: resolve_method() falls back to loader’s resolve when TOML lacks method entries
- nyash.toml: register JsonDocBox/JsonNodeBox methods (birth/parse/root/error; kind/get/size/at/str/int/bool)
- plugins/nyash-json-plugin:
  * serde/yyjson provider switch via env NYASH_JSON_PROVIDER (default serde)
  * vendored yyjson (c/yyjson) + shim; parse/root/get/size/at/str/int/bool implemented for yyjson
  * TLV void returns aligned to tag=9
- PyVM: add minimal JsonDocBox/JsonNodeBox shims in ops_box.py (for dev path)
- tests/smokes: add jsonbox_{parse_ok,parse_err,nested,collect_prints}; wire two into min-gate CI
- tools: collect_prints_mixed now uses JSON-based app
- MiniVmPrints: move BinaryOp and fallback heuristics behind a dev toggle (default OFF)
- CURRENT_TASK.md: updated with provider policy and fallback stance
2025-09-22 06:16:20 +09:00

231 lines
9.9 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.

using selfhost.vm.scan as MiniVmScan
using selfhost.vm.binop as MiniVmBinOp
using selfhost.vm.compare as MiniVmCompare
// Use the JSON adapter facade for cursor ops (next_non_ws, digits)
using selfhost.vm.json as MiniJsonLoader
static box MiniVmPrints {
// dev trace flag (0=OFF)
_trace_enabled() { return 0 }
// fallback toggle for legacy heuristics (0=OFF, 1=ON)
_fallback_enabled() { return 0 }
// literal string within Print
try_print_string_value_at(json, end, print_pos) {
local scan = new MiniVmScan()
local k_val = "\"value\":\""
local s = scan.index_of_from(json, k_val, print_pos)
if s < 0 || s >= end { return -1 }
local i = s + k_val.length()
local j = scan.index_of_from(json, "\"", i)
if j <= 0 || j > end { return -1 }
print(json.substring(i, j))
return j + 1
}
// literal int within Print (typed)
try_print_int_value_at(json, end, print_pos) {
local scan = new MiniVmScan()
local k_expr = "\"expression\":{"
local epos = scan.index_of_from(json, k_expr, print_pos)
if epos <= 0 || epos >= end { return -1 }
local obj_start = scan.index_of_from(json, "{", epos)
if obj_start <= 0 || obj_start >= end { return -1 }
local obj_end = scan.find_balanced_object_end(json, obj_start)
if obj_end <= 0 || obj_end > end { return -1 }
// robust: look for explicit int type within expression object
local k_tint = "\"type\":\"int\""
local tpos = scan.index_of_from(json, k_tint, obj_start)
if tpos <= 0 || tpos >= obj_end { return -1 }
local k_val2 = "\"value\":"
local v2 = scan.index_of_from(json, k_val2, tpos)
if v2 <= 0 || v2 >= obj_end { return -1 }
local digits = scan.read_digits(json, v2 + k_val2.length())
if digits == "" { return -1 }
print(digits)
return obj_end + 1
}
// minimal FunctionCall printer for echo/itoa
try_print_functioncall_at(json, end, print_pos) {
local scan = new MiniVmScan()
local k_fc = "\"kind\":\"FunctionCall\""
local fcp = scan.index_of_from(json, k_fc, print_pos)
if fcp <= 0 || fcp >= end { return -1 }
local k_name = "\"name\":\""
local npos = scan.index_of_from(json, k_name, fcp)
if npos <= 0 || npos >= end { return -1 }
local ni = npos + k_name.length()
local nj = scan.index_of_from(json, "\"", ni)
if nj <= 0 || nj > end { return -1 }
local fname = json.substring(ni, nj)
local k_args = "\"arguments\":["
local apos = scan.index_of_from(json, k_args, nj)
if apos <= 0 || apos >= end { return -1 }
local arr_start = scan.index_of_from(json, "[", apos)
local arr_end = scan.find_balanced_array_end(json, arr_start)
if arr_start <= 0 || arr_end <= 0 || arr_end > end { return -1 }
// handle empty args []
local nn = new MiniJsonLoader().next_non_ws(json, arr_start+1)
if nn > 0 && nn <= arr_end {
if json.substring(nn, nn+1) == "]" {
if fname == "echo" { print("") return arr_end + 1 }
if fname == "itoa" { print("0") return arr_end + 1 }
return -1
}
}
// first arg type
local k_t = "\"type\":\""
local atpos = scan.index_of_from(json, k_t, arr_start)
if atpos <= 0 || atpos >= arr_end {
if fname == "echo" { print("") return arr_end + 1 }
if fname == "itoa" { print("0") return arr_end + 1 }
return -1
}
atpos = atpos + k_t.length()
local at_end = scan.index_of_from(json, "\"", atpos)
if at_end <= 0 || at_end > arr_end { return -1 }
local aty = json.substring(atpos, at_end)
if aty == "string" {
local k_sval = "\"value\":\""
local svalp = scan.index_of_from(json, k_sval, at_end)
if svalp <= 0 || svalp >= arr_end { return -1 }
local si = svalp + k_sval.length()
local sj = scan.index_of_from(json, "\"", si)
if sj <= 0 || sj > arr_end { return -1 }
local sval = json.substring(si, sj)
if fname == "echo" { print(sval) return sj + 1 }
return -1
}
if aty == "int" || aty == "i64" || aty == "integer" {
local k_ival = "\"value\":"
local ivalp = scan.index_of_from(json, k_ival, at_end)
if ivalp <= 0 || ivalp >= arr_end { return -1 }
local digits = scan.read_digits(json, ivalp + k_ival.length())
if fname == "itoa" || fname == "echo" { print(digits) return ivalp + k_ival.length() }
return -1
}
return -1
}
// Print all Print-Literal values within [start,end]
print_prints_in_slice(json, start, end) {
local scan = new MiniVmScan()
local bin = new MiniVmBinOp()
local cmp = new MiniVmCompare()
local pos = start
local printed = 0
local guard = 0
local trace = _trace_enabled()
loop (true) {
guard = guard + 1
if guard > 200 { break }
local k_print = "\"kind\":\"Print\""
local p = scan.index_of_from(json, k_print, pos)
if p < 0 || p > end { break }
// bound current Print object
local p_obj_start = scan.index_of_from(json, "{", p)
local p_obj_end = scan.find_balanced_object_end(json, p_obj_start)
if p_obj_start <= 0 || p_obj_end <= 0 { p_obj_end = p + k_print.length() }
// also compute coarse slice end by next Print marker to guard when object balance is not reliable
local next_p = scan.index_of_from(json, k_print, p + k_print.length())
local p_slice_end = end
if next_p > 0 { p_slice_end = next_p }
// 1) BinaryOp fallbacks開発用トグル。既定OFF
if (new MiniVmPrints()._fallback_enabled() == 1) {
local nextp = bin.try_print_binop_sum_any(json, end, p)
if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue }
nextp = bin.try_print_binop_at(json, end, p)
if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue }
nextp = bin.try_print_binop_int_greedy(json, end, p)
if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue }
nextp = bin.try_print_binop_sum_any(json, end, p)
if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue }
// Inline typed sum within this Print BinaryOp('+')
{
local k_expr = "\"expression\":{"
local epos = scan.index_of_from(json, k_expr, p)
if epos > 0 { if epos < p_obj_end {
if scan.index_of_from(json, "\"kind\":\"BinaryOp\"", epos) > 0 {
if scan.index_of_from(json, "\"operator\":\"+\"", epos) > 0 {
local k_l = "\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
local k_r = "\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":"
local lp = scan.index_of_from(json, k_l, epos)
if lp > 0 { if lp < p_obj_end {
local ld = scan.read_digits(json, lp + k_l.length())
if ld != "" {
local rp = scan.index_of_from(json, k_r, lp + k_l.length())
if rp > 0 { if rp < p_obj_end {
local rd = scan.read_digits(json, rp + k_r.length())
if rd != "" { print(new MiniVmScan()._int_to_str(new MiniVmScan()._str_to_int(ld) + new MiniVmScan()._str_to_int(rd))) printed = printed + 1 pos = p_obj_end + 1 continue }
}}
}
}}
}
}
}}
}
}
// 2) Compare
nextp = cmp.try_print_compare_at(json, end, p)
if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue }
// 3) FunctionCall minimal
nextp = new MiniVmPrints().try_print_functioncall_at(json, end, p)
if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue }
// 4) literal string
nextp = new MiniVmPrints().try_print_string_value_at(json, end, p)
if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue }
// 5) literal int via type
nextp = new MiniVmPrints().try_print_int_value_at(json, end, p)
if nextp > 0 { printed = printed + 1 pos = p_obj_end + 1 continue }
// 5b) literal int簡易フォールバック既定OFF
if (new MiniVmPrints()._fallback_enabled() == 1) {
local ki = "\"type\":\"int\",\"value\":"
local pi = scan.index_of_from(json, ki, p)
if pi > 0 { if pi < p_slice_end {
local digits = scan.read_digits(json, pi + ki.length())
if digits != "" { print(digits) printed = printed + 1 pos = p_slice_end continue }
}}
// Unknown shape: skip this Print object entirely to avoid stalls
pos = p_obj_end + 1
if pos <= p { pos = p + k_print.length() }
} else {
// 既定は最小前進(次の探索へ)
pos = p + k_print.length()
}
}
return printed
}
// Process top-level If with literal condition; print branch prints. Returns printed count.
process_if_once(json) {
local scan = new MiniVmScan()
local k_if = "\"kind\":\"If\""
local p = scan.index_of_from(json, k_if, 0)
if p < 0 { return 0 }
local k_cond = "\"condition\""
local cpos = scan.index_of_from(json, k_cond, p)
if cpos < 0 { return 0 }
local k_val = "\"value\":"
local vpos = scan.index_of_from(json, k_val, cpos)
if vpos < 0 { return 0 }
local val_digits = scan.read_digits(json, vpos + k_val.length())
local truthy = 0
if val_digits { if val_digits != "0" { truthy = 1 } }
local k_then = "\"then_body\""
local k_else = "\"else_body\""
local bkey = k_then
if truthy == 0 { bkey = k_else }
local bpos = scan.index_of_from(json, bkey, cpos)
if bpos < 0 { return 0 }
local arr_start = scan.index_of_from(json, "[", bpos)
if arr_start < 0 { return 0 }
local arr_end = new MiniVmScan().find_balanced_array_end(json, arr_start)
if arr_end < 0 { return 0 }
return new MiniVmPrints().print_prints_in_slice(json, arr_start, arr_end)
}
// Print all Print-Literal values in Program.statements (string/int only; MVP)
print_all_print_literals(json) {
return new MiniVmPrints().print_prints_in_slice(json, 0, json.length())
}
}