## ✅ Fixed Issues ### 1. `local` keyword tokenization (commit 9aab64f7) - Added Stage-3 gate for LOCAL/TRY/CATCH/THROW keywords - LOCAL now only active when NYASH_PARSER_STAGE3=1 ### 2. `env.local.get` keyword conflict - File: `lang/src/compiler/entry/compiler_stageb.hako:21-23` - Problem: `.local` in member access tokenized as `.LOCAL` keyword - Fix: Commented out `env.local.get("HAKO_SOURCE")` line - Fallback: Use `--source` argument (still functional) ### 3. `flow` keyword missing - Added FLOW to TokenType enum (`src/tokenizer/kinds.rs`) - Added "flow" → TokenType::FLOW mapping (`src/tokenizer/lex_ident.rs`) - Added FLOW to Stage-3 gate (requires NYASH_PARSER_STAGE3=1) - Added FLOW to parser statement dispatch (`src/parser/statements/mod.rs`) - Added FLOW to declaration handler (`src/parser/statements/declarations.rs`) - Updated box_declaration parser to accept BOX or FLOW (`src/parser/declarations/box_definition.rs`) - Treat `flow FooBox {}` as syntactic sugar for `box FooBox {}` ### 4. Module namespace conversion - Renamed `lang.compiler.builder.ssa.local` → `localvar` (avoid keyword) - Renamed file `local.hako` → `local_ssa.hako` - Converted 152 path-based using statements to namespace format - Added 26+ entries to `nyash.toml` [modules] section ## ⚠️ Remaining Issues ### Stage-B selfhost compiler performance - Stage-B compiler not producing output (hangs/times out after 10+ seconds) - Excessive PHI debug output suggests compilation loop issue - Needs investigation: infinite loop or N² algorithm in hako compiler ### Fallback JSON version mismatch - Rust fallback (`--emit-mir-json`) emits MIR v1 JSON (schema_version: "1.0") - Smoke tests expect MIR v0 JSON (`"version":0, "kind":"Program"`) - stageb_helpers.sh fallback needs adjustment ## Test Status - Parse errors: FIXED ✅ - Keyword conflicts: FIXED ✅ - Stage-B smoke tests: STILL FAILING ❌ (performance issue) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
120 lines
4.5 KiB
Plaintext
120 lines
4.5 KiB
Plaintext
// CompareExtractBox — Stage‑1 JSON から Compare(lhs,rhs,op) を堅牢に抽出(整数のみ)
|
||
using lang.compiler.pipeline_v2.regex_flow as RegexFlow
|
||
using selfhost.shared.common.box_helpers as BoxHelpers
|
||
|
||
static box CompareExtractBox {
|
||
// --- internal helpers (range & safe find) ---
|
||
_find_brace_range(s, around_pos) {
|
||
// Find object range that contains around_pos: search '{' backwards, then match '}' by depth
|
||
if around_pos < 0 { return null }
|
||
local start = around_pos
|
||
loop (start >= 0) {
|
||
local ch = s.substring(start, start+1)
|
||
if ch == "{" { break }
|
||
start = start - 1
|
||
}
|
||
if start < 0 { return null }
|
||
local i = start
|
||
local depth = 0
|
||
loop(true) {
|
||
local ch2 = s.substring(i, i+1)
|
||
if ch2 == "" { break }
|
||
if ch2 == "{" { depth = depth + 1 } else { if ch2 == "}" { depth = depth - 1 } }
|
||
if depth == 0 { return { "from": start, "to": i + 1 } }
|
||
i = i + 1
|
||
}
|
||
return null
|
||
}
|
||
_find_in_range(s, needle, start, endp) {
|
||
local p = RegexFlow.find_from(s, needle, start)
|
||
if p < 0 { return -1 }
|
||
if p >= endp { return -1 }
|
||
return p
|
||
}
|
||
// Returns MapBox {"cmp": String, "lhs": Int, "rhs": Int } or null when not found
|
||
extract_return_compare_ints(ast_json) {
|
||
if ast_json == null { return null }
|
||
// Find Return then Compare (whitespace耐性は RegexFlow に委譲)
|
||
local rq = RegexFlow.find_from(ast_json, "\"type\":\"Return\"", 0)
|
||
if rq < 0 { return null }
|
||
local cq = RegexFlow.find_from(ast_json, "\"type\":\"Compare\"", rq)
|
||
if cq < 0 { return null }
|
||
// op
|
||
local opk_pos = RegexFlow.find_from(ast_json, "\"op\":\"", cq)
|
||
if opk_pos < 0 { return null }
|
||
local opk_end = RegexFlow.find_from(ast_json, "\"", opk_pos + 6)
|
||
if opk_end < 0 { return null }
|
||
local cmp = ast_json.substring(opk_pos + 6, opk_end)
|
||
// lhs/rhs → 各 value の digits を抽出
|
||
local lhsp = RegexFlow.find_from(ast_json, "\"lhs\"", cq)
|
||
local rhsp = RegexFlow.find_from(ast_json, "\"rhs\"", cq)
|
||
if lhsp < 0 || rhsp < 0 { return null }
|
||
local lv = -1
|
||
local rv = -1
|
||
{
|
||
local vpos = RegexFlow.find_from(ast_json, "\"value\":", lhsp)
|
||
if vpos >= 0 {
|
||
local ds = RegexFlow.digits_from(ast_json, vpos + 8)
|
||
if ds != "" { lv = RegexFlow.to_int(ds) }
|
||
}
|
||
}
|
||
{
|
||
local vpos2 = RegexFlow.find_from(ast_json, "\"value\":", rhsp)
|
||
if vpos2 >= 0 {
|
||
local ds2 = RegexFlow.digits_from(ast_json, vpos2 + 8)
|
||
if ds2 != "" { rv = RegexFlow.to_int(ds2) }
|
||
}
|
||
}
|
||
if lv < 0 || rv < 0 { return null }
|
||
// Pack cmp/lhs/rhs into ArrayBox [cmp, lhs, rhs]
|
||
return [lv, rv, cmp]
|
||
}
|
||
|
||
// If(cond=Compare(lhs,rhs,op), then=[Return(Int 1)], else=[Return(Int 0)]) → MapBox {cmp,lhs,rhs} or null
|
||
extract_if_compare_ints(ast_json) {
|
||
if ast_json == null { return null }
|
||
// Find If first
|
||
local ip = RegexFlow.find_from(ast_json, "\"type\":\"If\"", 0)
|
||
if ip < 0 { return null }
|
||
// Find Compare after If
|
||
local cq = RegexFlow.find_from(ast_json, "\"type\":\"Compare\"", ip)
|
||
if cq < 0 { return null }
|
||
// Restrict to the Compare object range to avoid accidental matches
|
||
local range = me._find_brace_range(ast_json, cq)
|
||
if range == null { return null }
|
||
local rs = BoxHelpers.map_get(range, "from")
|
||
local re = BoxHelpers.map_get(range, "to")
|
||
// TEMP debug
|
||
print("DBG:cmp-range=" + ast_json.substring(rs, re))
|
||
// op
|
||
local opk_pos = me._find_in_range(ast_json, "\"op\":\"", rs, re)
|
||
if opk_pos < 0 { return null }
|
||
local opv_start = opk_pos + 6
|
||
local opk_end = me._find_in_range(ast_json, "\"", opv_start, re)
|
||
if opk_end < 0 { return null }
|
||
local cmp = ast_json.substring(opv_start, opk_end)
|
||
print("DBG:cmp-op=" + cmp)
|
||
// lhs
|
||
local lhsp = me._find_in_range(ast_json, "\"lhs\"", rs, re)
|
||
if lhsp < 0 { return null }
|
||
local vpos = me._find_in_range(ast_json, "\"value\":", lhsp, re)
|
||
if vpos < 0 { return null }
|
||
local ds = RegexFlow.digits_from(ast_json, vpos + 8)
|
||
if ds == "" { return null }
|
||
local lv = RegexFlow.to_int(ds)
|
||
print("DBG:lhs=" + (""+lv))
|
||
// rhs
|
||
local rhsp = me._find_in_range(ast_json, "\"rhs\"", rs, re)
|
||
if rhsp < 0 { return null }
|
||
local vpos2 = me._find_in_range(ast_json, "\"value\":", rhsp, re)
|
||
if vpos2 < 0 { return null }
|
||
local ds2 = RegexFlow.digits_from(ast_json, vpos2 + 8)
|
||
if ds2 == "" { return null }
|
||
local rv = RegexFlow.to_int(ds2)
|
||
print("DBG:rhs=" + (""+rv))
|
||
return [lv, rv, cmp]
|
||
}
|
||
}
|
||
|
||
static box CompareExtractStub { main(args) { return 0 } }
|