Files
hakorune/apps/lib/json_builder.hako

122 lines
3.6 KiB
Plaintext

// JsonBuilder — Minimal helpers to construct AST JSON v0 fragments as strings
// Usage: local JB = include "apps/lib/json_builder.hako"
// local s = JB.literal_string("x")
static box JsonBuilder {
// Join array of strings with a separator
join(arr, sep) {
local out = ""
local i = 0
local n = arr.length()
loop(i < n) {
out = out + arr.get(i)
if i + 1 < n { out = out + sep }
i = i + 1
}
return out
}
// JSON string escaping (minimal): backslash, quote
escape_string(s) {
local out = ""
local i = 0
loop(i < s.length()) {
local ch = s.substring(i, i + 1)
if ch == "\\" {
out = out + "\\\\"
} else {
if ch == "\"" { out = out + "\\\"" } else { out = out + ch }
}
i = i + 1
}
return out
}
quote(s) { return "\"" + this.escape_string(s) + "\"" }
// ==== Node builders (strings) ====
literal_string(s) {
return "{\"kind\":\"Literal\",\"value\":{\"type\":\"string\",\"value\":" + this.quote(s) + "}}"
}
literal_int(i) {
return "{\"kind\":\"Literal\",\"value\":{\"type\":\"int\",\"value\":" + i + "}}"
}
literal_bool(b) {
if b { return "{\"kind\":\"Literal\",\"value\":{\"type\":\"bool\",\"value\":true}}" }
return "{\"kind\":\"Literal\",\"value\":{\"type\":\"bool\",\"value\":false}}"
}
literal_null() { return "{\"kind\":\"Literal\",\"value\":{\"type\":\"null\"}}" }
variable(name) {
return "{\"kind\":\"Variable\",\"name\":" + this.quote(name) + "}"
}
binary(op, lhs_json, rhs_json) {
return "{\"kind\":\"BinaryOp\",\"op\":" + this.quote(op) + ",\"left\":" + lhs_json + ",\"right\":" + rhs_json + "}"
}
assignment(target_json, value_json) {
return "{\"kind\":\"Assignment\",\"target\":" + target_json + ",\"value\":" + value_json + "}"
}
print_(expr_json) {
return "{\"kind\":\"Print\",\"expression\":" + expr_json + "}"
}
return_(value_json) {
local v = "null"
if value_json != null { v = value_json }
return "{\"kind\":\"Return\",\"value\":" + v + "}"
}
local_decl(vars, inits) {
// vars: array[string], inits: array[string|null]
local vs = []
local i = 0
loop(i < vars.length()) {
vs.push(this.quote(vars.get(i)))
i = i + 1
}
local is = []
i = 0
loop(i < inits.length()) {
local v = inits.get(i)
if v == null { is.push("null") } else { is.push(v) }
i = i + 1
}
return "{\"kind\":\"Local\",\"variables\":[" + this.join(vs, ",") + "],\"inits\":[" + this.join(is, ",") + "]}"
}
array(elems_json) {
return "{\"kind\":\"Array\",\"elements\":[" + this.join(elems_json, ",") + "]}"
}
map(entries) {
// entries: array of [k:string, v:json]
local parts = []
local i = 0
loop(i < entries.length()) {
local kv = entries.get(i)
local k = kv.get(0)
local v = kv.get(1)
parts.push("{\"k\":" + this.quote(k) + ",\"v\":" + v + "}")
i = i + 1
}
return "{\"kind\":\"Map\",\"entries\":[" + this.join(parts, ",") + "]}"
}
if_(cond_json, then_stmts_json, else_stmts_json) {
local then_s = "[" + this.join(then_stmts_json, ",") + "]"
local else_s = "null"
if else_stmts_json != null { else_s = "[" + this.join(else_stmts_json, ",") + "]" }
return "{\"kind\":\"If\",\"condition\":" + cond_json + ",\"then\":" + then_s + ",\"else\":" + else_s + "}"
}
loop_(cond_json, body_stmts_json) {
return "{\"kind\":\"Loop\",\"condition\":" + cond_json + ",\"body\":[" + this.join(body_stmts_json, ",") + "]}"
}
program(stmts_json) {
return "{\"kind\":\"Program\",\"statements\":[" + this.join(stmts_json, ",") + "]}"
}
}