Skip to content

Add eager if(cond, t, f) builtin#20

Merged
myzie merged 1 commit into
mainfrom
if-builtin
May 8, 2026
Merged

Add eager if(cond, t, f) builtin#20
myzie merged 1 commit into
mainfrom
if-builtin

Conversation

@myzie
Copy link
Copy Markdown
Contributor

@myzie myzie commented May 8, 2026

What

  • Register if(cond, t, f) as an eager builtin. Truthy condition returns t, falsey returns f. Both branches always evaluate.
  • Rewrite Go's if keyword token to a sentinel before parsing, mirroring the existing map rewrite. The keyword-rewrite list is factored out so future additions stay symmetric.
  • Translate the sentinel back via displayIdent in evalIdent, resolveCallable, and prewalk so env entries, registered shadows, error messages, and the prepared-func cache all key on the user-visible name "if".
  • Update templates.md and higher-order-patterns.md to use if(cond, t, f) instead of the brittle cond && t || f idiom. Update spec.md and llms.txt to document the new builtin.

Why

if(cond, t, f) reads cleanly even when both branches are non-nil values, where cond && t || f silently picks f whenever t happens to be falsey. Consolidating the keyword-rewrite plumbing also keeps the next addition (?. / ?[ in step 7) easy and consistent.

Test plan

  • go test ./...
  • go test -race ./...
  • go test -run=^$ -fuzz=FuzzCompile -fuzztime=20s .
  • go test -run=^$ -fuzz=FuzzEval -fuzztime=20s .
  • New tests cover arity, eager evaluation, env/funcs shadow, and use inside higher-order predicates.

What:
- Register `if(cond, t, f)` in Builtins(). Truthy condition picks t;
  falsey picks f. Both branches always evaluate.
- Rewrite the Go `if` keyword token to a sentinel identifier in
  preprocessSource so the parser accepts the call. The rewrite uses
  the same scheme already in place for `map`; the rewrite list is
  factored out so future additions stay symmetric.
- Translate the sentinel back via displayIdent in evalIdent,
  resolveCallable, and prewalk so user-visible env entries, registered
  shadows, error messages, and the prepared-func cache all key on
  "if".
- Update templates.md and higher-order-patterns.md to use
  `if(cond, t, f)` instead of the brittle `cond && t || f` idiom.
  Update spec.md and llms.txt to document the new builtin.

Why:
- `if(cond, t, f)` reads cleanly even when both branches are non-nil
  values, where `cond && t || f` silently picks `f` whenever `t`
  happens to be falsey.
- Consolidating the keyword-rewrite plumbing keeps the next addition
  (`?.` / `?[` in step 7) easy and consistent.
@myzie myzie merged commit e45b94e into main May 8, 2026
1 check passed
@myzie myzie deleted the if-builtin branch May 8, 2026 14:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant