Skip to content

Commit

Permalink
internal/core/adt: move cycle state saving logic to Expr
Browse files Browse the repository at this point in the history
The and builtin uses EvaluateKeepState to weave
cycle information into further evaluation. This should
generally be done if Expr is used. We therefore move that
logic to Expr directly, so that this complicated piece
of code does not proliferate.

Issue #3649

Signed-off-by: Marcel van Lohuizen <[email protected]>
Change-Id: Ib9460b0cf8e09065dc3a9b5a42f9f349c03d6fdc
  • Loading branch information
mpvl committed Feb 12, 2025
1 parent d5415a6 commit ea89159
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 9 deletions.
18 changes: 13 additions & 5 deletions internal/core/adt/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,26 @@ func (c *CallContext) Args() []Value {
return c.args
}

// Expr return the nth argument expression. The value remains unevaluated.
// If the call context represents a validator call, the argument will be offset
// by 1.
func (c *CallContext) Expr(i int) Expr {
// Expr return 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) Value {
// 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]
x := c.call.Args[i]

// Evaluated while keeping any cycle information in the context.
return c.ctx.EvaluateKeepState(x)
}

func (c *CallContext) Errf(format string, args ...interface{}) *Bottom {
Expand Down
2 changes: 1 addition & 1 deletion internal/core/adt/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ func (c *OpContext) Evaluate(env *Environment, x Expr) (result Value, complete b
return val, true
}

// EvaluateKeepState does an evaluate, but leaves any errors an cycle info
// EvaluateKeepState does an evaluate, but leaves any errors and cycle info
// within the context.
func (c *OpContext) EvaluateKeepState(x Expr) (result Value) {
src := c.src
Expand Down
4 changes: 1 addition & 3 deletions internal/core/compile/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,7 @@ var andBuiltin = &adt.Builtin{
c := call.OpContext()
arg := call.Expr(0)

// Pass through the cycle information from evaluating the first argument.
v := c.EvaluateKeepState(arg)
list := c.RawElems(v)
list := c.RawElems(arg)
if len(list) == 0 {
return &adt.Top{}
}
Expand Down

0 comments on commit ea89159

Please sign in to comment.