Repository navigation
fix: close correctness gaps across all frontends and backends - #1
Merged
Merged
Conversation
Audit found the README's "production-grade"/"100% coverage" claims don't hold: actual coverage is ~92%, no backend emits several IR node types (For/Break/Continue/Cast/Struct-Array-MapInit/IndexAccess/Unary), no string or reserved-word escaping anywhere, and multiple frontends silently drop unhandled constructs instead of erroring. CLAUDE.md records this so future sessions don't build on false assumptions. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fixes every bug from the CLAUDE.md audit, plus several more of the same
kind discovered while verifying against real tree-sitter grammars:
Backends (all 6 languages):
- Emit For/Break/Continue/Cast/StructInit/ArrayInit/MapInit/IndexAccess/
Unary, which every backend previously silently rendered as "".
- Escape string literals (backslash/quote/newline/tab/CR) instead of
interpolating them verbatim into generated source.
- Rename identifiers that collide with target-language keywords.
- Python: and/or no longer emit the raw && / || enum values.
- Go: field export uses proper camelCase-preserving capitalization
instead of str.capitalize() (userID -> UserID, not Userid).
- Java: functions named "main" only get the special no-arg entry-point
treatment when they actually take no params; struct/class definitions
are now emitted at all (previously silently dropped entirely).
- C: print() dispatches to print_str/print_float/print_bool/print_int
based on the argument's inferred type instead of always print_int.
Frontends:
- Go: for-loops were fundamentally broken -- even the "supported"
while-style `for cond {}` silently became `for true {}` because the
condition is a positional child, not a field, unless the loop has a
for_clause. C-style `for init;cond;update` is now parsed correctly
with real init/condition/update. Multi-target assignment/declaration
(`a, b := f()`, `a, b = b, a`) is staged through temporaries so swaps
evaluate correctly instead of executing sequentially.
- C: comma-expression statements (`x = 1, y = 2;`) and else-branches
(previously silently dropped via an unwrapped else_clause node) are
now handled correctly.
- JS: the same else_clause-unwrapping bug as C is fixed.
- Rust: if/while/loop were entirely unhandled and silently became
NullLiteral no-ops; now parsed properly, plus range-based for-loops
downlevel to a counted loop.
- Python: for-in over range() desugars to a counted loop, augmented
assignment, multi-target assignment, break/continue, and top-level
globals are now supported; try/except, with-statements, and for-loops
over non-range iterables now raise a clear error instead of silently
vanishing.
- C/Go/Java/JS: none of these four frontends parsed function *call*
expressions at all -- print(x)/fmt.Println(x)/System.out.println(x)/
console.log(x) silently disappeared from every one of them. This was
more severe than the original audit found and is now fixed.
- All 6 frontends now raise NotImplementedError on unhandled statement/
expression node types instead of silently dropping them, except for
comments, which are recognized and intentionally ignored.
CLI: error messages now include the exception type name, since
"NotImplementedError: ..." is now a meaningful, common signal rather
than a rare crash.
Docs: README's false "production-grade"/"100% coverage" claims are
corrected; CLAUDE.md's "Known state" section is updated to describe
the current (fixed) behavior and what remains genuinely unsupported.
Added tests/test_bugfixes.py with regression coverage for each fix.
Full suite: 263 passed, ~86% coverage, clean ruff/black/mypy.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ahron-maslin
marked this pull request as ready for review
July 8, 2026 18:49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to the initial docs-only audit (CLAUDE.md). This fixes every bug identified there, plus several more of the same kind discovered while verifying against real tree-sitter grammars — most notably that none of C/Go/Java/JS ever parsed a function call expression at all, meaning
print(x)/fmt.Println(x)/System.out.println(x)/console.log(x)silently vanished from every one of those four languages' output. That's fixed now, along with everything from the original list.Backends (all 6 languages)
For/Break/Continue/Cast/StructInit/ArrayInit/MapInit/IndexAccess/Unary, previously silently rendered as"".and/orno longer emit the raw&&/||enum values.userID->UserID, notUserid).mainis only special-cased when it actually takes no params; struct/class definitions are now emitted at all (previously dropped entirely).print()dispatches toprint_str/print_float/print_bool/print_intbased on inferred argument type instead of alwaysprint_int.Frontends
for cond {}silently becamefor true {}(condition is a positional child, not a field, unless there's afor_clause). C-stylefor init;cond;updatenow parses correctly. Multi-target assignment (a, b = b, a) is staged through temporaries so swaps evaluate correctly.else_clausenode) now work.else_clausebug fixed.if/while/loopwere entirely unhandled and silently became no-ops; now parsed properly, plus range-basedfor-loops downlevel to a counted loop.for x in range(...), augmented assignment, multi-target assignment, break/continue, and top-level globals now work;try/except,with, and non-rangefor-loops now raise a clear error instead of silently vanishing.NotImplementedErroron unhandled constructs instead of silently dropping them (comments are the intentional exception).CLI & docs
Test plan
tests/test_bugfixes.pywith regression coverage for each fix above.ruff check,black --check,mypyall clean.exec) for the Go-swap and Rust-loop-with-break cases, since those are easy to get subtly wrong.🤖 Generated with Claude Code