Skip to content

v35.4.1 — parser_ast.fj byte_at cascade

Choose a tag to compare

@fajarkraton fajarkraton released this 10 May 00:38
· 84 commits to main since this release

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_at mapping in BEGIN_CALL of codegen_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_char body, try_binop, op_prec, BEGIN_UNARY operator 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:

  1. Range compare on byte: first >= \"A\" && first <= \"Z\">= 65 && <= 90
  2. Multi-char STR var op accidentally migrated to numeric: reverted in op_prec
  3. byte (i64) pushed to AST [str] array → BEGIN_UNARY operator lookup-table fix
  4. STR var next_ch compared 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