Cheap heuristics that turn opaque parse / eval errors into precise diagnostic hints. Engine wires the catalogue into the per-form trailer so the model sees actionable repair instructions instead of a stack trace.
Catalogue today:
diagnose-quote-balance Odd number of unescaped double quotes in the source. Pinpoints the 1-based line where the running count first becomes odd. parinferish does indent-mode paren balancing only; string-quote imbalance needs its own walker.
diagnose-bracket-balance
Unbalanced (), [], {}. Walks a bracket stack skipping string/char
literals (incl. triple-quoted, with escapes) and # comments; reports
the FIRST wrong-type / extra / unclosed bracket + 1-based line/col.
repair-bracket-balance offers a single-candidate auto-fix, but ONLY
when one edit rebalances the WHOLE form. Python's mixed (), [], {} are
NOT indentation-determined, so parinfer (the Clojure paren repairer)
cannot be reused here.
unresolved-symbol-hint The Python eval raised a NameError for an undefined name X. Suggests the closest name(s) in the user's sandbox bindings (Levenshtein-style score), so the model sees 'did you mean ...?' instead of 'X is undefined'.
Cheap heuristics that turn opaque parse / eval errors into precise
diagnostic hints. Engine wires the catalogue into the per-form trailer so
the model sees actionable repair instructions instead of a stack trace.
Catalogue today:
diagnose-quote-balance
Odd number of unescaped double quotes in the source. Pinpoints the
1-based line where the running count first becomes odd. parinferish
does indent-mode paren balancing only; string-quote imbalance needs
its own walker.
diagnose-bracket-balance
Unbalanced (), [], {}. Walks a bracket stack skipping string/char
literals (incl. triple-quoted, with escapes) and `#` comments; reports
the FIRST wrong-type / extra / unclosed bracket + 1-based line/col.
`repair-bracket-balance` offers a single-candidate auto-fix, but ONLY
when one edit rebalances the WHOLE form. Python's mixed (), [], {} are
NOT indentation-determined, so parinfer (the Clojure paren repairer)
cannot be reused here.
unresolved-symbol-hint
The Python eval raised a NameError for an undefined name X. Suggests
the closest name(s) in the user's sandbox bindings (Levenshtein-style score),
so the model sees 'did you mean ...?' instead of 'X is undefined'.(count-unescaped-quotes s)Count double-quote characters in s that are NOT preceded by a backslash.
Also skips the character following a backslash so \\ (escaped
backslash) doesn't swallow the quote that follows it.
Count double-quote characters in `s` that are NOT preceded by a backslash. Also skips the character following a backslash so `\\` (escaped backslash) doesn't swallow the quote that follows it.
(diagnose-bracket-balance code)Walk code with a bracket stack over (), [], {} - skipping characters
inside string/char literals (single, double, and triple-quoted, honoring
backslash escapes) and # comments. Returns a diagnostic map shaped
{:reason :unbalanced-bracket :open C :close C :line R :col K :hint "..."}
for the FIRST imbalance found, or nil when every bracket pairs up.
Three failure shapes:
:open is what was open, :close the found closer):open nil):close nil)Heuristic only: Python's mixed (), [], {} are NOT indentation-determined, so parinfer (Clojure indent-mode) cannot be reused; this just pinpoints the first place the nesting goes wrong so the model can repair it.
Walk `code` with a bracket stack over (), [], {} - skipping characters
inside string/char literals (single, double, and triple-quoted, honoring
backslash escapes) and `#` comments. Returns a diagnostic map shaped
`{:reason :unbalanced-bracket :open C :close C :line R :col K :hint "..."}`
for the FIRST imbalance found, or nil when every bracket pairs up.
Three failure shapes:
- a closer of the WRONG type (`:open` is what was open, `:close` the found closer)
- an EXTRA closer with nothing open (`:open` nil)
- an UNCLOSED opener at end-of-input (`:close` nil)
Heuristic only: Python's mixed (), [], {} are NOT indentation-determined, so
parinfer (Clojure indent-mode) cannot be reused; this just pinpoints the
first place the nesting goes wrong so the model can repair it.(diagnose-quote-balance code)If code has an odd number of unescaped quote chars, return a diagnostic
map shaped {:reason :unbalanced-quote :total N :line R :hint "…"}.
Returns nil for balanced sources.
If `code` has an odd number of unescaped quote chars, return a diagnostic
map shaped `{:reason :unbalanced-quote :total N :line R :hint "…"}`.
Returns nil for balanced sources.(first-odd-quote-line code)Walk code line-by-line tracking the running unescaped-quote count.
Returns the 1-based line where the count first becomes odd at end-of-line,
or nil if the count is even at every newline. This is the line where the
user most likely introduced an unbalanced quote — even when the reader's
error reports a row far below.
Walk `code` line-by-line tracking the running unescaped-quote count. Returns the 1-based line where the count first becomes odd at end-of-line, or nil if the count is even at every newline. This is the line where the user most likely introduced an unbalanced quote — even when the reader's error reports a row far below.
(repair-bracket-balance code)Conservative single-candidate auto-fix for the imbalance diagnose-bracket-balance
finds. Returns {:fixed <repaired-source> :change <human note>} ONLY when there
is exactly one unambiguous edit that makes the WHOLE source balance, else nil.
Three repair shapes, each gated on re-running the walker and getting nil:
The confidence gate is the re-check: if more than one bracket is wrong, the single candidate edit will NOT fully rebalance, so we return nil rather than silently close the wrong container.
Conservative single-candidate auto-fix for the imbalance `diagnose-bracket-balance`
finds. Returns `{:fixed <repaired-source> :change <human note>}` ONLY when there
is exactly one unambiguous edit that makes the WHOLE source balance, else nil.
Three repair shapes, each gated on re-running the walker and getting nil:
- wrong-type closer -> swap it for the expected closer
- extra closer -> delete it
- unclosed opener -> append the matching closer
The confidence gate is the re-check: if more than one bracket is wrong, the
single candidate edit will NOT fully rebalance, so we return nil rather than
silently close the wrong container.(unresolved-symbol-hint error-message candidates)When an eval error message is shaped 'Unable to resolve symbol: foo',
propose the closest sandbox symbol(s) as a hint. candidates is a coll of
symbols / strings (e.g. keys of the live sandbox map). Returns nil when
the error does not look like an unresolved-symbol failure, or when no
close match exists.
When an eval error message is shaped 'Unable to resolve symbol: foo', propose the closest sandbox symbol(s) as a hint. `candidates` is a coll of symbols / strings (e.g. keys of the live sandbox map). Returns nil when the error does not look like an unresolved-symbol failure, or when no close match exists.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |