warn on same-precedence prefix-pair traps (*/a b c, +-, etc.)#301
Merged
Conversation
`*/a b c` parses as `*(/a b) c == (a/b)*c`, because the outer prefix op binds the inner prefix subexpression as its left operand. Personas reading `* / a b c` left-to-right expect `(a*b)/c` and silently get the wrong answer (logs-forensics has hit this three sessions running). Add a post-execution hint in `collect_hints` that detects the four mixed same-precedence pairs (`*/`, `/*`, `+-`, `-+`) when both tokens are in prefix position. The hint names the actual parse, the swap form, and a concrete bind rewrite for the other grouping. Same-op repeats (`++a b c == (a+b)+c`) and different-precedence pairs (`+*a b c == (a*b)+c`) keep matching the left-to-right reading and don't fire. Negative literals (`*-5 b c`) are absorbed by the lexer so the pair never appears. 12 unit tests pin the four firing shapes, the three non-firing shapes (same-op, different-precedence, infix), and the predecessor check (values vs prefix position).
Three named functions cover the trap (`mul-div-trap`), the swap (`mul-div-flip`), and the bind (`mul-then-div`). Each carries `-- run:` / `-- out:` assertions so `tests/examples_engines.rs` exercises them across tree, VM, and Cranelift on every CI run. Also acts as an in-context learning example for agents who run into the precedence trap and read the example file to understand the fix.
Adds a section to SPEC.md after the canonical prefix-nesting examples explaining the four shapes that disagree with left-to-right reading, plus the matching note in ai.txt (compact AI-spec format) and skills/ilo/SKILL.md (Claude plugin marketplace skill). Site has a matching update at ilo-lang/site#main (separate repo).
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
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
*/a b cparses as(a/b)*c, not(a*b)/c. Same trap for/*,+-,-+. This is by design (outer prefix op binds inner subexpression as its left operand, matching the canonical+*a b c == (a*b)+crule) but it consistently misleads agents reading the tokens left-to-right. Three persona logs in the assessment doc have hit it across three rerun sessions (logs-forensics entries at lines 844, 1056, 1651, 2833).The token cost is real: a persona spends a turn debugging "why does my percentage formula give the wrong number?" then a second turn rewriting to
r=*imp gl;pct=*r 100. A one-line hint at the terminal lets attempt #1 land correctly.Manifesto framing: this is pure additive token-saving. The hint fires after a successful run, costs zero tokens when not relevant (suppressible with
-nh), and saves a multi-turn debug loop when it is.Repro before / after
Before: result is
9(=(6/2)*3) with no warning. Persona reading the source as "multiply, then divide" expected4and silently believed the program.After: same
9result, plusWhat's in the diff (per commit)
src/main.rs. Walks the token stream fromlexer::lex(source), fires on the four mixed same-precedence pairs(*,/),(/,*),(+,-),(-,+)when both ops are in prefix position (predecessor is not value-yielding). Same-op repeats and different-precedence pairs are skipped because they match the left-to-right reading. 12 unit tests pin the firing, non-firing, predecessor, and negative-literal cases.-- run:/-- out:assertions for tree / VM / Cranelift. Also serves as in-context learning material for agents who hit the trap and read examples to understand the fix.Test plan
cargo test --release --features cranelift— 22 collect_hints tests (12 new) pass, examples_engines runs the new example across tree / VM / Cranelift and passes.cargo fmt --all -- --checkclean.cargo clippy --workspace --all-targets --features cranelift -- -D warningsclean.ilo run examples/prefix-mul-div.ilo mul-div-trap 6 2 3prints9+ hint.ilo 'f a:n b:n c:n>n;+*a b c' f 2 3 4prints10with NO hint (different precedence, intuition matches).ilo 'f a:n b:n c:n>n;++a b c' f 2 3 4prints9with NO hint (same-op repeat).-nhsuppresses the hint as expected.Follow-ups
None. The fix is self-contained and the persona pattern is fully covered by the four shapes in the detector.