parser: chain 2-arg numeric builtins without parens#523
Merged
Conversation
rndn, atan2, fmod, clamp, and the unary trig forms (tan, asin, acos, atan, log10, log2) were absent from builtin_arity_tables, so the parse_call_arg nested-call branch never fired for them. A chained shape like 'abs rndn 0 1' fell through to parse_operand, returning a bare Ref(rndn), and the outer call swallowed the remaining operands producing 'arity mismatch: abs expects 1 args, got 3'. With the arities registered, parse_call_arg recurses into the inner call exactly arity operands deep, matching the existing behaviour for pow and min/max. Workaround paren-grouping is no longer needed. Closes pending #5ao.
9 regression tests pin the new parse behaviour across every public engine: abs/sqrt/pow outer composed with atan2/fmod/clamp/rndn/log10 inner, plus the original pending repro shape (y=+1 rndn 0 0.1) and a stochastic rndn run that asserts parse + execute succeed. examples/chained-num-args.ilo gives agents an in-context template for the now-working chain shape and runs through the examples harness, so any future grammar regression that drops the structural fix shows up there too.
SPEC.md Call Arguments section and ai.txt CALLS line now state that known-arity calls can chain directly without parens, with examples for the canonical 2-arg-numeric-under-unary shape. Variadic and unknown-arity calls still need paren grouping, called out explicitly so agents reach for parens only when they actually help.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 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
Closes pending #5ao.
abs rndn 0 1(and any chain putting a 2-arg numeric builtin under a unary outer) was misparsing asabs(rndn, 0, 1)and erroring with "arity mismatch: abs expects 1 args, got 3". Workaround had beenabs (rndn 0 1)— agents kept reaching for parens that the manifesto wants to avoid.Root cause:
parse_call_argonly recurses into a nested call when the inner ident has a registered arity inbuiltin_arity_tables().rndn,atan2,fmod,clamp, and the unary trig forms (tan,asin,acos,atan,log10,log2) were missing from that table, so the parser fell through toparse_operand, returned a bareRef(rndn), and let the outer greedy loop swallow the remaining operands.The structural fix is to register the missing arities. The nested-call branch already exists and is the right code path; this just lets it fire for these builtins exactly like it already does for
powandmin/max.Repro
Before:
After:
What's in the diff
parser: register arity for missing numeric builtins— adds the missing entries tobuiltin_arity_tables(). Lowest-blast-radius fix that takes the existing nested-call branch.test: cover chained 2-arg numeric calls cross-engine— 9 regression tests across--vmand--jitcovering abs/sqrt/pow outer × atan2/fmod/clamp/rndn/log10 inner, the pending repro shape (y=+1 rndn 0 0.1), and a composedpow atan2 1 1 2. Addsexamples/chained-num-args.ilofor agent in-context learning, exercised byexamples_engines.rs.docs: spell out known-arity call chaining rule— SPEC.md Call Arguments section and ai.txt CALLS line now document the chain-without-parens behaviour, with the variadic/unknown-arity carve-out called out.Test plan
cargo test --release --features craneliftpasses (all 3273 lib + every integration suite green)cargo test --release --features cranelift --test regression_chained_1arg_hint— 9/9 passcargo test --release --features cranelift --test examples_engines— new example exercisedcargo fmt --checkcleancargo clippy --release --features cranelift --all-targets -- -D warningscleanabs rndn 0 0.1,sqrt atan2 1 1,abs clamp 5 0 10,pow atan2 1 1 2all run on both enginesFollow-ups
There are ~60 more builtins still missing from the parser arity table (incl.
take,drop,enumerate,chunks,window,quantile,median,stdev,variance,matmul,dot,transpose,inv,det,solve,zip). Each has the same latent chained-call trap. This PR fixes the cluster the pending entry called out; happy to widen in a follow-up once we've watched main bake.