Skip to content

Commit

Permalink
internal/core/adt: add Expr method on CallContext
Browse files Browse the repository at this point in the history
This method allows looking up the unevaluated
expression of a CallExpr. To avoid having to create
a slice, it computes the exact position of the
argument depending on whether the call represents
a validation or function call.

As expressions are raw, we now also need to set
the Environment in Validate. For calls the
Environment was already passed correctly.

The usage of these calls will happen in  subsequent
CLs. We make these change already to isolate any
problems that may arise from these more
straightforward changes.

Issue #3649

Signed-off-by: Marcel van Lohuizen <[email protected]>
Change-Id: I2818a7f0ca8fb00c8746007e64623d0278e31c53
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1208684
TryBot-Result: CUEcueckoo <[email protected]>
Reviewed-by: Matthew Sackman <[email protected]>
  • Loading branch information
mpvl committed Feb 13, 2025
1 parent 6fb2a9b commit ee11854
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 10 deletions.
26 changes: 21 additions & 5 deletions internal/core/adt/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,25 @@ func (c *CallContext) Args() []Value {
return c.args
}

// Exprs return the unevaluated argument expressions. This function is only used
// for transitioning and will be removed at some point. Use [CallContext.Expr]
// instead. (TODO)
func (c *CallContext) Exprs() []Expr {
return c.call.Args
// Expr returns the nth argument expression. The value is evaluated and any
// cycle information is accumulated in the context. This allows cycles in
// arguments to be detected.
//
// This method of getting an argument should be used when the argument is used
// as a schema and may contain cycles.
func (c *CallContext) Expr(i int) Expr {
// If the call context represents a validator call, the argument will be
// offset by 1.
if c.isValidator {
if i == 0 {
c.Errf("Expr may not be called for 0th argument of validator")
return nil
}
i--
}
return c.call.Args[i]
}

func (c *CallContext) Errf(format string, args ...interface{}) *Bottom {
return c.ctx.NewErrf(format, args...)
}
3 changes: 3 additions & 0 deletions internal/core/adt/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,13 +461,16 @@ func (c *OpContext) Validate(check Conjunct, value Value) *Bottom {

src := c.src
ci := c.ci
env := c.e
c.src = check.Source()
c.ci = check.CloseInfo
c.e = check.Env

err := check.x.(Validator).validate(c, value)

c.src = src
c.ci = ci
c.e = env

return err
}
Expand Down
4 changes: 2 additions & 2 deletions internal/core/compile/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,10 @@ var andBuiltin = &adt.Builtin{
Result: adt.IntKind,
RawFunc: func(call *adt.CallContext) adt.Value {
c := call.OpContext()
args := call.Exprs()
arg := call.Expr(0)

// Pass through the cycle information from evaluating the first argument.
v := c.EvaluateKeepState(args[0])
v := c.EvaluateKeepState(arg)
list := c.RawElems(v)
if len(list) == 0 {
return &adt.Top{}
Expand Down
7 changes: 4 additions & 3 deletions internal/pkg/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,10 @@ func ToBuiltin(b *Builtin) *adt.Builtin {

// call, _ := ctx.Source().(*ast.CallExpr)
c := &CallCtxt{
ctx: ctx,
args: args,
builtin: b,
CallContext: call,
ctx: ctx,
args: args,
builtin: b,
}
defer func() {
var errVal interface{} = c.Err
Expand Down
1 change: 1 addition & 0 deletions internal/pkg/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (

// CallCtxt is passed to builtin implementations that need to use a cue.Value. This is an internal type. Its interface may change.
type CallCtxt struct {
*adt.CallContext
ctx *adt.OpContext
builtin *Builtin
Err interface{}
Expand Down

0 comments on commit ee11854

Please sign in to comment.