1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package adt
16
17 import (
18 "cuelang.org/go/cue/ast"
19 "cuelang.org/go/cue/token"
20 )
21
22 var (
23 handleExpr *runner
24 handleResolver *runner
25 handleDynamic *runner
26 handlePatternConstraint *runner
27 handleComprehension *runner
28 handleListLit *runner
29 handleListVertex *runner
30 handleDisjunction *runner
31 )
32
33
34 func init() {
35 handleExpr = &runner{
36 name: "Expr",
37 f: processExpr,
38 completes: genericConjunct,
39 }
40 handleResolver = &runner{
41 name: "Resolver",
42 f: processResolver,
43 completes: genericConjunct,
44 }
45 handleDynamic = &runner{
46 name: "Dynamic",
47 f: processDynamic,
48 completes: fieldConjunct,
49 }
50 handlePatternConstraint = &runner{
51 name: "PatternConstraint",
52 f: processPatternConstraint,
53 completes: allTasksCompleted | fieldConjunctsKnown,
54 }
55 handleComprehension = &runner{
56 name: "Comprehension",
57 f: processComprehension,
58 completes: valueKnown | allTasksCompleted | fieldConjunctsKnown,
59 }
60 handleListLit = &runner{
61 name: "ListLit",
62 f: processListLit,
63 completes: fieldConjunct,
64 needs: listTypeKnown,
65 }
66 handleListVertex = &runner{
67 name: "ListVertex",
68 f: processListVertex,
69 completes: fieldConjunct,
70 needs: listTypeKnown,
71 }
72 }
73
74
75
76 func processExpr(ctx *OpContext, t *task, mode runMode) {
77 x := t.x.(Expr)
78
79 state := combineMode(concreteKnown, mode)
80 v := ctx.evalState(x, state)
81 t.node.insertValueConjunct(t.env, v, t.id)
82 }
83
84 func processResolver(ctx *OpContext, t *task, mode runMode) {
85 r := t.x.(Resolver)
86
87 arc := r.resolve(ctx, oldOnly(0))
88 if arc == nil {
89
90 return
91 }
92
93
94 ci, skip := t.node.markCycle(arc, t.env, r, t.id)
95 if skip {
96 return
97 }
98
99 c := MakeConjunct(t.env, t.x, ci)
100 t.node.scheduleVertexConjuncts(c, arc, ci)
101 }
102
103 func processDynamic(ctx *OpContext, t *task, mode runMode) {
104 n := t.node
105
106 field := t.x.(*DynamicField)
107
108 v := ctx.scalarValue(t, field.Key)
109 if v == nil {
110 return
111 }
112
113 if v.Concreteness() != Concrete {
114 n.addBottom(&Bottom{
115 Code: IncompleteError,
116 Err: ctx.NewPosf(pos(field.Key),
117 "key value of dynamic field must be concrete, found %v", v),
118 })
119 return
120 }
121
122 f := ctx.Label(field.Key, v)
123
124 if f.IsInt() {
125 n.addErr(ctx.NewPosf(pos(field.Key), "integer fields not supported"))
126 return
127 }
128
129 c := MakeConjunct(t.env, field, t.id)
130 c.CloseInfo.cc = nil
131 n.insertArc(f, field.ArcType, c, t.id, true)
132 }
133
134 func processPatternConstraint(ctx *OpContext, t *task, mode runMode) {
135 n := t.node
136
137 field := t.x.(*BulkOptionalField)
138
139
140
141 v := ctx.evalState(field.Filter, require(0, scalarKnown))
142 if v == nil {
143 return
144 }
145
146 n.insertPattern(v, MakeConjunct(t.env, t.x, t.id))
147 }
148
149 func processComprehension(ctx *OpContext, t *task, mode runMode) {
150 n := t.node
151
152 y := &envYield{
153 envComprehension: t.comp,
154 leaf: t.leaf,
155 env: t.env,
156 id: t.id,
157 expr: t.x,
158 }
159
160 err := n.processComprehension(y, 0)
161 t.err = CombineErrors(nil, t.err, err)
162 t.comp.vertex.state.addBottom(err)
163 }
164
165 func processListLit(c *OpContext, t *task, mode runMode) {
166 n := t.node
167
168 l := t.x.(*ListLit)
169
170 n.updateCyclicStatus(t.id)
171
172 var ellipsis Node
173
174 index := int64(0)
175 hasComprehension := false
176 for j, elem := range l.Elems {
177
178
179 switch x := elem.(type) {
180 case *Comprehension:
181 err := c.yield(nil, t.env, x, 0, func(e *Environment) {
182 label, err := MakeLabel(x.Source(), index, IntLabel)
183 n.addErr(err)
184 index++
185 c := MakeConjunct(e, x.Value, t.id)
186 n.insertArc(label, ArcMember, c, t.id, true)
187 })
188 hasComprehension = true
189 if err != nil {
190 n.addBottom(err)
191 return
192 }
193
194 case *Ellipsis:
195 if j != len(l.Elems)-1 {
196 n.addErr(c.Newf("ellipsis must be last element in list"))
197 return
198 }
199
200 elem := x.Value
201 if elem == nil {
202 elem = &Top{}
203 }
204
205 c := MakeConjunct(t.env, elem, t.id)
206 pat := &BoundValue{
207 Op: GreaterEqualOp,
208 Value: n.ctx.NewInt64(index, x),
209 }
210 n.insertPattern(pat, c)
211 ellipsis = x
212
213 default:
214 label, err := MakeLabel(x.Source(), index, IntLabel)
215 n.addErr(err)
216 index++
217 c := MakeConjunct(t.env, x, t.id)
218 n.insertArc(label, ArcMember, c, t.id, true)
219 }
220
221 if max := n.maxListLen; n.listIsClosed && int(index) > max {
222 n.invalidListLength(max, len(l.Elems), n.maxNode, l)
223 return
224 }
225 }
226
227 isClosed := ellipsis == nil
228
229 switch max := n.maxListLen; {
230 case int(index) < max:
231 if isClosed {
232 n.invalidListLength(int(index), max, l, n.maxNode)
233 return
234 }
235
236 case int(index) > max,
237 isClosed && !n.listIsClosed,
238 (isClosed == n.listIsClosed) && !hasComprehension:
239 n.maxListLen = int(index)
240 n.maxNode = l
241 n.listIsClosed = isClosed
242 }
243
244 n.updateListType(l, t.id, isClosed, ellipsis)
245 }
246
247 func processListVertex(c *OpContext, t *task, mode runMode) {
248 n := t.node
249
250 l := t.x.(*Vertex)
251
252 elems := l.Elems()
253 isClosed := l.IsClosedList()
254
255
256 switch max := n.maxListLen; {
257 case len(elems) < max:
258 if isClosed {
259 n.invalidListLength(len(elems), max, l, n.maxNode)
260 return
261 }
262
263 case len(elems) > max:
264 if n.listIsClosed {
265 n.invalidListLength(max, len(elems), n.maxNode, l)
266 return
267 }
268 n.listIsClosed = isClosed
269 n.maxListLen = len(elems)
270 n.maxNode = l
271
272 case isClosed:
273 n.listIsClosed = true
274 n.maxNode = l
275 }
276
277 for _, a := range elems {
278 if a.Conjuncts == nil {
279 c := MakeRootConjunct(nil, a)
280 n.insertArc(a.Label, ArcMember, c, CloseInfo{}, true)
281 continue
282 }
283 for _, c := range a.Conjuncts {
284 c.CloseInfo.cc = t.id.cc
285 n.insertArc(a.Label, ArcMember, c, t.id, true)
286 }
287 }
288
289 n.updateListType(l, t.id, isClosed, nil)
290 }
291
292 func (n *nodeContext) updateListType(list Expr, id CloseInfo, isClosed bool, ellipsis Node) {
293 m, ok := n.node.BaseValue.(*ListMarker)
294 if !ok {
295 m = &ListMarker{
296 IsOpen: true,
297 }
298 n.node.setValue(n.ctx, partial, m)
299 }
300 m.IsOpen = m.IsOpen && !isClosed
301
302 if ellipsis != nil {
303 if src, _ := ellipsis.Source().(ast.Expr); src != nil {
304 if m.Src == nil {
305 m.Src = src
306 } else {
307 m.Src = ast.NewBinExpr(token.AND, m.Src, src)
308 }
309 }
310 }
311
312 if n.kind != ListKind {
313 n.updateNodeType(ListKind, list, id)
314 }
315 }
316
View as plain text