fix(mir): PHI検証panic修正 - update_cfg()を検証前に呼び出し
A案実装: debug_verify_phi_inputs呼び出し前にCFG predecessorを更新
修正箇所(7箇所):
- src/mir/builder/phi.rs:50, 73, 132, 143
- src/mir/builder/ops.rs:273, 328, 351
根本原因:
- Branch/Jump命令でsuccessorは即座に更新
- predecessorはupdate_cfg()で遅延再構築
- PHI検証が先に実行されてpredecessor未更新でpanic
解決策:
- 各debug_verify_phi_inputs呼び出し前に
if let Some(func) = self.current_function.as_mut() {
func.update_cfg();
}
を挿入してCFGを同期
影響: if/else文、論理演算子(&&/||)のPHI生成が正常動作
This commit is contained in:
@ -12,3 +12,8 @@ Policy
|
||||
- VM engines live under `lang/src/vm/engines/` (Hakorune/Mini), with shared helpers in `vm/boxes/`.
|
||||
- Keep imports across these boundaries minimal and documented.
|
||||
|
||||
Grammar Notes (parser parity)
|
||||
- Semicolons are accepted as optional statement separators (default ON).
|
||||
- Both newline and `;` delimit statements; trailing `};` is allowed.
|
||||
- Consecutive `;;` are treated as empty statements (no-op).
|
||||
- Env toggle (opt-out): set `NYASH_PARSER_ALLOW_SEMICOLON=0|false|off` to disable.
|
||||
|
||||
@ -17,11 +17,11 @@ static box RewriteKnown {
|
||||
// Find name start
|
||||
local name_key = "\"name\":\""
|
||||
local np = s.indexOf(name_key, p)
|
||||
if np < 0 { out = out + s.substring(p, s.size()) i = s.size() break }
|
||||
local name_start = np + name_key.size()
|
||||
if np < 0 { out = out + s.substring(p, s.length()) i = s.length() break }
|
||||
local name_start = np + name_key.length()
|
||||
// Find name end quote
|
||||
local name_end = s.indexOf("\"", name_start)
|
||||
if name_end < 0 { out = out + s.substring(p, s.size()) i = s.size() break }
|
||||
if name_end < 0 { out = out + s.substring(p, s.length()) i = s.length() break }
|
||||
local name = s.substring(name_start, name_end)
|
||||
|
||||
// If already canonical, just append segment as-is
|
||||
@ -35,7 +35,7 @@ static box RewriteKnown {
|
||||
local args_key = "\"args\":["
|
||||
local ap = s.indexOf(args_key, name_end)
|
||||
if ap < 0 { out = out + s.substring(p, name_end) i = name_end continue }
|
||||
local lb = ap + args_key.size() - 1 // points to '['
|
||||
local lb = ap + args_key.length() - 1 // points to '['
|
||||
// Find closing bracket
|
||||
local rb = s.indexOf("]", lb + 1)
|
||||
if rb < 0 { out = out + s.substring(p, name_end) i = name_end continue }
|
||||
@ -44,7 +44,7 @@ static box RewriteKnown {
|
||||
local body = s.substring(lb + 1, rb)
|
||||
local trimmed = me._trim(body)
|
||||
local arity = 0
|
||||
if trimmed.size() == 0 {
|
||||
if trimmed.length() == 0 {
|
||||
arity = 0
|
||||
} else {
|
||||
// guard: if body contains non-digit/comma/space, skip rewrite (fail-safe)
|
||||
@ -61,13 +61,13 @@ static box RewriteKnown {
|
||||
i = name_end
|
||||
}
|
||||
// Append the tail
|
||||
out = out + s.substring(i, s.size())
|
||||
out = out + s.substring(i, s.length())
|
||||
return out
|
||||
}
|
||||
|
||||
_trim(text) {
|
||||
local a = 0
|
||||
local b = text.size()
|
||||
local b = text.length()
|
||||
loop(a < b && me._is_space(text.substring(a,a+1))) { a = a + 1 }
|
||||
loop(b > a && me._is_space(text.substring(b-1,b))) { b = b - 1 }
|
||||
return text.substring(a,b)
|
||||
@ -76,7 +76,7 @@ static box RewriteKnown {
|
||||
_is_digit(ch) { return ch >= "0" && ch <= "9" }
|
||||
_is_simple_ids(text) {
|
||||
local i = 0
|
||||
loop(i < text.size()) {
|
||||
loop(i < text.length()) {
|
||||
local ch = text.substring(i,i+1)
|
||||
if !(me._is_space(ch) || ch == "," || me._is_digit(ch)) { return false }
|
||||
i = i + 1
|
||||
@ -86,7 +86,7 @@ static box RewriteKnown {
|
||||
_count_commas(text) {
|
||||
local i = 0
|
||||
local n = 0
|
||||
loop(i < text.size()) { if text.substring(i,i+1) == "," { n = n + 1 } i = i + 1 }
|
||||
loop(i < text.length()) { if text.substring(i,i+1) == "," { n = n + 1 } i = i + 1 }
|
||||
return n
|
||||
}
|
||||
_itoa(n) {
|
||||
|
||||
@ -191,6 +191,6 @@ static box CondInserter {
|
||||
local e = finish
|
||||
if s < 0 { s = 0 }
|
||||
if e < s { e = s }
|
||||
return call("String.substring/2", text, s, e)
|
||||
return text.substring(s, e)
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ static box LocalSSA {
|
||||
local p = hay.indexOf(needle)
|
||||
if p < 0 { break }
|
||||
n = n + 1
|
||||
hay = hay.substring(p + needle.size(), hay.size())
|
||||
hay = hay.substring(p + needle.length(), hay.length())
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ static box CallEmitBox {
|
||||
}
|
||||
|
||||
make_mir_call_module(name, arg_ids, dst) {
|
||||
local canon = me._canonical_module_name(name, arg_ids.size())
|
||||
local canon = me._canonical_module_name(name, arg_ids.length())
|
||||
local callee = {type: "ModuleFunction", name: canon}
|
||||
return {op: "mir_call", dst: dst, callee: callee, args: arg_ids}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// newbox_emit_box.hako — NewBoxEmitBox: construct MIR(JSON v0) node for newbox
|
||||
// Responsibility: return MapBox node for { op: newbox, box_type, args, dst }.
|
||||
using "apps/lib/json_native/stringify.hako" as JSON
|
||||
using "lang/src/shared/json/stringify.hako" as JSON
|
||||
|
||||
static box NewBoxEmitBox {
|
||||
make_new(box_type, arg_ids, dst) {
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
// Future: add Binary/Compare/ExternCall/BoxCall lowering incrementally.
|
||||
|
||||
using selfhost.common.json.mir_builder_min as MirJsonBuilderMin
|
||||
using "apps/lib/json_native/stringify.hako" as JSON
|
||||
using "lang/src/shared/json/stringify.hako" as JSON
|
||||
using "lang/src/shared/common/string_helpers.hako" as StringHelpers
|
||||
|
||||
static box MirEmitterBox {
|
||||
@ -149,7 +149,7 @@ static box MirEmitterBox {
|
||||
q = q + 23 // length of the marker
|
||||
// Use StringHelpers for digit reading and parsing
|
||||
local digits = StringHelpers.read_digits(ast_json, q)
|
||||
if digits.size() == 0 { return 0 }
|
||||
if digits.length() == 0 { return 0 }
|
||||
return StringHelpers.to_i64(digits)
|
||||
}
|
||||
|
||||
|
||||
@ -30,7 +30,8 @@ static box Main {
|
||||
|
||||
_collect_flags(args) {
|
||||
// Stage-A flags: emit/source/return only
|
||||
local flags = { emit: 0, ret: null, source: null, stage_b: 0 }
|
||||
// Stage-B flags: prefer_cfg/stage3/v1_compat
|
||||
local flags = { emit: 0, ret: null, source: null, stage_b: 0, prefer_cfg: 1, stage3: 0, v1_compat: 0 }
|
||||
if args == null { return flags }
|
||||
|
||||
local i = 0
|
||||
@ -48,6 +49,14 @@ static box Main {
|
||||
local parsed = me._parse_signed_int(args.get(i + 1))
|
||||
if parsed != null { flags.ret = parsed }
|
||||
i = i + 1
|
||||
} else if token == "--prefer-cfg" && i + 1 < n {
|
||||
local parsed = me._parse_signed_int(args.get(i + 1))
|
||||
if parsed != null { flags.prefer_cfg = parsed }
|
||||
i = i + 1
|
||||
} else if token == "--stage3" {
|
||||
flags.stage3 = 1
|
||||
} else if token == "--v1-compat" {
|
||||
flags.v1_compat = 1
|
||||
}
|
||||
i = i + 1
|
||||
}
|
||||
@ -469,7 +478,9 @@ static box Main {
|
||||
main(args) {
|
||||
local flags = me._collect_flags(args)
|
||||
if flags.stage_b == 1 {
|
||||
return StageBMain.main(args)
|
||||
local json = StageBMain._do_compile_stage_b(flags.source, flags.prefer_cfg, flags.stage3, flags.v1_compat)
|
||||
print(json)
|
||||
return 0
|
||||
}
|
||||
if flags.emit == 1 {
|
||||
local json = me._compile_source_to_json_v0(flags.source)
|
||||
@ -489,4 +500,5 @@ static box Main {
|
||||
me._emit_program_json(ret)
|
||||
return 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
// Stage-B compiler entry — ParserBox → FlowEntry emit-only
|
||||
|
||||
using "lang/src/compiler/parser/parser_box.hako" as ParserBox
|
||||
using "lang/src/compiler/pipeline_v2/flow_entry.hako" as FlowEntryBox
|
||||
using lang.compiler.parser.box as ParserBox
|
||||
using lang.compiler.pipeline_v2.flow_entry as FlowEntryBox
|
||||
|
||||
static box StageBMain {
|
||||
_fallback_program() {
|
||||
return "{\"version\":0,\"kind\":\"Program\",\"body\":[{\"type\":\"Return\",\"expr\":{\"type\":\"Int\",\"value\":0}}]}"
|
||||
}
|
||||
|
||||
_parse_signed_int(raw) {
|
||||
if raw == null { return null }
|
||||
local text = "" + raw
|
||||
@ -52,23 +56,20 @@ static box StageBMain {
|
||||
return flags
|
||||
}
|
||||
|
||||
main(args) {
|
||||
local flags = me._collect_flags(args)
|
||||
local src = flags.source
|
||||
_do_compile_stage_b(src, prefer_cfg, stage3, v1_compat) {
|
||||
if src == null || src == "" {
|
||||
print("{\"version\":0,\"kind\":\"Program\",\"body\":[{\"type\":\"Return\",\"expr\":{\"type\":\"Int\",\"value\":0}}]}")
|
||||
return 0
|
||||
return me._fallback_program()
|
||||
}
|
||||
local p = new ParserBox()
|
||||
if flags.stage3 == 1 { p.stage3_enable(1) }
|
||||
if stage3 == 1 { p.stage3_enable(1) }
|
||||
p.extract_usings(src)
|
||||
local usings_json = p.get_usings_json()
|
||||
p.extract_externs(src)
|
||||
local externs_json = p.get_externs_json()
|
||||
local ast_json = p.parse_program2(src)
|
||||
local prefer = flags.prefer_cfg
|
||||
local prefer = prefer_cfg
|
||||
local jv0 = null
|
||||
if flags.v1_compat == 1 {
|
||||
if v1_compat == 1 {
|
||||
jv0 = FlowEntryBox.emit_v1_compat_from_ast_with_meta(ast_json, prefer, externs_json)
|
||||
}
|
||||
if jv0 == null || jv0 == "" {
|
||||
@ -77,9 +78,21 @@ static box StageBMain {
|
||||
if jv0 == null || jv0 == "" {
|
||||
jv0 = FlowEntryBox.emit_v0_from_ast(ast_json, prefer)
|
||||
}
|
||||
// Attach usings metadata when available(Stage-B pipeline consumes via resolver)
|
||||
if jv0 == null || jv0 == "" { jv0 = "{\"version\":0,\"kind\":\"Program\",\"body\":[{\"type\":\"Return\",\"expr\":{\"type\":\"Int\",\"value\":0}}]}" }
|
||||
print(jv0)
|
||||
if jv0 == null || jv0 == "" {
|
||||
jv0 = me._fallback_program()
|
||||
}
|
||||
return jv0
|
||||
}
|
||||
|
||||
main(args) {
|
||||
local flags = me._collect_flags(args)
|
||||
local src = flags.source
|
||||
local prefer = flags.prefer_cfg
|
||||
local stage3 = flags.stage3
|
||||
local v1_compat = flags.v1_compat
|
||||
local json = me._do_compile_stage_b(src, prefer, stage3, v1_compat)
|
||||
if json == null || json == "" { json = me._fallback_program() }
|
||||
print(json)
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,13 +13,13 @@ static box ParserExprBox {
|
||||
local at = pair.lastIndexOf("@")
|
||||
local json = pair.substring(0, at)
|
||||
local pos = i
|
||||
if at >= 0 { pos = ctx.to_int(pair.substring(at+1, pair.size())) }
|
||||
if at >= 0 { pos = ctx.to_int(pair.substring(at+1, pair.length())) }
|
||||
ctx.gpos_set(pos)
|
||||
return json
|
||||
}
|
||||
|
||||
parse_string2(src, i, ctx) {
|
||||
local n = src.size()
|
||||
local n = src.length()
|
||||
local j = i + 1
|
||||
local out = ""
|
||||
local guard = 0
|
||||
@ -57,7 +57,7 @@ static box ParserExprBox {
|
||||
|
||||
parse_factor2(src, i, ctx) {
|
||||
local j = ctx.skip_ws(src, i)
|
||||
if j >= src.size() {
|
||||
if j >= src.length() {
|
||||
ctx.gpos_set(j)
|
||||
return "{\"type\":\"Int\",\"value\":0}"
|
||||
}
|
||||
@ -116,13 +116,13 @@ static box ParserExprBox {
|
||||
local idp = ctx.read_ident2(src, p)
|
||||
local at = idp.lastIndexOf("@")
|
||||
local cls = idp.substring(0, at)
|
||||
local k = ctx.to_int(idp.substring(at+1, idp.size()))
|
||||
local k = ctx.to_int(idp.substring(at+1, idp.length()))
|
||||
k = ctx.skip_ws(src, k)
|
||||
if src.substring(k, k+1) == "(" { k = k + 1 }
|
||||
local args_and_pos = me.parse_args2(src, k, ctx)
|
||||
local at2 = args_and_pos.lastIndexOf("@")
|
||||
local args_json = args_and_pos.substring(0, at2)
|
||||
k = ctx.to_int(args_and_pos.substring(at2+1, args_and_pos.size()))
|
||||
k = ctx.to_int(args_and_pos.substring(at2+1, args_and_pos.length()))
|
||||
k = ctx.skip_ws(src, k)
|
||||
if src.substring(k, k+1) == ")" { k = k + 1 }
|
||||
ctx.gpos_set(k)
|
||||
@ -134,7 +134,7 @@ static box ParserExprBox {
|
||||
local idp = ctx.read_ident2(src, j)
|
||||
local at = idp.lastIndexOf("@")
|
||||
local name = idp.substring(0, at)
|
||||
local k = ctx.to_int(idp.substring(at+1, idp.size()))
|
||||
local k = ctx.to_int(idp.substring(at+1, idp.length()))
|
||||
local node = "{\"type\":\"Var\",\"name\":\"" + name + "\"}"
|
||||
local cont2 = 1
|
||||
|
||||
@ -147,7 +147,7 @@ static box ParserExprBox {
|
||||
local args_and_pos = me.parse_args2(src, k, ctx)
|
||||
local at2 = args_and_pos.lastIndexOf("@")
|
||||
local args_json = args_and_pos.substring(0, at2)
|
||||
k = ctx.to_int(args_and_pos.substring(at2+1, args_and_pos.size()))
|
||||
k = ctx.to_int(args_and_pos.substring(at2+1, args_and_pos.length()))
|
||||
k = ctx.skip_ws(src, k)
|
||||
if src.substring(k, k+1) == ")" { k = k + 1 }
|
||||
node = "{\"type\":\"Call\",\"name\":\"" + name + "\",\"args\":" + args_json + "}"
|
||||
@ -158,13 +158,13 @@ static box ParserExprBox {
|
||||
local midp = ctx.read_ident2(src, k)
|
||||
local at3 = midp.lastIndexOf("@")
|
||||
local mname = midp.substring(0, at3)
|
||||
k = ctx.to_int(midp.substring(at3+1, midp.size()))
|
||||
k = ctx.to_int(midp.substring(at3+1, midp.length()))
|
||||
k = ctx.skip_ws(src, k)
|
||||
if src.substring(k, k+1) == "(" { k = k + 1 }
|
||||
local args2 = me.parse_args2(src, k, ctx)
|
||||
local at4 = args2.lastIndexOf("@")
|
||||
local args_json2 = args2.substring(0, at4)
|
||||
k = ctx.to_int(args2.substring(at4+1, args2.size()))
|
||||
k = ctx.to_int(args2.substring(at4+1, args2.length()))
|
||||
k = ctx.skip_ws(src, k)
|
||||
if src.substring(k, k+1) == ")" { k = k + 1 }
|
||||
node = "{\"type\":\"Method\",\"recv\":" + node + ",\"method\":\"" + mname + "\",\"args\":" + args_json2 + "}"
|
||||
@ -201,7 +201,7 @@ static box ParserExprBox {
|
||||
|
||||
loop(cont == 1) {
|
||||
j = ctx.skip_ws(src, j)
|
||||
if j >= src.size() {
|
||||
if j >= src.length() {
|
||||
cont = 0
|
||||
} else {
|
||||
local op = src.substring(j, j+1)
|
||||
@ -226,7 +226,7 @@ static box ParserExprBox {
|
||||
|
||||
loop(cont == 1) {
|
||||
j = ctx.skip_ws(src, j)
|
||||
if j >= src.size() {
|
||||
if j >= src.length() {
|
||||
cont = 0
|
||||
} else {
|
||||
local op = src.substring(j, j+1)
|
||||
@ -301,7 +301,7 @@ static box ParserExprBox {
|
||||
j = ctx.skip_ws(src, j)
|
||||
local else_expr = me.parse_expr2(src, j, ctx)
|
||||
j = ctx.gpos_get()
|
||||
if else_expr.size() == 0 { else_expr = "{\"type\":\"Int\",\"value\":0}" }
|
||||
if else_expr.length() == 0 { else_expr = "{\"type\":\"Int\",\"value\":0}" }
|
||||
ctx.gpos_set(j)
|
||||
return "{\"type\":\"Ternary\",\"cond\":" + lhs + ",\"then\":" + then_expr + ",\"else\":" + else_expr + "}"
|
||||
}
|
||||
@ -312,7 +312,7 @@ static box ParserExprBox {
|
||||
|
||||
parse_args2(src, i, ctx) {
|
||||
local j = ctx.skip_ws(src, i)
|
||||
local n = src.size()
|
||||
local n = src.length()
|
||||
local out = "["
|
||||
j = ctx.skip_ws(src, j)
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
static box ParserLiteralBox {
|
||||
// Map literal: {"k": v, ...} (string keys only) → Call{name:"map.of", args:[Str(k1), v1, Str(k2), v2, ...]}
|
||||
parse_map(src, i, ctx) {
|
||||
local n = src.size()
|
||||
local n = src.length()
|
||||
local j = i + 1 // skip opening '{'
|
||||
local out = "["
|
||||
local first = 1
|
||||
@ -68,7 +68,7 @@ static box ParserLiteralBox {
|
||||
|
||||
// Array literal: [e1, e2, ...] → Call{name:"array.of", args:[...]}
|
||||
parse_array(src, i, ctx) {
|
||||
local n = src.size()
|
||||
local n = src.length()
|
||||
local j = i + 1 // skip opening '['
|
||||
local out = "["
|
||||
local first = 1
|
||||
|
||||
@ -7,7 +7,7 @@ static box ParserPeekBox {
|
||||
parse(src, i, ctx) {
|
||||
// ctx is ParserBox for delegation
|
||||
local j = i
|
||||
local n = src.size()
|
||||
local n = src.length()
|
||||
|
||||
// Parse scrutinee expression
|
||||
local scr = ctx.parse_expr2(src, j)
|
||||
|
||||
@ -44,7 +44,7 @@ box ParserBox {
|
||||
esc_json(s) {
|
||||
local out = ""
|
||||
local i = 0
|
||||
local n = s.size()
|
||||
local n = s.length()
|
||||
loop(i < n) {
|
||||
local ch = s.substring(i, i+1)
|
||||
if ch == "\\" { out = out + "\\\\" }
|
||||
@ -84,7 +84,7 @@ box ParserBox {
|
||||
local at = pair.lastIndexOf("@")
|
||||
local content = pair.substring(0, at)
|
||||
local pos = 0
|
||||
if at >= 0 { pos = me.to_int(pair.substring(at+1, pair.size())) }
|
||||
if at >= 0 { pos = me.to_int(pair.substring(at+1, pair.length())) }
|
||||
else { pos = i }
|
||||
me.gpos_set(pos)
|
||||
return content
|
||||
@ -93,7 +93,7 @@ box ParserBox {
|
||||
// === using system ===
|
||||
add_using(kind, target, alias) {
|
||||
local cur = me.usings_json
|
||||
if cur == null || cur.size() == 0 { cur = "[]" }
|
||||
if cur == null || cur.length() == 0 { cur = "[]" }
|
||||
|
||||
local name = ""
|
||||
local path = null
|
||||
@ -106,17 +106,17 @@ box ParserBox {
|
||||
local p = target
|
||||
local idx = -1
|
||||
local t = 0
|
||||
loop(t < p.size()) {
|
||||
loop(t < p.length()) {
|
||||
if p.substring(t,t+1) == "/" { idx = t }
|
||||
t = t + 1
|
||||
}
|
||||
if idx >= 0 { p = p.substring(idx+1, p.size()) }
|
||||
if idx >= 0 { p = p.substring(idx+1, p.length()) }
|
||||
|
||||
if p.size() > 5 && me.starts_with(p, p.size()-5, ".hako") == 1 {
|
||||
p = p.substring(0, p.size()-5)
|
||||
if p.length() > 5 && me.starts_with(p, p.length()-5, ".hako") == 1 {
|
||||
p = p.substring(0, p.length()-5)
|
||||
} else {
|
||||
if p.size() > 6 && me.starts_with(p, p.size()-6, ".nyash") == 1 {
|
||||
p = p.substring(0, p.size()-6)
|
||||
if p.length() > 6 && me.starts_with(p, p.length()-6, ".nyash") == 1 {
|
||||
p = p.substring(0, p.length()-6)
|
||||
}
|
||||
}
|
||||
name = p
|
||||
@ -163,7 +163,7 @@ box ParserBox {
|
||||
if func_name == null { func_name = "" }
|
||||
local entry = "{\"symbol\":\"" + me.esc_json(sym) + "\",\"func\":\"" + me.esc_json(func_name) + "\"}"
|
||||
local cur = me.externs_json
|
||||
if cur == null || cur.size() == 0 { cur = "[]" }
|
||||
if cur == null || cur.length() == 0 { cur = "[]" }
|
||||
if cur == "[]" {
|
||||
me.externs_json = "[" + entry + "]"
|
||||
return 0
|
||||
@ -188,20 +188,17 @@ box ParserBox {
|
||||
|
||||
// === Delegation to ParserExprBox ===
|
||||
parse_expr2(src, i) {
|
||||
local expr = new ParserExprBox()
|
||||
return expr.parse_expr2(src, i, me)
|
||||
return ParserExprBox.parse_expr2(src, i, me)
|
||||
}
|
||||
|
||||
// === Delegation to ParserStmtBox ===
|
||||
parse_stmt2(src, i) {
|
||||
local stmt = new ParserStmtBox()
|
||||
return stmt.parse(src, i, me)
|
||||
return ParserStmtBox.parse(src, i, me)
|
||||
}
|
||||
|
||||
// === Delegation to ParserControlBox ===
|
||||
parse_block2(src, i) {
|
||||
local ctrl = new ParserControlBox()
|
||||
return ctrl.parse_block(src, i, me)
|
||||
return ParserControlBox.parse_block(src, i, me)
|
||||
}
|
||||
|
||||
// === Top-level program parser ===
|
||||
@ -214,7 +211,7 @@ box ParserBox {
|
||||
loop(cont_prog == 1) {
|
||||
i = me.skip_ws(src, i)
|
||||
|
||||
if i >= src.size() {
|
||||
if i >= src.length() {
|
||||
cont_prog = 0
|
||||
} else {
|
||||
local start_i = i
|
||||
@ -223,8 +220,8 @@ box ParserBox {
|
||||
|
||||
// Progress guard
|
||||
if i <= start_i {
|
||||
if i < src.size() { i = i + 1 }
|
||||
else { i = src.size() }
|
||||
if i < src.length() { i = i + 1 }
|
||||
else { i = src.length() }
|
||||
me.gpos_set(i)
|
||||
}
|
||||
|
||||
@ -240,7 +237,7 @@ box ParserBox {
|
||||
local before2 = i
|
||||
i = me.skip_ws(src, i)
|
||||
|
||||
if i < src.size() && src.substring(i, i+1) == ";" {
|
||||
if i < src.length() && src.substring(i, i+1) == ";" {
|
||||
i = i + 1
|
||||
} else {
|
||||
done2 = 1
|
||||
@ -249,7 +246,7 @@ box ParserBox {
|
||||
if i == before2 { done2 = 1 }
|
||||
}
|
||||
|
||||
if s.size() > 0 {
|
||||
if s.length() > 0 {
|
||||
if first == 1 {
|
||||
body = body + s
|
||||
first = 0
|
||||
|
||||
@ -23,8 +23,8 @@ static box ParserCommonUtilsBox {
|
||||
dq() { return "\"" }
|
||||
|
||||
starts_with(src, i, pat) {
|
||||
local n = src.size()
|
||||
local m = pat.size()
|
||||
local n = src.length()
|
||||
local m = pat.length()
|
||||
if i + m > n { return 0 }
|
||||
local k = 0
|
||||
loop(k < m) {
|
||||
@ -35,8 +35,8 @@ static box ParserCommonUtilsBox {
|
||||
}
|
||||
|
||||
index_of(src, i, pat) {
|
||||
local n = src.size()
|
||||
local m = pat.size()
|
||||
local n = src.length()
|
||||
local m = pat.length()
|
||||
if m == 0 { return i }
|
||||
local j = i
|
||||
loop(j + m <= n) {
|
||||
@ -48,7 +48,7 @@ static box ParserCommonUtilsBox {
|
||||
|
||||
trim(s) {
|
||||
local i = 0
|
||||
local n = s.size()
|
||||
local n = s.length()
|
||||
loop(i < n && (s.substring(i,i+1) == " " || s.substring(i,i+1) == "\t")) { i = i + 1 }
|
||||
local j = n
|
||||
loop(j > i && (s.substring(j-1,j) == " " || s.substring(j-1,j) == "\t" || s.substring(j-1,j) == ";")) { j = j - 1 }
|
||||
@ -58,7 +58,7 @@ static box ParserCommonUtilsBox {
|
||||
esc_json(s) {
|
||||
local out = ""
|
||||
local i = 0
|
||||
local n = s.size()
|
||||
local n = s.length()
|
||||
loop(i < n) {
|
||||
local ch = s.substring(i, i+1)
|
||||
if ch == "\\" { out = out + "\\\\" }
|
||||
|
||||
@ -4,7 +4,7 @@ using lang.compiler.parser.scan.parser_string_utils_box as ParserStringUtilsBox
|
||||
static box ParserIdentScanBox {
|
||||
scan_ident(src, i) {
|
||||
local j = i
|
||||
local n = src.size()
|
||||
local n = src.length()
|
||||
if j >= n { return "@" + ParserStringUtilsBox.i2s(i) }
|
||||
// first char: alpha or '_'
|
||||
local ch = src.substring(j, j+1)
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
// ParserNumberScanBox — scan integer literal starting at index i
|
||||
// Returns: "{\"type\":\"Int\",\"value\":<digits>}@<pos>"
|
||||
|
||||
using lang.compiler.parser.scan.parser_common_utils_box as Utils
|
||||
using lang.compiler.parser.scan.parser_common_utils_box as ParserCommonUtilsBox
|
||||
|
||||
static box ParserNumberScanBox {
|
||||
scan_int(src, i) {
|
||||
if src == null { return "{\"type\":\"Int\",\"value\":0}@" + Utils.i2s(i) }
|
||||
local n = src.size()
|
||||
if src == null { return "{\"type\":\"Int\",\"value\":0}@" + ParserCommonUtilsBox.i2s(i) }
|
||||
local n = src.length()
|
||||
local j = i
|
||||
local cont = 1
|
||||
local guard = 0
|
||||
@ -15,12 +15,12 @@ static box ParserNumberScanBox {
|
||||
loop(cont == 1) {
|
||||
if guard > max { cont = 0 } else { guard = guard + 1 }
|
||||
if j < n {
|
||||
if Utils.is_digit(src.substring(j, j+1)) { j = j + 1 } else { cont = 0 }
|
||||
if ParserCommonUtilsBox.is_digit(src.substring(j, j+1)) { j = j + 1 } else { cont = 0 }
|
||||
} else { cont = 0 }
|
||||
}
|
||||
local s = src.substring(i, j)
|
||||
if s.size() == 0 { s = "0" }
|
||||
return "{\"type\":\"Int\",\"value\":" + s + "}@" + Utils.i2s(j)
|
||||
if s.length() == 0 { s = "0" }
|
||||
return "{\"type\":\"Int\",\"value\":" + s + "}@" + ParserCommonUtilsBox.i2s(j)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4,14 +4,14 @@
|
||||
// Returns: "<content>@<pos>" where <pos> is the index after the closing quote.
|
||||
// Notes: pure string scanning; no external deps.
|
||||
|
||||
using lang.compiler.parser.scan.parser_common_utils_box as Utils
|
||||
using lang.compiler.parser.scan.parser_common_utils_box as ParserCommonUtilsBox
|
||||
|
||||
static box ParserStringScanBox {
|
||||
scan(src, i) {
|
||||
if src == null { return "@" + Utils.i2s(i) }
|
||||
local n = src.size()
|
||||
if src == null { return "@" + ParserCommonUtilsBox.i2s(i) }
|
||||
local n = src.length()
|
||||
local j = i
|
||||
if j >= n || src.substring(j, j+1) != "\"" { return "@" + Utils.i2s(i) }
|
||||
if j >= n || src.substring(j, j+1) != "\"" { return "@" + ParserCommonUtilsBox.i2s(i) }
|
||||
j = j + 1
|
||||
local out = ""
|
||||
local guard = 0
|
||||
@ -21,7 +21,7 @@ static box ParserStringScanBox {
|
||||
local ch = src.substring(j, j+1)
|
||||
if ch == "\"" {
|
||||
j = j + 1
|
||||
return out + "@" + Utils.i2s(j)
|
||||
return out + "@" + ParserCommonUtilsBox.i2s(j)
|
||||
}
|
||||
if ch == "\\" && j + 1 < n {
|
||||
local nx = src.substring(j+1, j+2)
|
||||
@ -44,7 +44,7 @@ static box ParserStringScanBox {
|
||||
}
|
||||
}
|
||||
// if unterminated, return what we have and the last pos to avoid infinite loops
|
||||
return out + "@" + Utils.i2s(j)
|
||||
return out + "@" + ParserCommonUtilsBox.i2s(j)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
// Responsibility: Backward compatibility wrapper for parser code
|
||||
// Notes: All functionality now provided by apps/selfhost/common/string_helpers.hako
|
||||
|
||||
using "lang/src/shared/common/string_helpers.hako" as StringHelpers
|
||||
using sh_core as StringHelpers
|
||||
|
||||
static box ParserStringUtilsBox {
|
||||
// Delegate all methods to StringHelpers (centralized implementation)
|
||||
|
||||
@ -23,7 +23,7 @@ static box ParserControlBox {
|
||||
local then_res = me.parse_block(src, j, ctx)
|
||||
local at1 = then_res.lastIndexOf("@")
|
||||
local then_json = then_res.substring(0, at1)
|
||||
j = ctx.to_int(then_res.substring(at1+1, then_res.size()))
|
||||
j = ctx.to_int(then_res.substring(at1+1, then_res.length()))
|
||||
j = ctx.skip_ws(src, j)
|
||||
|
||||
local else_json = null
|
||||
@ -33,11 +33,11 @@ static box ParserControlBox {
|
||||
local else_res = me.parse_block(src, j, ctx)
|
||||
local at2 = else_res.lastIndexOf("@")
|
||||
else_json = else_res.substring(0, at2)
|
||||
j = ctx.to_int(else_res.substring(at2+1, else_res.size()))
|
||||
j = ctx.to_int(else_res.substring(at2+1, else_res.length()))
|
||||
}
|
||||
|
||||
if j <= stmt_start {
|
||||
if j < src.size() { j = j + 1 } else { j = src.size() }
|
||||
if j < src.length() { j = j + 1 } else { j = src.length() }
|
||||
}
|
||||
ctx.gpos_set(j)
|
||||
|
||||
@ -63,10 +63,10 @@ static box ParserControlBox {
|
||||
local body_res = me.parse_block(src, j, ctx)
|
||||
local at3 = body_res.lastIndexOf("@")
|
||||
local body_json = body_res.substring(0, at3)
|
||||
j = ctx.to_int(body_res.substring(at3+1, body_res.size()))
|
||||
j = ctx.to_int(body_res.substring(at3+1, body_res.length()))
|
||||
|
||||
if j <= stmt_start {
|
||||
if j < src.size() { j = j + 1 } else { j = src.size() }
|
||||
if j < src.length() { j = j + 1 } else { j = src.length() }
|
||||
}
|
||||
ctx.gpos_set(j)
|
||||
return "{\"type\":\"Loop\",\"cond\":" + cond + ",\"body\":" + body_json + "}"
|
||||
@ -79,14 +79,14 @@ static box ParserControlBox {
|
||||
if ctx.stage3_enabled() == 1 {
|
||||
j = ctx.skip_ws(src, j)
|
||||
if j <= stmt_start {
|
||||
if j < src.size() { j = j + 1 } else { j = src.size() }
|
||||
if j < src.length() { j = j + 1 } else { j = src.length() }
|
||||
}
|
||||
ctx.gpos_set(j)
|
||||
return "{\"type\":\"Break\"}"
|
||||
}
|
||||
|
||||
if j <= stmt_start {
|
||||
if j < src.size() { j = j + 1 } else { j = src.size() }
|
||||
if j < src.length() { j = j + 1 } else { j = src.length() }
|
||||
}
|
||||
ctx.gpos_set(j)
|
||||
return "{\"type\":\"Expr\",\"expr\":{\"type\":\"Int\",\"value\":0}}"
|
||||
@ -99,14 +99,14 @@ static box ParserControlBox {
|
||||
if ctx.stage3_enabled() == 1 {
|
||||
j = ctx.skip_ws(src, j)
|
||||
if j <= stmt_start {
|
||||
if j < src.size() { j = j + 1 } else { j = src.size() }
|
||||
if j < src.length() { j = j + 1 } else { j = src.length() }
|
||||
}
|
||||
ctx.gpos_set(j)
|
||||
return "{\"type\":\"Continue\"}"
|
||||
}
|
||||
|
||||
if j <= stmt_start {
|
||||
if j < src.size() { j = j + 1 } else { j = src.size() }
|
||||
if j < src.length() { j = j + 1 } else { j = src.length() }
|
||||
}
|
||||
ctx.gpos_set(j)
|
||||
return "{\"type\":\"Expr\",\"expr\":{\"type\":\"Int\",\"value\":0}}"
|
||||
@ -125,7 +125,7 @@ static box ParserControlBox {
|
||||
loop(cont_block == 1) {
|
||||
j = ctx.skip_ws(src, j)
|
||||
|
||||
if j >= src.size() {
|
||||
if j >= src.length() {
|
||||
cont_block = 0
|
||||
} else {
|
||||
if src.substring(j, j+1) == "}" {
|
||||
@ -138,7 +138,7 @@ static box ParserControlBox {
|
||||
|
||||
// Progress guard: ensure forward movement to avoid infinite loop on malformed input
|
||||
if j <= start_j {
|
||||
if j < src.size() { j = j + 1 } else { j = src.size() }
|
||||
if j < src.length() { j = j + 1 } else { j = src.length() }
|
||||
ctx.gpos_set(j)
|
||||
}
|
||||
|
||||
@ -150,11 +150,11 @@ static box ParserControlBox {
|
||||
if guard > max { done = 1 } else { guard = guard + 1 }
|
||||
local before = j
|
||||
j = ctx.skip_ws(src, j)
|
||||
if j < src.size() && src.substring(j, j+1) == ";" { j = j + 1 } else { done = 1 }
|
||||
if j < src.length() && src.substring(j, j+1) == ";" { j = j + 1 } else { done = 1 }
|
||||
if j == before { done = 1 }
|
||||
}
|
||||
|
||||
if s.size() > 0 {
|
||||
if s.length() > 0 {
|
||||
if first == 1 {
|
||||
body = body + s
|
||||
first = 0
|
||||
|
||||
@ -13,14 +13,14 @@ static box ParserExceptionBox {
|
||||
|
||||
if ctx.stage3_enabled() == 1 {
|
||||
if j <= stmt_start {
|
||||
if j < src.size() { j = j + 1 } else { j = src.size() }
|
||||
if j < src.length() { j = j + 1 } else { j = src.length() }
|
||||
}
|
||||
ctx.gpos_set(j)
|
||||
return "{\"type\":\"Throw\",\"expr\":" + e_throw + "}"
|
||||
}
|
||||
|
||||
if j <= stmt_start {
|
||||
if j < src.size() { j = j + 1 } else { j = src.size() }
|
||||
if j < src.length() { j = j + 1 } else { j = src.length() }
|
||||
}
|
||||
ctx.gpos_set(j)
|
||||
return "{\"type\":\"Expr\",\"expr\":" + e_throw + "}"
|
||||
@ -35,7 +35,7 @@ static box ParserExceptionBox {
|
||||
local try_res = ctx.parse_block2(src, j)
|
||||
local at_t = try_res.lastIndexOf("@")
|
||||
local try_json = try_res.substring(0, at_t)
|
||||
j = ctx.to_int(try_res.substring(at_t+1, try_res.size()))
|
||||
j = ctx.to_int(try_res.substring(at_t+1, try_res.length()))
|
||||
|
||||
local catches_json = "["
|
||||
local catch_first = 1
|
||||
@ -63,7 +63,7 @@ static box ParserExceptionBox {
|
||||
local id1 = ctx.read_ident2(src, j)
|
||||
local at1 = id1.lastIndexOf("@")
|
||||
catch_type = id1.substring(0, at1)
|
||||
j = ctx.to_int(id1.substring(at1+1, id1.size()))
|
||||
j = ctx.to_int(id1.substring(at1+1, id1.length()))
|
||||
j = ctx.skip_ws(src, j)
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ static box ParserExceptionBox {
|
||||
local id2 = ctx.read_ident2(src, j)
|
||||
local at2 = id2.lastIndexOf("@")
|
||||
catch_param = id2.substring(0, at2)
|
||||
j = ctx.to_int(id2.substring(at2+1, id2.size()))
|
||||
j = ctx.to_int(id2.substring(at2+1, id2.length()))
|
||||
j = ctx.skip_ws(src, j)
|
||||
}
|
||||
|
||||
@ -83,18 +83,18 @@ static box ParserExceptionBox {
|
||||
// catch body
|
||||
local c_res = ctx.parse_block2(src, j)
|
||||
local atc = c_res.lastIndexOf("@")
|
||||
j = ctx.to_int(c_res.substring(atc+1, c_res.size()))
|
||||
j = ctx.to_int(c_res.substring(atc+1, c_res.length()))
|
||||
|
||||
if ctx.stage3_enabled() == 1 {
|
||||
local entry = "{"
|
||||
local wrote = 0
|
||||
|
||||
if catch_param != null && catch_param.size() > 0 {
|
||||
if catch_param != null && catch_param.length() > 0 {
|
||||
entry = entry + "\"param\":\"" + ctx.esc_json(catch_param) + "\""
|
||||
wrote = 1
|
||||
}
|
||||
|
||||
if catch_type != null && catch_type.size() > 0 {
|
||||
if catch_type != null && catch_type.length() > 0 {
|
||||
if wrote == 1 { entry = entry + "," }
|
||||
entry = entry + "\"typeHint\":\"" + ctx.esc_json(catch_type) + "\""
|
||||
wrote = 1
|
||||
@ -127,13 +127,13 @@ static box ParserExceptionBox {
|
||||
j = ctx.skip_ws(src, j)
|
||||
local f_res = ctx.parse_block2(src, j)
|
||||
local atf = f_res.lastIndexOf("@")
|
||||
j = ctx.to_int(f_res.substring(atf+1, f_res.size()))
|
||||
j = ctx.to_int(f_res.substring(atf+1, f_res.length()))
|
||||
finally_json = f_res.substring(0, atf)
|
||||
}
|
||||
|
||||
if ctx.stage3_enabled() == 1 {
|
||||
if j <= stmt_start {
|
||||
if j < src.size() { j = j + 1 } else { j = src.size() }
|
||||
if j < src.length() { j = j + 1 } else { j = src.length() }
|
||||
}
|
||||
ctx.gpos_set(j)
|
||||
local node = "{\"type\":\"Try\",\"try\":" + try_json + ",\"catches\":" + catches_json
|
||||
@ -143,7 +143,7 @@ static box ParserExceptionBox {
|
||||
}
|
||||
|
||||
if j <= stmt_start {
|
||||
if j < src.size() { j = j + 1 } else { j = src.size() }
|
||||
if j < src.length() { j = j + 1 } else { j = src.length() }
|
||||
}
|
||||
ctx.gpos_set(j)
|
||||
return "{\"type\":\"Expr\",\"expr\":{\"type\":\"Int\",\"value\":0}}"
|
||||
|
||||
@ -15,32 +15,32 @@ static box ParserStmtBox {
|
||||
if ctx.starts_with(src, j, "@extern_c") == 1 {
|
||||
j = j + 9 // len("@extern_c")
|
||||
j = ctx.skip_ws(src, j)
|
||||
if j < src.size() && src.substring(j, j+1) == "(" { j = j + 1 }
|
||||
if j < src.length() && src.substring(j, j+1) == "(" { j = j + 1 }
|
||||
j = ctx.skip_ws(src, j)
|
||||
// First string literal: symbol
|
||||
local sym = ""
|
||||
if j < src.size() && src.substring(j, j+1) == "\"" {
|
||||
if j < src.length() && src.substring(j, j+1) == "\"" {
|
||||
sym = ctx.read_string_lit(src, j)
|
||||
j = ctx.gpos_get()
|
||||
}
|
||||
j = ctx.skip_ws(src, j)
|
||||
if j < src.size() && src.substring(j, j+1) == "," { j = j + 1 }
|
||||
if j < src.length() && src.substring(j, j+1) == "," { j = j + 1 }
|
||||
j = ctx.skip_ws(src, j)
|
||||
// Second string literal: func
|
||||
local fn = ""
|
||||
if j < src.size() && src.substring(j, j+1) == "\"" {
|
||||
fn = ctx.read_string_lit(src, j)
|
||||
local func_name = ""
|
||||
if j < src.length() && src.substring(j, j+1) == "\"" {
|
||||
func_name = ctx.read_string_lit(src, j)
|
||||
j = ctx.gpos_get()
|
||||
}
|
||||
// Skip to ')' if present
|
||||
j = ctx.skip_ws(src, j)
|
||||
if j < src.size() && src.substring(j, j+1) == ")" { j = j + 1 }
|
||||
if j < src.length() && src.substring(j, j+1) == ")" { j = j + 1 }
|
||||
// Optional semicolon is consumed by caller; still advance if present
|
||||
j = ctx.skip_ws(src, j)
|
||||
if j < src.size() && src.substring(j, j+1) == ";" { j = j + 1 }
|
||||
if j < src.length() && src.substring(j, j+1) == ";" { j = j + 1 }
|
||||
ctx.gpos_set(j)
|
||||
// Record annotation in parser context and emit no statement
|
||||
ctx.add_extern_c(sym, fn)
|
||||
ctx.add_extern_c(sym, func_name)
|
||||
return ""
|
||||
}
|
||||
|
||||
@ -50,23 +50,23 @@ static box ParserStmtBox {
|
||||
}
|
||||
|
||||
// assignment: IDENT '=' expr
|
||||
if j < src.size() && ctx.is_alpha(src.substring(j, j+1)) {
|
||||
if j < src.length() && ctx.is_alpha(src.substring(j, j+1)) {
|
||||
local idp0 = ctx.read_ident2(src, j)
|
||||
local at0 = idp0.lastIndexOf("@")
|
||||
if at0 > 0 {
|
||||
local name0 = idp0.substring(0, at0)
|
||||
local k0 = ctx.to_int(idp0.substring(at0+1, idp0.size()))
|
||||
local k0 = ctx.to_int(idp0.substring(at0+1, idp0.length()))
|
||||
k0 = ctx.skip_ws(src, k0)
|
||||
if k0 < src.size() && src.substring(k0, k0+1) == "=" {
|
||||
if k0 < src.length() && src.substring(k0, k0+1) == "=" {
|
||||
local eq_two = "="
|
||||
if k0 + 1 < src.size() { eq_two = src.substring(k0, k0+2) }
|
||||
if k0 + 1 < src.length() { eq_two = src.substring(k0, k0+2) }
|
||||
if eq_two != "==" {
|
||||
k0 = k0 + 1
|
||||
k0 = ctx.skip_ws(src, k0)
|
||||
local default_local = "{\"type\":\"Int\",\"value\":0}"
|
||||
local expr_json0 = default_local
|
||||
local end_pos0 = k0
|
||||
if k0 < src.size() {
|
||||
if k0 < src.length() {
|
||||
local ahead = src.substring(k0, k0+1)
|
||||
if ahead != "}" && ahead != ";" {
|
||||
expr_json0 = ctx.parse_expr2(src, k0)
|
||||
@ -75,7 +75,7 @@ static box ParserStmtBox {
|
||||
}
|
||||
k0 = end_pos0
|
||||
if k0 <= stmt_start {
|
||||
if k0 < src.size() { k0 = k0 + 1 } else { k0 = src.size() }
|
||||
if k0 < src.length() { k0 = k0 + 1 } else { k0 = src.length() }
|
||||
}
|
||||
ctx.gpos_set(k0)
|
||||
return "{\"type\":\"Local\",\"name\":\"" + name0 + "\",\"expr\":" + expr_json0 + "}"
|
||||
@ -91,7 +91,7 @@ static box ParserStmtBox {
|
||||
local default_ret = "{\"type\":\"Int\",\"value\":0}"
|
||||
local expr_json_ret = default_ret
|
||||
local end_pos_ret = j
|
||||
if j < src.size() {
|
||||
if j < src.length() {
|
||||
local ahead_ret = src.substring(j, j+1)
|
||||
if ahead_ret != "}" && ahead_ret != ";" {
|
||||
expr_json_ret = ctx.parse_expr2(src, j)
|
||||
@ -100,7 +100,7 @@ static box ParserStmtBox {
|
||||
}
|
||||
j = end_pos_ret
|
||||
if j <= stmt_start {
|
||||
if j < src.size() { j = j + 1 } else { j = src.size() }
|
||||
if j < src.length() { j = j + 1 } else { j = src.length() }
|
||||
}
|
||||
ctx.gpos_set(j)
|
||||
return "{\"type\":\"Return\",\"expr\":" + expr_json_ret + "}"
|
||||
@ -113,14 +113,14 @@ static box ParserStmtBox {
|
||||
local idp = ctx.read_ident2(src, j)
|
||||
local at = idp.lastIndexOf("@")
|
||||
local name = idp.substring(0, at)
|
||||
j = ctx.to_int(idp.substring(at+1, idp.size()))
|
||||
j = ctx.to_int(idp.substring(at+1, idp.length()))
|
||||
j = ctx.skip_ws(src, j)
|
||||
if j < src.size() && src.substring(j, j+1) == "=" { j = j + 1 }
|
||||
if j < src.length() && src.substring(j, j+1) == "=" { j = j + 1 }
|
||||
j = ctx.skip_ws(src, j)
|
||||
local default_local = "{\"type\":\"Int\",\"value\":0}"
|
||||
local expr_json_local = default_local
|
||||
local end_pos_local = j
|
||||
if j < src.size() {
|
||||
if j < src.length() {
|
||||
local ahead_local = src.substring(j, j+1)
|
||||
if ahead_local != "}" && ahead_local != ";" {
|
||||
expr_json_local = ctx.parse_expr2(src, j)
|
||||
@ -129,7 +129,7 @@ static box ParserStmtBox {
|
||||
}
|
||||
j = end_pos_local
|
||||
if j <= stmt_start {
|
||||
if j < src.size() { j = j + 1 } else { j = src.size() }
|
||||
if j < src.length() { j = j + 1 } else { j = src.length() }
|
||||
}
|
||||
ctx.gpos_set(j)
|
||||
return "{\"type\":\"Local\",\"name\":\"" + name + "\",\"expr\":" + expr_json_local + "}"
|
||||
@ -165,7 +165,7 @@ static box ParserStmtBox {
|
||||
local e = ctx.parse_expr2(src, j)
|
||||
j = ctx.gpos_get()
|
||||
if j <= expr_start {
|
||||
if j < src.size() { j = j + 1 } else { j = src.size() }
|
||||
if j < src.length() { j = j + 1 } else { j = src.length() }
|
||||
}
|
||||
ctx.gpos_set(j)
|
||||
return "{\"type\":\"Expr\",\"expr\":" + e + "}"
|
||||
@ -187,7 +187,7 @@ static box ParserStmtBox {
|
||||
local idp = ctx.read_ident2(src, j)
|
||||
local at = idp.lastIndexOf("@")
|
||||
alias = idp.substring(0, at)
|
||||
j = ctx.to_int(idp.substring(at+1, idp.size()))
|
||||
j = ctx.to_int(idp.substring(at+1, idp.length()))
|
||||
}
|
||||
ctx.add_using("path", p, alias)
|
||||
} else {
|
||||
@ -195,7 +195,7 @@ static box ParserStmtBox {
|
||||
local idp = ctx.read_ident2(src, j)
|
||||
local at = idp.lastIndexOf("@")
|
||||
local name = idp.substring(0, at)
|
||||
j = ctx.to_int(idp.substring(at+1, idp.size()))
|
||||
j = ctx.to_int(idp.substring(at+1, idp.length()))
|
||||
local cont = 1
|
||||
loop(cont == 1) {
|
||||
j = ctx.skip_ws(src, j)
|
||||
@ -205,7 +205,7 @@ static box ParserStmtBox {
|
||||
idp = ctx.read_ident2(src, j)
|
||||
at = idp.lastIndexOf("@")
|
||||
name = name + "." + idp.substring(0, at)
|
||||
j = ctx.to_int(idp.substring(at+1, idp.size()))
|
||||
j = ctx.to_int(idp.substring(at+1, idp.length()))
|
||||
} else {
|
||||
cont = 0
|
||||
}
|
||||
@ -218,7 +218,7 @@ static box ParserStmtBox {
|
||||
idp = ctx.read_ident2(src, j)
|
||||
at = idp.lastIndexOf("@")
|
||||
alias2 = idp.substring(0, at)
|
||||
j = ctx.to_int(idp.substring(at+1, idp.size()))
|
||||
j = ctx.to_int(idp.substring(at+1, idp.length()))
|
||||
}
|
||||
ctx.add_using("ns", name, alias2)
|
||||
}
|
||||
@ -226,7 +226,7 @@ static box ParserStmtBox {
|
||||
|
||||
// ensure progress
|
||||
if j <= stmt_start {
|
||||
if j < src.size() { j = j + 1 } else { j = src.size() }
|
||||
if j < src.length() { j = j + 1 } else { j = src.length() }
|
||||
}
|
||||
ctx.gpos_set(j)
|
||||
return ""
|
||||
|
||||
@ -6,14 +6,14 @@
|
||||
// - ParserBox.extract_usings delegates to this box (Phase 2 split)
|
||||
// - Pure string scan(依存ゼロ)。Fail‑Fastはせず、安全にスキップでループを進める
|
||||
|
||||
using lang.compiler.parser.scan.parser_common_utils_box as Utils
|
||||
using lang.compiler.parser.scan.parser_common_utils_box as ParserCommonUtilsBox
|
||||
|
||||
static box UsingCollectorBox {
|
||||
|
||||
// Public API: collect line-based using declarations to JSON array string
|
||||
collect(src) {
|
||||
if src == null { return "[]" }
|
||||
local n = src.size()
|
||||
local n = src.length()
|
||||
local i = 0
|
||||
local first = 1
|
||||
local out = "["
|
||||
@ -24,30 +24,30 @@ static box UsingCollectorBox {
|
||||
local line = src.substring(i, j)
|
||||
// trim left spaces/tabs
|
||||
local k = 0
|
||||
loop(k < line.size() && (line.substring(k,k+1) == " " || line.substring(k,k+1) == "\t")) { k = k + 1 }
|
||||
if Utils.starts_with(line, k, "using ") == 1 {
|
||||
local rest = Utils.trim(line.substring(k + 6, line.size()))
|
||||
loop(k < line.length() && (line.substring(k,k+1) == " " || line.substring(k,k+1) == "\t")) { k = k + 1 }
|
||||
if ParserCommonUtilsBox.starts_with(line, k, "using ") == 1 {
|
||||
local rest = ParserCommonUtilsBox.trim(line.substring(k + 6, line.length()))
|
||||
// split on ' as '
|
||||
local as_pos = Utils.index_of(rest, 0, " as ")
|
||||
local as_pos = ParserCommonUtilsBox.index_of(rest, 0, " as ")
|
||||
local target = rest
|
||||
local alias = null
|
||||
if as_pos >= 0 { target = Utils.trim(rest.substring(0, as_pos)) alias = Utils.trim(rest.substring(as_pos + 4, rest.size())) }
|
||||
if as_pos >= 0 { target = ParserCommonUtilsBox.trim(rest.substring(0, as_pos)) alias = ParserCommonUtilsBox.trim(rest.substring(as_pos + 4, rest.length())) }
|
||||
// path or namespace
|
||||
local is_path = 0
|
||||
if target.size() > 0 {
|
||||
if Utils.starts_with(target, 0, Utils.dq()) == 1 { is_path = 1 }
|
||||
if Utils.starts_with(target, 0, "./") == 1 { is_path = 1 }
|
||||
if Utils.starts_with(target, 0, "/") == 1 { is_path = 1 }
|
||||
if target.size() >= 5 && Utils.starts_with(target, target.size()-5, ".hako") == 1 { is_path = 1 }
|
||||
if target.size() >= 6 && Utils.starts_with(target, target.size()-6, ".nyash") == 1 { is_path = 1 }
|
||||
if target.length() > 0 {
|
||||
if ParserCommonUtilsBox.starts_with(target, 0, ParserCommonUtilsBox.dq()) == 1 { is_path = 1 }
|
||||
if ParserCommonUtilsBox.starts_with(target, 0, "./") == 1 { is_path = 1 }
|
||||
if ParserCommonUtilsBox.starts_with(target, 0, "/") == 1 { is_path = 1 }
|
||||
if target.length() >= 5 && ParserCommonUtilsBox.starts_with(target, target.length()-5, ".hako") == 1 { is_path = 1 }
|
||||
if target.length() >= 6 && ParserCommonUtilsBox.starts_with(target, target.length()-6, ".nyash") == 1 { is_path = 1 }
|
||||
}
|
||||
local name = ""
|
||||
local path = null
|
||||
if is_path == 1 {
|
||||
// strip quotes
|
||||
if Utils.starts_with(target, 0, Utils.dq()) == 1 {
|
||||
target = target.substring(1, target.size())
|
||||
if target.size() > 0 && target.substring(target.size()-1, target.size()) == Utils.dq() { target = target.substring(0, target.size()-1) }
|
||||
if ParserCommonUtilsBox.starts_with(target, 0, ParserCommonUtilsBox.dq()) == 1 {
|
||||
target = target.substring(1, target.length())
|
||||
if target.length() > 0 && target.substring(target.length()-1, target.length()) == ParserCommonUtilsBox.dq() { target = target.substring(0, target.length()-1) }
|
||||
}
|
||||
path = target
|
||||
if alias != null { name = alias } else {
|
||||
@ -55,11 +55,11 @@ static box UsingCollectorBox {
|
||||
local p = target
|
||||
local idx = -1
|
||||
local t = 0
|
||||
loop(t < p.size()) { if p.substring(t,t+1) == "/" { idx = t } t = t + 1 }
|
||||
if idx >= 0 { p = p.substring(idx+1, p.size()) }
|
||||
loop(t < p.length()) { if p.substring(t,t+1) == "/" { idx = t } t = t + 1 }
|
||||
if idx >= 0 { p = p.substring(idx+1, p.length()) }
|
||||
// strip extension
|
||||
if p.size() > 5 && Utils.starts_with(p, p.size()-5, ".hako") == 1 { p = p.substring(0, p.size()-5) }
|
||||
else { if p.size() > 6 && Utils.starts_with(p, p.size()-6, ".nyash") == 1 { p = p.substring(0, p.size()-6) } }
|
||||
if p.length() > 5 && ParserCommonUtilsBox.starts_with(p, p.length()-5, ".hako") == 1 { p = p.substring(0, p.length()-5) }
|
||||
else { if p.length() > 6 && ParserCommonUtilsBox.starts_with(p, p.length()-6, ".nyash") == 1 { p = p.substring(0, p.length()-6) } }
|
||||
name = p
|
||||
}
|
||||
} else {
|
||||
@ -67,8 +67,8 @@ static box UsingCollectorBox {
|
||||
}
|
||||
// append entry
|
||||
if first == 0 { out = out + "," } else { first = 0 }
|
||||
out = out + "{" + Utils.dq() + "name" + Utils.dq() + ":" + Utils.dq() + Utils.esc_json(name) + Utils.dq()
|
||||
if path != null { out = out + "," + Utils.dq() + "path" + Utils.dq() + ":" + Utils.dq() + Utils.esc_json(path) + Utils.dq() }
|
||||
out = out + "{" + ParserCommonUtilsBox.dq() + "name" + ParserCommonUtilsBox.dq() + ":" + ParserCommonUtilsBox.dq() + ParserCommonUtilsBox.esc_json(name) + ParserCommonUtilsBox.dq()
|
||||
if path != null { out = out + "," + ParserCommonUtilsBox.dq() + "path" + ParserCommonUtilsBox.dq() + ":" + ParserCommonUtilsBox.dq() + ParserCommonUtilsBox.esc_json(path) + ParserCommonUtilsBox.dq() }
|
||||
out = out + "}"
|
||||
}
|
||||
i = j + 1
|
||||
@ -77,4 +77,3 @@ static box UsingCollectorBox {
|
||||
return out
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -21,9 +21,9 @@ static box EmitCallBox {
|
||||
}
|
||||
_quote(s) {
|
||||
if s == null { return "\"\"" }
|
||||
local out = ""; local i = 0; local n = s.size()
|
||||
local out = ""; local i = 0; local n = s.length()
|
||||
loop (i < n) {
|
||||
local ch = call("String.substring/2", s, i, i+1)
|
||||
local ch = s.substring(i, i+1)
|
||||
if ch == "\\" { out = out + "\\\\" }
|
||||
else { if ch == "\"" { out = out + "\\\"" } else {
|
||||
if ch == "\n" { out = out + "\\n" } else {
|
||||
@ -56,9 +56,9 @@ static box EmitCallBox {
|
||||
if first == 1 { first = 0 } else { body = body + "," }
|
||||
body = body + "{\\\"op\\\":\\\"const\\\",\\\"dst\\\":" + EmitCallBox._to_str(vid) + ",\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":" + EmitCallBox._to_str(vv) + "}}"
|
||||
n = n + 1
|
||||
pos = pos + ds.size()
|
||||
pos = pos + ds.length()
|
||||
}
|
||||
if pos >= s.size() { break }
|
||||
if pos >= s.length() { break }
|
||||
}
|
||||
local dst = n + 1
|
||||
// mir_call (Extern)
|
||||
|
||||
@ -14,9 +14,9 @@ static box EmitCompareBox {
|
||||
}
|
||||
_quote(s) {
|
||||
if s == null { return "\"\"" }
|
||||
local out = ""; local i = 0; local n = s.size()
|
||||
local out = ""; local i = 0; local n = s.length()
|
||||
loop (i < n) {
|
||||
local ch = call("String.substring/2", s, i, i+1)
|
||||
local ch = s.substring(i, i+1)
|
||||
if ch == "\\" { out = out + "\\\\" }
|
||||
else { if ch == "\"" { out = out + "\\\"" } else {
|
||||
if ch == "\n" { out = out + "\\n" } else {
|
||||
|
||||
@ -16,9 +16,9 @@ static box EmitMethodBox {
|
||||
}
|
||||
_quote(s) {
|
||||
if s == null { return "\"\"" }
|
||||
local out = ""; local i = 0; local n = s.size()
|
||||
local out = ""; local i = 0; local n = s.length()
|
||||
loop (i < n) {
|
||||
local ch = call("String.substring/2", s, i, i+1)
|
||||
local ch = s.substring(i, i+1)
|
||||
if ch == "\\" { out = out + "\\\\" }
|
||||
else { if ch == "\"" { out = out + "\\\"" } else {
|
||||
if ch == "\n" { out = out + "\\n" } else {
|
||||
@ -52,9 +52,9 @@ static box EmitMethodBox {
|
||||
local vv = RegexFlow.to_int(ds)
|
||||
body = body + "," + "{\\\"op\\\":\\\"const\\\",\\\"dst\\\":" + EmitMethodBox._to_str(vid) + ",\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":" + EmitMethodBox._to_str(vv) + "}}"
|
||||
n = n + 1
|
||||
pos = pos + ds.size()
|
||||
pos = pos + ds.length()
|
||||
}
|
||||
if pos >= s.size() { break }
|
||||
if pos >= s.length() { break }
|
||||
}
|
||||
local dst = n + 2
|
||||
// mir_call (Method)
|
||||
|
||||
@ -43,7 +43,7 @@ box ExecutionPipelineBox {
|
||||
local ast = p.parse_program2(src)
|
||||
// Emit Stage‑1 JSON with meta.usings
|
||||
local json = EmitterBox.emit_program(ast, usings, externs)
|
||||
if json == null || json.size() == 0 { return 1 }
|
||||
if json == null || json.length() == 0 { return 1 }
|
||||
print(json)
|
||||
return 0
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ static box JsonMinifyBox {
|
||||
local s = "" + text
|
||||
local out = ""
|
||||
local i = 0
|
||||
local n = s.size()
|
||||
local n = s.length()
|
||||
local in_str = 0
|
||||
loop(i < n) {
|
||||
local ch = s.substring(i, i+1)
|
||||
|
||||
@ -19,7 +19,7 @@ static box LocalSSABox {
|
||||
if insts == null { return 1 }
|
||||
insts = me._maybe_unwrap_instructions(insts)
|
||||
if insts == null { return 1 }
|
||||
call("ArrayBox.push/2", insts, { op:"copy", dst: dst, src: src })
|
||||
insts.push({ op:"copy", dst: dst, src: src })
|
||||
return 0
|
||||
}
|
||||
|
||||
@ -43,20 +43,20 @@ static box LocalSSABox {
|
||||
local insert_at = i // phi 直後
|
||||
local node = { op:"copy", dst: dst, src: src }
|
||||
if insert_at >= n {
|
||||
call("ArrayBox.push/2", insts, node)
|
||||
insts.push(node)
|
||||
return 0
|
||||
}
|
||||
if n > 0 {
|
||||
call("ArrayBox.push/2", insts, BoxHelpers.array_get(insts, n - 1))
|
||||
insts.push(BoxHelpers.array_get(insts, n - 1))
|
||||
local j = n - 1
|
||||
loop (j >= insert_at) {
|
||||
call("ArrayBox.set/3", insts, j + 1, BoxHelpers.array_get(insts, j))
|
||||
insts.set(j + 1, BoxHelpers.array_get(insts, j))
|
||||
j = j - 1
|
||||
}
|
||||
call("ArrayBox.set/3", insts, insert_at, node)
|
||||
insts.set(insert_at, node)
|
||||
return 0
|
||||
}
|
||||
call("ArrayBox.push/2", insts, node)
|
||||
insts.push(node)
|
||||
return 0
|
||||
}
|
||||
|
||||
@ -97,19 +97,19 @@ static box LocalSSABox {
|
||||
// Do not cross terminator: insert before the first terminator if present
|
||||
if insert_at > term_at { insert_at = term_at }
|
||||
local node = { op:"copy", dst: dst, src: src }
|
||||
if insert_at >= n { call("ArrayBox.push/2", insts, node) return 0 }
|
||||
if insert_at >= n { insts.push(node) return 0 }
|
||||
// 1つ末尾に空きを作る(末尾要素を複製して押し出す)
|
||||
if n > 0 {
|
||||
call("ArrayBox.push/2", insts, BoxHelpers.array_get(insts, n - 1))
|
||||
insts.push(BoxHelpers.array_get(insts, n - 1))
|
||||
local j = n - 1
|
||||
loop (j >= insert_at) {
|
||||
call("ArrayBox.set/3", insts, j + 1, BoxHelpers.array_get(insts, j))
|
||||
insts.set(j + 1, BoxHelpers.array_get(insts, j))
|
||||
j = j - 1
|
||||
}
|
||||
call("ArrayBox.set/3", insts, insert_at, node)
|
||||
insts.set(insert_at, node)
|
||||
return 0
|
||||
}
|
||||
call("ArrayBox.push/2", insts, node)
|
||||
insts.push(node)
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ box MirBuilderBox {
|
||||
build(ast_json) {
|
||||
if ast_json == null { return EmitReturnBox.emit_return_int2(0, 0) }
|
||||
// If(cond=Compare) → CFG (branch/jump/ret)
|
||||
if call("String.indexOf/2", ast_json, "\"type\":\"If\"") >= 0 {
|
||||
if ast_json.indexOf("\"type\":\"If\"") >= 0 {
|
||||
local ic = Stage1ExtractFlow.extract_if_compare(ast_json)
|
||||
if ic != null { return EmitCompareBox.emit_compare_cfg3(BoxHelpers.map_get(ic, "lhs"), BoxHelpers.map_get(ic, "rhs"), BoxHelpers.map_get(ic, "cmp"), 0, 0) }
|
||||
}
|
||||
|
||||
@ -20,8 +20,8 @@ static box MirCallBox {
|
||||
// materialize const args r1..rN
|
||||
loop (true) {
|
||||
local ds = RegexFlow.digits_from(s, pos)
|
||||
if ds == "" { pos = pos + 1 } else { insts.push(MirEmitBox.make_const(1 + n, RegexFlow.to_int(ds))) n = n + 1 pos = pos + ds.size() }
|
||||
if pos >= s.size() { break }
|
||||
if ds == "" { pos = pos + 1 } else { insts.push(MirEmitBox.make_const(1 + n, RegexFlow.to_int(ds))) n = n + 1 pos = pos + ds.length() }
|
||||
if pos >= s.length() { break }
|
||||
}
|
||||
local dst = n + 1
|
||||
// args 1..n
|
||||
@ -46,8 +46,8 @@ static box MirCallBox {
|
||||
// materialize args r2..r(n+1)
|
||||
{ local i = 0 loop(true) {
|
||||
local ds = RegexFlow.digits_from(s, pos)
|
||||
if ds == "" { pos = pos + 1 } else { insts.push(MirEmitBox.make_const(2 + i, RegexFlow.to_int(ds))) i = i + 1 n = i pos = pos + ds.size() }
|
||||
if pos >= s.size() { break }
|
||||
if ds == "" { pos = pos + 1 } else { insts.push(MirEmitBox.make_const(2 + i, RegexFlow.to_int(ds))) i = i + 1 n = i pos = pos + ds.length() }
|
||||
if pos >= s.length() { break }
|
||||
}
|
||||
}
|
||||
local dst = n + 2
|
||||
@ -72,8 +72,8 @@ static box MirCallBox {
|
||||
// materialize args r1..rN
|
||||
{ local i = 0 loop(true) {
|
||||
local ds = RegexFlow.digits_from(s, pos)
|
||||
if ds == "" { pos = pos + 1 } else { insts.push(MirEmitBox.make_const(1 + i, RegexFlow.to_int(ds))) i = i + 1 n = i pos = pos + ds.size() }
|
||||
if pos >= s.size() { break }
|
||||
if ds == "" { pos = pos + 1 } else { insts.push(MirEmitBox.make_const(1 + i, RegexFlow.to_int(ds))) i = i + 1 n = i pos = pos + ds.length() }
|
||||
if pos >= s.length() { break }
|
||||
}
|
||||
}
|
||||
local dst = n + 1
|
||||
|
||||
@ -18,7 +18,7 @@ static box PipelineNameResolveBox {
|
||||
local dot2 = RegexFlow.find_from(raw_name, ".", 0)
|
||||
if dot2 < 0 { return null }
|
||||
local head2 = raw_name.substring(0, dot2)
|
||||
local tail2 = raw_name.substring(dot2 + 1, raw_name.size())
|
||||
local tail2 = raw_name.substring(dot2 + 1, raw_name.length())
|
||||
local ns2 = UsingResolverBox.resolve_namespace_alias(r_state, head2)
|
||||
if ns2 == null { ns2 = UsingResolverBox.guess_namespace_from_tail(r_state, head2) }
|
||||
if ns2 == null { return null }
|
||||
|
||||
@ -20,7 +20,7 @@ static box NamespaceBox {
|
||||
local pos = RegexFlow.find_from(s, ".", 0)
|
||||
if pos < 0 { return s }
|
||||
local head = s.substring(0, pos)
|
||||
local tail = s.substring(pos + 1, s.size())
|
||||
local tail = s.substring(pos + 1, s.length())
|
||||
if resolver_state == null { return s }
|
||||
local ns = UsingResolver.resolve_namespace_alias(resolver_state, head)
|
||||
if ns == null {
|
||||
@ -47,7 +47,7 @@ static box NamespaceBox {
|
||||
return null
|
||||
}
|
||||
local head = s.substring(0, pos)
|
||||
local tail = s.substring(pos + 1, s.size())
|
||||
local tail = s.substring(pos + 1, s.length())
|
||||
if resolver_state == null { return s }
|
||||
local ns2 = UsingResolver.resolve_namespace_alias(resolver_state, head)
|
||||
if ns2 == null {
|
||||
|
||||
@ -256,22 +256,31 @@ flow PipelineV2 {
|
||||
{
|
||||
local kq = RegexFlow.find_from(ast_json, "\"type\":\"Call\"", 0)
|
||||
if kq >= 0 {
|
||||
print("[flow] Call pattern: kq=" + kq)
|
||||
// Strict preflight via tolerant scanner: read raw name and enforce using alias resolution
|
||||
{
|
||||
local scan0 = Stage1JsonScannerBox.extract_name_args(ast_json, kq)
|
||||
if scan0 != null {
|
||||
if AliasPreflightBox.check_head(scan0.get("name"), r) != 1 { return null }
|
||||
print("[flow] Call scan0 name=" + scan0.get("name"))
|
||||
if AliasPreflightBox.check_head(scan0.get("name"), r) != 1 {
|
||||
print("[flow] Call AliasPreflightBox failed, returning null")
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local kc = CallExtractBox.extract_return_call_ints(ast_json)
|
||||
if kc != null {
|
||||
print("[flow] Call extract_return_call_ints succeeded")
|
||||
local kn = NormalizerBox.normalize_call_ints(kc)
|
||||
if kn == null { return null }
|
||||
if SignatureVerifierBox.verify_call_name_arity(kn.get("name"), kn.get("args")) != 1 { return null }
|
||||
if kn == null { print("[flow] Call normalize_call_ints returned null") return null }
|
||||
if SignatureVerifierBox.verify_call_name_arity(kn.get("name"), kn.get("args")) != 1 { print("[flow] Call verify_call_name_arity failed") return null }
|
||||
local j4 = EmitCallBox.emit_call_int_args(kn.get("name"), kn.get("args"))
|
||||
if j4 == null { return null }
|
||||
if j4 == null { print("[flow] Call emit_call_int_args returned null") return null }
|
||||
print("[flow] Call path 1 succeeded, returning JSON")
|
||||
return LocalSSA.ensure_calls(LocalSSA.ensure_cond(j4))
|
||||
} else {
|
||||
print("[flow] Call extract_return_call_ints returned null, trying scanner fallback")
|
||||
}
|
||||
// Fallback: scanner → normalizer → emit
|
||||
{
|
||||
|
||||
@ -40,7 +40,7 @@ static box PipelineHelpersBox {
|
||||
parse_int_after_prefix(s, prefix, search_pos) {
|
||||
local p = RegexFlow.find_from(s, prefix, search_pos)
|
||||
if p < 0 { return null }
|
||||
local res = PipelineHelpersBox.parse_int_at(s, p + prefix.size())
|
||||
local res = PipelineHelpersBox.parse_int_at(s, p + prefix.length())
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ static box ReadOnlyMapView {
|
||||
return v
|
||||
}
|
||||
|
||||
has(key) { return call("MapBox.has/2", me._m, key) }
|
||||
has(key) { return me._m.has(key) }
|
||||
get(key) { return BoxHelpers.map_get(me._m, key) }
|
||||
|
||||
set(key, val) {
|
||||
|
||||
@ -55,8 +55,8 @@ flow RegexFlow {
|
||||
if s == null { return -1 }
|
||||
if needle == null { return -1 }
|
||||
if pos < 0 { pos = 0 }
|
||||
local n = s.size()
|
||||
local m = needle.size()
|
||||
local n = s.length()
|
||||
local m = needle.length()
|
||||
if m == 0 { return pos }
|
||||
local i = pos
|
||||
local limit = n - m
|
||||
@ -75,7 +75,7 @@ flow RegexFlow {
|
||||
|
||||
to_int(digits) {
|
||||
if digits == null { return 0 }
|
||||
local n = digits.size()
|
||||
local n = digits.length()
|
||||
if n == 0 { return 0 }
|
||||
local i = 0
|
||||
local neg = 0
|
||||
|
||||
@ -62,9 +62,9 @@ static box SignatureVerifierBox {
|
||||
n = n + 1
|
||||
// advance to the end of this digit run
|
||||
local p2 = RegexFlow.find_from(s, ds, pos)
|
||||
if p2 < 0 { pos = pos + ds.size() } else { pos = p2 + ds.size() }
|
||||
if p2 < 0 { pos = pos + ds.length() } else { pos = p2 + ds.length() }
|
||||
}
|
||||
if pos >= s.size() { break }
|
||||
if pos >= s.length() { break }
|
||||
}
|
||||
return n
|
||||
}
|
||||
@ -89,13 +89,13 @@ static box SignatureVerifierBox {
|
||||
// Split at last '.' for method name
|
||||
local last = RegexFlow.last_index_of(s, ".")
|
||||
if last < 0 { return 1 }
|
||||
local method = s.substring(last + 1, s.size())
|
||||
local method = s.substring(last + 1, s.length())
|
||||
// Determine class token just before method (penultimate segment)
|
||||
local head_all = s.substring(0, last)
|
||||
local prev = RegexFlow.last_index_of(head_all, ".")
|
||||
local head = head_all
|
||||
if prev >= 0 {
|
||||
head = head_all.substring(prev + 1, head_all.size())
|
||||
head = head_all.substring(prev + 1, head_all.length())
|
||||
}
|
||||
// Normalize head to Box name
|
||||
local bxname = head
|
||||
|
||||
@ -14,8 +14,8 @@ static box Stage1ArgsParserBox {
|
||||
local n = 0
|
||||
loop(true) {
|
||||
local ds = RegexFlow.digits_from(s, pos)
|
||||
if ds == "" { pos = pos + 1 } else { n = n + 1 pos = pos + ds.size() }
|
||||
if pos >= s.size() { break }
|
||||
if ds == "" { pos = pos + 1 } else { n = n + 1 pos = pos + ds.length() }
|
||||
if pos >= s.length() { break }
|
||||
}
|
||||
return n
|
||||
}
|
||||
@ -34,9 +34,9 @@ static box Stage1ArgsParserBox {
|
||||
out.push(RegexFlow.to_int(ds))
|
||||
// advance to end of this token to avoid re-matching
|
||||
local p2 = RegexFlow.find_from(s, ds, pos)
|
||||
if p2 < 0 { pos = pos + ds.size() } else { pos = p2 + ds.size() }
|
||||
if p2 < 0 { pos = pos + ds.length() } else { pos = p2 + ds.length() }
|
||||
}
|
||||
if pos >= s.size() { break }
|
||||
if pos >= s.length() { break }
|
||||
}
|
||||
return out
|
||||
}
|
||||
@ -46,7 +46,7 @@ static box Stage1ArgsParserBox {
|
||||
local lb = JsonCursorBox.find_from(s, "[", 0)
|
||||
if lb < 0 { return 1 }
|
||||
local rb = JsonCursorBox.seek_array_end(s, lb)
|
||||
if rb < 0 { rb = s.size() }
|
||||
if rb < 0 { rb = s.length() }
|
||||
local chk = RegexFlow.find_from(s, "\"type\":\"", lb)
|
||||
if chk < 0 || chk >= rb { return 1 }
|
||||
local pos = chk
|
||||
|
||||
@ -125,7 +125,7 @@ flow Stage1ExtractFlow {
|
||||
local args = []
|
||||
if ak >= 0 {
|
||||
local rb = Stage1ExtractFlow._idx_from(ast_json, "]", ak)
|
||||
if rb < 0 { rb = ast_json.size() }
|
||||
if rb < 0 { rb = ast_json.length() }
|
||||
local i = ak
|
||||
loop(true) {
|
||||
local tpos = Stage1ExtractFlow._idx_from(ast_json, "\"type\":\"Int\"", i)
|
||||
@ -134,7 +134,7 @@ flow Stage1ExtractFlow {
|
||||
if vpos < 0 || vpos >= rb { i = tpos + 1 continue }
|
||||
local ds = RegexFlow.digits_from(ast_json, vpos + 8)
|
||||
if ds != "" { args.push(RegexFlow.to_int(ds)) }
|
||||
i = vpos + 8 + ds.size()
|
||||
i = vpos + 8 + ds.length()
|
||||
}
|
||||
}
|
||||
return { method: mname, args: args }
|
||||
@ -158,7 +158,7 @@ flow Stage1ExtractFlow {
|
||||
local args = []
|
||||
if ak >= 0 {
|
||||
local rb = Stage1ExtractFlow._idx_from(ast_json, "]", ak)
|
||||
if rb < 0 { rb = ast_json.size() }
|
||||
if rb < 0 { rb = ast_json.length() }
|
||||
local i = ak
|
||||
loop(true) {
|
||||
local tpos = Stage1ExtractFlow._idx_from(ast_json, "\"type\":\"Int\"", i)
|
||||
@ -167,7 +167,7 @@ flow Stage1ExtractFlow {
|
||||
if vpos < 0 || vpos >= rb { i = tpos + 1 continue }
|
||||
local ds = RegexFlow.digits_from(ast_json, vpos + 8)
|
||||
if ds != "" { args.push(RegexFlow.to_int(ds)) }
|
||||
i = vpos + 8 + ds.size()
|
||||
i = vpos + 8 + ds.length()
|
||||
}
|
||||
}
|
||||
return { class: cname, args: args }
|
||||
@ -192,7 +192,7 @@ flow Stage1ExtractFlow {
|
||||
local ak = Stage1ExtractFlow._idx_from(ast_json, "\"args\":[", q)
|
||||
if ak < 0 { return { name: name, args: [] } }
|
||||
local rb = Stage1ExtractFlow._idx_from(ast_json, "]", ak)
|
||||
if rb < 0 { rb = ast_json.size() }
|
||||
if rb < 0 { rb = ast_json.length() }
|
||||
local args = []
|
||||
local i = ak
|
||||
loop(true) {
|
||||
@ -202,7 +202,7 @@ flow Stage1ExtractFlow {
|
||||
if vpos < 0 || vpos >= rb { i = tpos + 1 continue }
|
||||
local ds = RegexFlow.digits_from(ast_json, vpos + 8)
|
||||
if ds != "" { args.push(RegexFlow.to_int(ds)) }
|
||||
i = vpos + 8 + ds.size()
|
||||
i = vpos + 8 + ds.length()
|
||||
}
|
||||
return { name: name, args: args }
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ static box Stage1IntArgsExtractBox {
|
||||
|
||||
// bracket-aware end detection
|
||||
local lb = RegexFlow.find_from(ast_json, "[", ak)
|
||||
local rb = ast_json.size()
|
||||
local rb = ast_json.length()
|
||||
if lb >= 0 {
|
||||
local i2 = lb + 1
|
||||
local depth = 1
|
||||
@ -63,7 +63,7 @@ static box Stage1IntArgsExtractBox {
|
||||
if vpos < 0 || vpos >= rb { i = tpos + 1 continue }
|
||||
local ds = RegexFlow.digits_from(ast_json, vpos + 8)
|
||||
if ds != "" { vals.push(RegexFlow.to_int(ds)) }
|
||||
i = vpos + 8 + ds.size()
|
||||
i = vpos + 8 + ds.length()
|
||||
}
|
||||
return vals
|
||||
}
|
||||
@ -90,7 +90,7 @@ static box Stage1IntArgsExtractBox {
|
||||
if ak < 0 { return 1 }
|
||||
local lb = RegexFlow.find_from(ast_json, "[", ak)
|
||||
if lb < 0 { return 1 }
|
||||
local rb = ast_json.size()
|
||||
local rb = ast_json.length()
|
||||
local i2 = lb + 1
|
||||
local depth = 1
|
||||
loop(true) {
|
||||
|
||||
@ -25,16 +25,16 @@ static box Stage1JsonScannerBox {
|
||||
local escaped = "\\\"" + key + "\\\":\\\""
|
||||
local p1 = JsonCursorBox.find_key_dual(s, plain, escaped, start_pos)
|
||||
if p1 >= 0 { return p1 }
|
||||
if plain.size() >= 2 {
|
||||
local head = plain.substring(0, plain.size() - 1)
|
||||
local last = plain.substring(plain.size() - 1, plain.size())
|
||||
if plain.length() >= 2 {
|
||||
local head = plain.substring(0, plain.length() - 1)
|
||||
local last = plain.substring(plain.length() - 1, plain.length())
|
||||
local spaced = head + " " + last
|
||||
local p2 = JsonCursorBox.find_from(s, spaced, start_pos)
|
||||
if p2 >= 0 { return p2 }
|
||||
// Escaped + spaced: tolerate JSON embedded as string with colon-space
|
||||
if escaped.size() >= 2 {
|
||||
local ehead = escaped.substring(0, escaped.size() - 1)
|
||||
local elast = escaped.substring(escaped.size() - 1, escaped.size())
|
||||
if escaped.length() >= 2 {
|
||||
local ehead = escaped.substring(0, escaped.length() - 1)
|
||||
local elast = escaped.substring(escaped.length() - 1, escaped.length())
|
||||
local espaced = ehead + " " + elast
|
||||
local p3 = JsonCursorBox.find_from(s, espaced, start_pos)
|
||||
if p3 >= 0 { return p3 }
|
||||
@ -46,7 +46,7 @@ static box Stage1JsonScannerBox {
|
||||
value_start_after_key_pos(s, key_pos) {
|
||||
if s == null { return -1 }
|
||||
local i = key_pos
|
||||
local n = s.size()
|
||||
local n = s.length()
|
||||
loop(i < n) {
|
||||
local ch = s.substring(i,i+1)
|
||||
if ch == ":" { i = i + 1 break }
|
||||
@ -77,21 +77,21 @@ static box Stage1JsonScannerBox {
|
||||
if nend <= vstart { return null }
|
||||
local label = s.substring(vstart, nend)
|
||||
local lb = JsonCursorBox.find_from(s, "[", apos)
|
||||
local rb = s.size()
|
||||
local rb = s.length()
|
||||
if lb >= 0 {
|
||||
// Use JsonCursorBox for escape-aware array end seeking
|
||||
local rb_result = JsonCursorBox.seek_array_end(s, lb)
|
||||
if rb_result >= lb { rb = rb_result }
|
||||
}
|
||||
local args_text = s.substring(apos, rb)
|
||||
return map({ label: label, args_text: args_text, label_pos: npos, args_pos: apos, label_key: label_key })
|
||||
return { label: label, args_text: args_text, label_pos: npos, args_pos: apos, label_key: label_key }
|
||||
}
|
||||
|
||||
// Backward compatible helper for Call (label_key = "name")
|
||||
extract_name_args(ast_json, start_pos) {
|
||||
local m = me.extract_label_args(ast_json, "name", start_pos)
|
||||
if m == null { return null }
|
||||
call("MapBox.set/3", m, "name", BoxHelpers.map_get(m, "label"))
|
||||
m.set("name", BoxHelpers.map_get(m, "label"))
|
||||
return m
|
||||
}
|
||||
}
|
||||
|
||||
@ -33,16 +33,16 @@ static box UsingResolverBox {
|
||||
local key = s.substring(kpos + 1, kend)
|
||||
local dot = RegexFlow.last_index_of(key, ".")
|
||||
local last = key
|
||||
if dot >= 0 { last = key.substring(dot + 1, key.size()) }
|
||||
if dot >= 0 { last = key.substring(dot + 1, key.length()) }
|
||||
if last == alias {
|
||||
if found == null { found = key } else { return null }
|
||||
} else {
|
||||
// first-letter case-insensitive match
|
||||
if last.size() == alias.size() && last.size() > 0 {
|
||||
if last.length() == alias.length() && last.length() > 0 {
|
||||
local l0 = last.substring(0,1)
|
||||
local a0 = alias.substring(0,1)
|
||||
local restl = last.substring(1, last.size())
|
||||
local resta = alias.substring(1, alias.size())
|
||||
local restl = last.substring(1, last.length())
|
||||
local resta = alias.substring(1, alias.length())
|
||||
if restl == resta {
|
||||
local U = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; local L = "abcdefghijklmnopqrstuvwxyz"
|
||||
local idxL = L.indexOf(l0); local idxU = U.indexOf(l0)
|
||||
|
||||
@ -16,10 +16,10 @@ static box JsonProgramBox {
|
||||
ensure_meta(json, usings_json, externs_json) {
|
||||
local payload = usings_json
|
||||
if payload == null { payload = "[]" }
|
||||
if payload.size() == 0 { payload = "[]" }
|
||||
if payload.length() == 0 { payload = "[]" }
|
||||
local ext = externs_json
|
||||
if ext == null { ext = "[]" }
|
||||
if ext.size() == 0 { ext = "[]" }
|
||||
if ext.length() == 0 { ext = "[]" }
|
||||
|
||||
if json == null {
|
||||
return "{\"version\":0,\"kind\":\"Program\",\"body\":[],\"meta\":{\"usings\":" + payload + ",\"extern_c\":" + ext + "}}"
|
||||
@ -28,11 +28,11 @@ static box JsonProgramBox {
|
||||
local n = json.lastIndexOf("}")
|
||||
if n < 0 { return json }
|
||||
local head = json.substring(0, n)
|
||||
local tail = json.substring(n, json.size())
|
||||
local tail = json.substring(n, json.length())
|
||||
local needs_comma = 1
|
||||
if head.size() == 0 { needs_comma = 0 }
|
||||
if head.length() == 0 { needs_comma = 0 }
|
||||
else {
|
||||
local last = head.substring(head.size() - 1, head.size())
|
||||
local last = head.substring(head.length() - 1, head.length())
|
||||
if last == "{" || last == "," { needs_comma = 0 }
|
||||
}
|
||||
if needs_comma == 1 { head = head + "," }
|
||||
@ -78,11 +78,11 @@ static box JsonProgramBox {
|
||||
|
||||
_replace_all(text, pat, rep) {
|
||||
if text == null { return text }
|
||||
local m = pat.size()
|
||||
local m = pat.length()
|
||||
if m == 0 { return text }
|
||||
local out = ""
|
||||
local i = 0
|
||||
local n = text.size()
|
||||
local n = text.length()
|
||||
loop(i < n) {
|
||||
if StringHelpers.starts_with(text, i, pat) == 1 {
|
||||
out = out + rep
|
||||
@ -100,18 +100,18 @@ static box JsonProgramBox {
|
||||
normalize_stmt_array(array_json) {
|
||||
if array_json == null { return "[]" }
|
||||
local trimmed = me.trim(array_json)
|
||||
if trimmed.size() == 0 { return "[]" }
|
||||
if trimmed.length() == 0 { return "[]" }
|
||||
if trimmed == "null" { return "[]" }
|
||||
if trimmed.size() < 2 { return "[]" }
|
||||
if trimmed.length() < 2 { return "[]" }
|
||||
if trimmed.substring(0, 1) != "[" { return trimmed }
|
||||
if trimmed == "[]" { return "[]" }
|
||||
|
||||
local parts = JsonUtilsBox.split_top_level(trimmed)
|
||||
local out = new ArrayBox()
|
||||
local i = 0
|
||||
loop(i < parts.size()) {
|
||||
loop(i < parts.length()) {
|
||||
local item = me.trim(parts.get(i))
|
||||
if item.size() > 0 {
|
||||
if item.length() > 0 {
|
||||
out.push(me.normalize_stmt(item))
|
||||
}
|
||||
i = i + 1
|
||||
@ -185,18 +185,18 @@ static box JsonProgramBox {
|
||||
normalize_expr_array(array_json) {
|
||||
if array_json == null { return "[]" }
|
||||
local trimmed = me.trim(array_json)
|
||||
if trimmed.size() == 0 { return "[]" }
|
||||
if trimmed.length() == 0 { return "[]" }
|
||||
if trimmed == "null" { return "[]" }
|
||||
if trimmed.size() < 2 { return "[]" }
|
||||
if trimmed.length() < 2 { return "[]" }
|
||||
if trimmed.substring(0, 1) != "[" { return trimmed }
|
||||
if trimmed == "[]" { return "[]" }
|
||||
|
||||
local parts = JsonUtilsBox.split_top_level(trimmed)
|
||||
local out = new ArrayBox()
|
||||
local i = 0
|
||||
loop(i < parts.size()) {
|
||||
loop(i < parts.length()) {
|
||||
local item = me.trim(parts.get(i))
|
||||
if item.size() > 0 {
|
||||
if item.length() > 0 {
|
||||
local norm = me.normalize_expr(item)
|
||||
if norm == null { norm = item }
|
||||
out.push(norm)
|
||||
@ -294,19 +294,19 @@ static box JsonProgramBox {
|
||||
|
||||
_trim_all(text) {
|
||||
if text == null { return "" }
|
||||
local n = text.size()
|
||||
local n = text.length()
|
||||
local start = 0
|
||||
loop(start < n) {
|
||||
local ch = call("String.substring/2", text, start, start + 1)
|
||||
local ch = text.substring(start, start + 1)
|
||||
if ch == " " || ch == "\t" || ch == "\n" || ch == "\r" { start = start + 1 } else { break }
|
||||
}
|
||||
local end_idx = n
|
||||
loop(end_idx > start) {
|
||||
local ch2 = call("String.substring/2", text, end_idx - 1, end_idx)
|
||||
local ch2 = text.substring(end_idx - 1, end_idx)
|
||||
if ch2 == " " || ch2 == "\t" || ch2 == "\n" || ch2 == "\r" || ch2 == ";" { end_idx = end_idx - 1 } else { break }
|
||||
}
|
||||
if end_idx <= start { return "" }
|
||||
local part = call("String.substring/2", text, start, end_idx)
|
||||
local part = text.substring(start, end_idx)
|
||||
if part == null { return "" }
|
||||
return part
|
||||
}
|
||||
@ -318,7 +318,7 @@ static box JsonProgramBox {
|
||||
if parts == null { return "" }
|
||||
local out = ""
|
||||
local i = 0
|
||||
local n = parts.size()
|
||||
local n = parts.length()
|
||||
loop(i < n) {
|
||||
local item = parts.get(i)
|
||||
if i == 0 { out = out + item } else { out = out + "," + item }
|
||||
|
||||
Reference in New Issue
Block a user