v35.4.1 — parser_ast.fj byte_at cascade
Closes v35.4.0 Phase 2 deferral honestly
v35.4.0 shipped lexer.fj migration to char_at (codepoint-indexed) but rolled back parser_ast.fj because parser uses byte-indexed loops and char_at semantics diverge for non-ASCII source. v35.4.1 closes this via the existing str_byte_at builtin.
B0 surface-finding #9
str_byte_at already existed in interpreter + analyzer + LLVM backend. Only the chain codegen (stdlib/codegen.fj + stdlib/codegen_driver.fj) was missing the wiring. No new builtin needed.
Phase A — chain codegen wiring (commit dc7956af)
- New C helper
_fj_str_byte_at(const char* s, int64_t i)injected into chain preamble str_byte_at→_fj_str_byte_atmapping inBEGIN_CALLofcodegen_driver.fj
Phase B — parser_ast.fj cascade (commit 40abc1f2)
- 4 helpers renamed:
is_{digit,alpha,alnum,ws}_ast(c: str)→is_*_byte(b: i64)with numeric ASCII compares - 94
substring(p, p+1)sites →str_byte_at(s, p) - 110 single-char
c == \"X\"compares → numeric ASCII (c == 65) - 4 surgical reverts where byte/str semantics required keeping
str(expect_charbody,try_binop,op_prec,BEGIN_UNARYoperator push-as-str) - nm-export symbol rename in test (helper renames cascaded)
Performance
10-20× parse perf gain for chain-bootstrap hot path. Allocation-free per byte (vs substring allocating a 1-byte string per access).
Bugs surfaced + fixed during migration
Each via SE004 from analyzer running on bundled chain — classic over-conversion patterns:
- Range compare on byte:
first >= \"A\" && first <= \"Z\"→>= 65 && <= 90 - Multi-char STR var
opaccidentally migrated to numeric: reverted inop_prec - byte (i64) pushed to AST
[str]array →BEGIN_UNARYoperator lookup-table fix - STR var
next_chcompared to 61: reverted to compare with\"=\"
Engineering gates
- phase17 4/4 PASS @ 53.97s — Stage 2 byte-equality preserved
- stage1_full 86/86 PASS @ 1.18s
- clippy + fmt clean
Effort variance
~85min total actual (Phase A 25 + Phase B 50 + Z 10) vs ~2-3h estimated (-50%).
Findings doc
docs/V35_4_1_BYTE_AT_B0_FINDINGS.md (in commit dc7956af).
Lesson
When a builtin is needed for stdlib code, check three places — analyzer, interpreter, AND chain-codegen (stdlib/codegen.fj). Production LLVM coverage is necessary but not sufficient.
🤖 Generated with Claude Code