Skip to content

Commit 5991735

Browse files
committed
internal/core/adt: pass CallContext to builtin functions
This is the next step in the refactor. This gives functions access to the low-level expressions, which in turn gives finer control over evaluation order, which is important for some functions that validate schema. In general, this gives more flexibility as to what kind of information is pass and when it is evaluated. Signed-off-by: Marcel van Lohuizen <[email protected]> Change-Id: Id5128951a670f60a2b4e7d039806413d3059836f Reviewed-on: https://cue.gerrithub.io/c/cue-lang/cue/+/1208022 Unity-Result: CUE porcuepine <[email protected]> TryBot-Result: CUEcueckoo <[email protected]> Reviewed-by: Matthew Sackman <[email protected]>
1 parent 2d65404 commit 5991735

File tree

7 files changed

+74
-17
lines changed

7 files changed

+74
-17
lines changed

cue/interpreter/wasm/builtin.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ func generateCallThatReturnsBuiltin(name string, scope adt.Value, args []string,
5555
call := &adt.CallExpr{Fun: &adt.Builtin{
5656
Result: adt.TopKind,
5757
Name: name,
58-
Func: func(opctx *adt.OpContext, _ []adt.Value) adt.Expr {
58+
Func: func(call *adt.CallContext) adt.Expr {
59+
opctx := call.OpContext()
60+
5961
scope := value.Make(opctx, scope)
6062
sig := compileStringsInScope(args, scope)
6163
args, result := splitLast(sig)

internal/core/adt/call.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ type CallContext struct {
2929
isValidator bool
3030
}
3131

32+
func (c *CallContext) OpContext() *OpContext {
33+
return c.ctx
34+
}
35+
3236
func (c *CallContext) Pos() token.Pos {
3337
var src ast.Node
3438
switch {
@@ -57,3 +61,17 @@ func (c *CallContext) AddPositions(err *ValueError) {
5761
err.AddPosition(v)
5862
}
5963
}
64+
65+
// Args return the pre-evaluated arguments. This function is only used for
66+
// transitioning and will be removed at some point. Use [CallContext.Value]
67+
// instead.
68+
func (c *CallContext) Args() []Value {
69+
return c.args
70+
}
71+
72+
// Exprs return the unevaluated argument expressions. This function is only used
73+
// for transitioning and will be removed at some point. Use [CallContext.Expr]
74+
// instead. (TODO)
75+
func (c *CallContext) Exprs() []Expr {
76+
return c.call.Args
77+
}

internal/core/adt/expr.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,7 +1544,7 @@ func (x *CallExpr) evaluate(c *OpContext, state combinedFlags) Value {
15441544
if !call.builtin.checkArgs(c, pos(x), len(x.Args)) {
15451545
return nil
15461546
}
1547-
return f.RawFunc(c, x.Args)
1547+
return f.RawFunc(call)
15481548
}
15491549

15501550
case *BuiltinValidator:
@@ -1637,15 +1637,17 @@ type Builtin struct {
16371637
// arguments. By default, all arguments are checked to be concrete.
16381638
NonConcrete bool
16391639

1640-
Func func(c *OpContext, args []Value) Expr
1640+
Func func(call *CallContext) Expr
16411641

16421642
// RawFunc gives low-level control to CUE's internals for builtins.
16431643
// It should be used when fine control over the evaluation process is
16441644
// needed. Note that RawFuncs are responsible for returning a Value. This
16451645
// gives them fine control over how exactly such value gets evaluated.
16461646
// A RawFunc may pass CycleInfo, errors and other information through
16471647
// the Context.
1648-
RawFunc func(c *OpContext, args []Expr) Value
1648+
//
1649+
// TODO: consider merging Func and RawFunc into a single field again.
1650+
RawFunc func(call *CallContext) Value
16491651

16501652
Package Feature
16511653
Name string
@@ -1773,7 +1775,7 @@ func (x *Builtin) call(call *CallContext) Expr {
17731775

17741776
saved := c.IsValidator
17751777
c.IsValidator = call.isValidator
1776-
ret := x.Func(c, call.args)
1778+
ret := x.Func(call)
17771779
c.IsValidator = saved
17781780

17791781
return ret

internal/core/compile/builtin.go

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ var lenBuiltin = &adt.Builtin{
3535
Name: "len",
3636
Params: []adt.Param{{Value: &adt.BasicType{K: supportedByLen}}},
3737
Result: adt.IntKind,
38-
Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
38+
Func: func(call *adt.CallContext) adt.Expr {
39+
c := call.OpContext()
40+
args := call.Args()
41+
3942
v := args[0]
4043
if x, ok := v.(*adt.Vertex); ok {
4144
x.LockArcs = true
@@ -82,7 +85,10 @@ var closeBuiltin = &adt.Builtin{
8285
Name: "close",
8386
Params: []adt.Param{structParam},
8487
Result: adt.StructKind,
85-
Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
88+
Func: func(call *adt.CallContext) adt.Expr {
89+
c := call.OpContext()
90+
args := call.Args()
91+
8692
s, ok := args[0].(*adt.Vertex)
8793
if !ok {
8894
return c.NewErrf("struct argument must be concrete")
@@ -110,7 +116,10 @@ var andBuiltin = &adt.Builtin{
110116
Name: "and",
111117
Params: []adt.Param{listParam},
112118
Result: adt.IntKind,
113-
RawFunc: func(c *adt.OpContext, args []adt.Expr) adt.Value {
119+
RawFunc: func(call *adt.CallContext) adt.Value {
120+
c := call.OpContext()
121+
args := call.Exprs()
122+
114123
// Pass through the cycle information from evaluating the first argument.
115124
v := c.EvaluateKeepState(args[0])
116125
list := c.RawElems(v)
@@ -130,7 +139,10 @@ var orBuiltin = &adt.Builtin{
130139
Params: []adt.Param{listParam},
131140
Result: adt.IntKind,
132141
NonConcrete: true,
133-
Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
142+
Func: func(call *adt.CallContext) adt.Expr {
143+
c := call.OpContext()
144+
args := call.Args()
145+
134146
d := []adt.Disjunct{}
135147
for _, c := range c.RawElems(args[0]) {
136148
d = append(d, adt.Disjunct{Val: c, Default: false})
@@ -165,7 +177,10 @@ var divBuiltin = &adt.Builtin{
165177
Name: "div",
166178
Params: []adt.Param{intParam, intParam},
167179
Result: adt.IntKind,
168-
Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
180+
Func: func(call *adt.CallContext) adt.Expr {
181+
c := call.OpContext()
182+
args := call.Args()
183+
169184
const name = "argument to div builtin"
170185

171186
return intDivOp(c, (*adt.OpContext).IntDiv, name, args)
@@ -176,7 +191,10 @@ var modBuiltin = &adt.Builtin{
176191
Name: "mod",
177192
Params: []adt.Param{intParam, intParam},
178193
Result: adt.IntKind,
179-
Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
194+
Func: func(call *adt.CallContext) adt.Expr {
195+
c := call.OpContext()
196+
args := call.Args()
197+
180198
const name = "argument to mod builtin"
181199

182200
return intDivOp(c, (*adt.OpContext).IntMod, name, args)
@@ -187,7 +205,10 @@ var quoBuiltin = &adt.Builtin{
187205
Name: "quo",
188206
Params: []adt.Param{intParam, intParam},
189207
Result: adt.IntKind,
190-
Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
208+
Func: func(call *adt.CallContext) adt.Expr {
209+
c := call.OpContext()
210+
args := call.Args()
211+
191212
const name = "argument to quo builtin"
192213

193214
return intDivOp(c, (*adt.OpContext).IntQuo, name, args)
@@ -198,7 +219,10 @@ var remBuiltin = &adt.Builtin{
198219
Name: "rem",
199220
Params: []adt.Param{intParam, intParam},
200221
Result: adt.IntKind,
201-
Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
222+
Func: func(call *adt.CallContext) adt.Expr {
223+
c := call.OpContext()
224+
args := call.Args()
225+
202226
const name = "argument to rem builtin"
203227

204228
return intDivOp(c, (*adt.OpContext).IntRem, name, args)

internal/core/compile/validator.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ var matchNBuiltin = &adt.Builtin{
3030
Params: []adt.Param{topParam, intParam, listParam}, // varargs
3131
Result: adt.BoolKind,
3232
NonConcrete: true,
33-
Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
33+
Func: func(call *adt.CallContext) adt.Expr {
34+
c := call.OpContext()
35+
args := call.Args()
36+
3437
if !c.IsValidator {
3538
return c.NewErrf("matchN is a validator and should not be used as a function")
3639
}
@@ -89,7 +92,10 @@ var matchIfBuiltin = &adt.Builtin{
8992
Params: []adt.Param{topParam, topParam, topParam, topParam},
9093
Result: adt.BoolKind,
9194
NonConcrete: true,
92-
Func: func(c *adt.OpContext, args []adt.Value) adt.Expr {
95+
Func: func(call *adt.CallContext) adt.Expr {
96+
c := call.OpContext()
97+
args := call.Args()
98+
9399
if !c.IsValidator {
94100
return c.NewErrf("matchIf is a validator and should not be used as a function")
95101
}

internal/core/runtime/extern_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,9 @@ func (c *compilerFake) Compile(name string, scope adt.Value, a *internal.Attr) (
119119

120120
call := &adt.CallExpr{Fun: &adt.Builtin{
121121
Result: adt.TopKind,
122-
Func: func(opctx *adt.OpContext, args []adt.Value) adt.Expr {
122+
Func: func(call *adt.CallContext) adt.Expr {
123+
opctx := call.OpContext()
124+
123125
cuectx := (*cue.Context)(c.runtime)
124126
scope := value.Make(opctx, scope)
125127

internal/pkg/builtin.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,10 @@ func ToBuiltin(b *Builtin) *adt.Builtin {
126126
Package: b.Pkg,
127127
Name: b.Name,
128128
}
129-
x.Func = func(ctx *adt.OpContext, args []adt.Value) (ret adt.Expr) {
129+
x.Func = func(call *adt.CallContext) (ret adt.Expr) {
130+
ctx := call.OpContext()
131+
args := call.Args()
132+
130133
// call, _ := ctx.Source().(*ast.CallExpr)
131134
c := &CallCtxt{
132135
ctx: ctx,

0 commit comments

Comments
 (0)