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
This commit is contained in:
@ -7,6 +7,8 @@ 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()
|
||||
@ -127,39 +129,40 @@ static box MiniVmPrints {
|
||||
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 }
|
||||
// dev trace hook (no-op)
|
||||
// 1) BinaryOp
|
||||
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 }
|
||||
}}
|
||||
}
|
||||
}}
|
||||
// 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)
|
||||
@ -173,18 +176,21 @@ static box MiniVmPrints {
|
||||
// 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 (simple pattern inside current Print object)
|
||||
{
|
||||
// 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
|
||||
}
|
||||
|
||||
53
apps/tests/jsonbox_collect_prints_smoke.nyash
Normal file
53
apps/tests/jsonbox_collect_prints_smoke.nyash
Normal file
@ -0,0 +1,53 @@
|
||||
static box Main {
|
||||
main(args) {
|
||||
// JSON v0 Program with mixed Print expressions
|
||||
local json = "{\"kind\":\"Program\",\"statements\":[{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"string\",\"value\":\"A\"}}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"FunctionCall\",\"name\":\"echo\",\"arguments\":[{\"kind\":\"Literal\",\"value\":{\"type\":\"string\",\"value\":\"B\"}}]}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"FunctionCall\",\"name\":\"itoa\",\"arguments\":[{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":7}}]}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"Compare\",\"operation\":\"<\",\"lhs\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":1}},\"rhs\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":2}}}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"BinaryOp\",\"operator\":\"+\",\"left\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":3}},\"right\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":4}}}},{\"kind\":\"Print\",\"expression\":{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":5}}}]}"
|
||||
|
||||
local doc = new JsonDocBox()
|
||||
doc.parse(json)
|
||||
local root = doc.root()
|
||||
local stmts = root.get("statements")
|
||||
local n = stmts.size()
|
||||
local i = 0
|
||||
loop (i < n) {
|
||||
local node = stmts.at(i)
|
||||
local expr = node.get("expression")
|
||||
local kind = expr.get("kind").str()
|
||||
if kind == "Literal" {
|
||||
local val = expr.get("value")
|
||||
local ty = val.get("type").str()
|
||||
if ty == "string" { print(val.get("value").str()) } else { print(val.get("value").int()) }
|
||||
} else if kind == "FunctionCall" {
|
||||
local name = expr.get("name").str()
|
||||
// First argument as typed literal object { type, value }
|
||||
local arg0 = expr.get("arguments").at(0).get("value")
|
||||
if name == "echo" {
|
||||
if arg0.get("type").str() == "string" { print(arg0.get("value").str()) } else { print(arg0.get("value").int()) }
|
||||
}
|
||||
if name == "itoa" { print(arg0.get("value").int()) }
|
||||
} else if kind == "Compare" {
|
||||
local op = expr.get("operation").str()
|
||||
local lhs = expr.get("lhs").get("value").get("value").int()
|
||||
local rhs = expr.get("rhs").get("value").get("value").int()
|
||||
if op == "<" {
|
||||
if lhs < rhs { print(1) } else { print(0) }
|
||||
}
|
||||
if op == "==" {
|
||||
if lhs == rhs { print(1) } else { print(0) }
|
||||
}
|
||||
if op == ">" {
|
||||
if lhs > rhs { print(1) } else { print(0) }
|
||||
}
|
||||
} else if kind == "BinaryOp" {
|
||||
local op = expr.get("operator").str()
|
||||
if op == "+" {
|
||||
local left = expr.get("left").get("value").get("value").int()
|
||||
local right = expr.get("right").get("value").get("value").int()
|
||||
print(left + right)
|
||||
}
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
}
|
||||
16
apps/tests/jsonbox_nested.nyash
Normal file
16
apps/tests/jsonbox_nested.nyash
Normal file
@ -0,0 +1,16 @@
|
||||
static box Main {
|
||||
main(args) {
|
||||
local json = "{\"a\":{\"n\":7,\"s\":\"B\"},\"arr\":[1,2,3]}"
|
||||
local doc = new JsonDocBox()
|
||||
doc.parse(json)
|
||||
local root = doc.root()
|
||||
// prints: B, 7, 3, 2
|
||||
print(root.get("a").get("s").str())
|
||||
print(root.get("a").get("n").int())
|
||||
local arr = root.get("arr")
|
||||
print(arr.size())
|
||||
print(arr.at(1).int())
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
12
apps/tests/jsonbox_parse_err.nyash
Normal file
12
apps/tests/jsonbox_parse_err.nyash
Normal file
@ -0,0 +1,12 @@
|
||||
static box Main {
|
||||
main(args) {
|
||||
// invalid JSON (missing value after kind)
|
||||
local json = "{\"kind\": }"
|
||||
local doc = new JsonDocBox()
|
||||
doc.parse(json)
|
||||
local err = doc.error()
|
||||
if err == "" { print("OK") } else { print("ERR") }
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
11
apps/tests/jsonbox_parse_ok.nyash
Normal file
11
apps/tests/jsonbox_parse_ok.nyash
Normal file
@ -0,0 +1,11 @@
|
||||
static box Main {
|
||||
main(args) {
|
||||
local json = "{\"kind\":\"Program\",\"statements\":[]}"
|
||||
local doc = new JsonDocBox()
|
||||
doc.parse(json)
|
||||
local root = doc.root()
|
||||
print(root.get("kind").str())
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
12
apps/tests/jsonbox_parse_probe.nyash
Normal file
12
apps/tests/jsonbox_parse_probe.nyash
Normal file
@ -0,0 +1,12 @@
|
||||
static box Main {
|
||||
main(args) {
|
||||
local json = "{\"kind\":\"Program\",\"statements\":[]}"
|
||||
local doc = new JsonDocBox()
|
||||
doc.parse(json)
|
||||
// print parse error (if any) for debugging
|
||||
print(doc.error())
|
||||
local root = doc.root()
|
||||
print(root.get("kind").str())
|
||||
return 0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user