Skip to content

New built-in functions for late binding interpolation (fn::template and fn::eval)#638

Open
tehsis wants to merge 2 commits intomainfrom
pterradillos/claire-defns
Open

New built-in functions for late binding interpolation (fn::template and fn::eval)#638
tehsis wants to merge 2 commits intomainfrom
pterradillos/claire-defns

Conversation

@tehsis
Copy link
Copy Markdown
Collaborator

@tehsis tehsis commented Apr 21, 2026

Summary

This PR introduces new built-in function to enable late binding interpolation

The fn::template built-in function defines a template expression whose interpolations are not resolved immediately. Instead, the template is evaluated later when a consumer environment references it with fn::eval. This enables late binding — defining reusable expressions in one environment and evaluating them with different values in another.

Test changes

  • [] late-binding unit tests were added

Risk

None.

Rollback

Revert the commit

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces late-binding interpolation by adding two new built-in functions: fn::template (to define a deferred template) and fn::eval (to evaluate a deferred template in the consumer environment), along with a new golden test case under eval/testdata/eval/late-binding.

Changes:

  • Add AST support for fn::template and fn::eval.
  • Add evaluator support to defer template evaluation and explicitly evaluate it later via fn::eval.
  • Add new late-binding eval test fixtures + expected output.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
ast/expr.go Adds AST nodes + parsing hooks for fn::template / fn::eval.
eval/eval.go Declares/evaluates new expr forms (templateExpr, evalExpr) to implement late-binding.
eval/expr.go Updates expression exporting logic for the new expr kinds.
eval/eval_test.go Modifies the golden-test runner logic (currently filtering to only late-binding).
eval/testdata/eval/late-binding/* Adds new golden test case YAMLs + expected.json.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread eval/eval_test.go
Comment on lines +367 to +369
entries = slices.DeleteFunc(entries, func(entry os.DirEntry) bool {
return entry.Name() != "late-binding"
})
Comment thread eval/eval.go
Comment on lines +660 to +662
defn := e.evaluateExpr(repr.value, schema.Always()) // deref template expr
expr := declare(e, "", defn.repr.(*templateExpr).node.Args(), nil) // clone its ast node into a new expr
val = e.evaluateExpr(expr, schema.Always()) // evaluate it
Comment thread eval/eval.go
repr := &templateExpr{node: x, template: declare(e, "", x.Args(), nil)}
return newExpr(path, repr, schema.Never().Schema(), base)
case *ast.EvalExpr:
repr := &evalExpr{node: x, value: declare(e, "", x.Args(), base)}
Comment thread eval/expr.go
Comment on lines +348 to +350
// not evaluated
case *evalExpr:
return repr.value.export(environment)
@pgavlin
Copy link
Copy Markdown
Member

pgavlin commented Apr 21, 2026

this really needs a design doc. do we have one?

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.

4 participants