Skip to content

Commit 143b396

Browse files
mpvlvanhtuan0409
authored andcommitted
internal/core/adt: add RawFunc
This prepares for both adding new buitlins (such as the proposed numExist et. al.) as well as adjusting some exiting ones, like `and`. This CL is supposed to be a no-op (aside from adding the functionality) and we separate it out to make future diffs smaller. We will test RawFunc itself with the respective builtins. The issue with `and`, for instance, is that it "weaves" in partially evaluated expressions into existing evaluation. In come cases this may lead to cycles. To prevent this, there needs to be a back channel from the function to the evaluator. Only the function can know exactly which cycle information is needed. Other uses are functions like `numExists` or any other builtin that needs to operate on CUE expressions rather than values. Issue cue-lang#943 Signed-off-by: Marcel van Lohuizen <[email protected]> Change-Id: I32ef92bfdc2a8318b00801bc067df4a073a10a73 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1202442 Reviewed-by: Matthew Sackman <[email protected]> TryBot-Result: CUEcueckoo <[email protected]> Unity-Result: CUE porcuepine <[email protected]>
1 parent fc74722 commit 143b396

File tree

1 file changed

+34
-10
lines changed

1 file changed

+34
-10
lines changed

internal/core/adt/expr.go

+34-10
Original file line numberDiff line numberDiff line change
@@ -1524,6 +1524,12 @@ func (x *CallExpr) evaluate(c *OpContext, state combinedFlags) Value {
15241524
switch f := fun.(type) {
15251525
case *Builtin:
15261526
b = f
1527+
if f.RawFunc != nil {
1528+
if !b.checkArgs(c, pos(x), len(x.Args)) {
1529+
return nil
1530+
}
1531+
return f.RawFunc(c, x.Args)
1532+
}
15271533

15281534
case *BuiltinValidator:
15291535
// We allow a validator that takes no arguments except the validated
@@ -1605,6 +1611,14 @@ type Builtin struct {
16051611

16061612
Func func(c *OpContext, args []Value) Expr
16071613

1614+
// RawFunc gives low-level control to CUE's internals for builtins.
1615+
// It should be used when fine control over the evaluation process is
1616+
// needed. Note that RawFuncs are responsible for returning a Value. This
1617+
// gives them fine control over how exactly such value gets evaluated.
1618+
// A RawFunc may pass CycleInfo, errors and other information through
1619+
// the Context.
1620+
RawFunc func(c *OpContext, args []Expr) Value
1621+
16081622
Package Feature
16091623
Name string
16101624
}
@@ -1665,23 +1679,33 @@ func bottom(v Value) *Bottom {
16651679
return b
16661680
}
16671681

1668-
func (x *Builtin) call(c *OpContext, p token.Pos, validate bool, args []Value) Expr {
1669-
fun := x // right now always x.
1670-
if len(args) > len(x.Params) {
1682+
func (x *Builtin) checkArgs(c *OpContext, p token.Pos, numArgs int) bool {
1683+
if numArgs > len(x.Params) {
16711684
c.addErrf(0, p,
16721685
"too many arguments in call to %v (have %d, want %d)",
1673-
fun, len(args), len(x.Params))
1674-
return nil
1686+
x, numArgs, len(x.Params))
1687+
return false
16751688
}
1676-
for i := len(args); i < len(x.Params); i++ {
1677-
v := x.Params[i].Default()
1689+
if numArgs < len(x.Params) {
1690+
// Assume that all subsequent params have a default as well.
1691+
v := x.Params[numArgs].Default()
16781692
if v == nil {
16791693
c.addErrf(0, p,
16801694
"not enough arguments in call to %v (have %d, want %d)",
1681-
fun, len(args), len(x.Params))
1682-
return nil
1695+
x, numArgs, len(x.Params))
1696+
return false
16831697
}
1684-
args = append(args, v)
1698+
}
1699+
return true
1700+
}
1701+
1702+
func (x *Builtin) call(c *OpContext, p token.Pos, validate bool, args []Value) Expr {
1703+
fun := x // right now always x.
1704+
if !x.checkArgs(c, p, len(args)) {
1705+
return nil
1706+
}
1707+
for i := len(args); i < len(x.Params); i++ {
1708+
args = append(args, x.Params[i].Default())
16851709
}
16861710
for i, a := range args {
16871711
if x.Params[i].Kind() == BottomKind {

0 commit comments

Comments
 (0)