blob: 654fdc08d1722b567c730eaf6ea8be9b8ed2a822 [file] [log] [blame]
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001// Copyright 2020 CUE Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15// Package eval contains the high level CUE evaluation strategy.
16//
17// CUE allows for a significant amount of freedom in order of evaluation due to
18// the commutativity of the unification operation. This package implements one
19// of the possible strategies.
20package eval
21
22// TODO:
23// - result should be nodeContext: this allows optionals info to be extracted
24// and computed.
25//
26
27import (
28 "fmt"
Marcel van Lohuizen17ade832020-07-15 20:18:40 +020029 "html/template"
30 "strings"
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +020031
32 "cuelang.org/go/cue/ast"
33 "cuelang.org/go/cue/errors"
34 "cuelang.org/go/cue/token"
35 "cuelang.org/go/internal/core/adt"
36 "cuelang.org/go/internal/core/debug"
37)
38
Marcel van Lohuizen62528c32020-09-10 09:29:45 +020039var Debug = false
40
Marcel van Lohuizen17ade832020-07-15 20:18:40 +020041// TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO
42//
43// - Reuse work from previous cycles. For instance, if we can guarantee that a
44// value is always correct for partial results, we can just process the arcs
45// going from Partial to Finalized, without having to reevaluate the value.
46//
47// - Test closedness far more thoroughly.
48//
49
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +020050func Evaluate(r adt.Runtime, v *adt.Vertex) {
51 format := func(n adt.Node) string {
52 return debug.NodeString(r, n, printConfig)
53 }
54 e := New(r)
55 c := adt.New(v, &adt.Config{
56 Runtime: r,
57 Unifier: e,
58 Format: format,
59 })
60 e.Unify(c, v, adt.Finalized)
61}
62
63func New(r adt.Runtime) *Evaluator {
64 return &Evaluator{r: r, index: r}
65}
66
Marcel van Lohuizen17ade832020-07-15 20:18:40 +020067type Stats struct {
68 DisjunctCount int
69 UnifyCount int
70}
71
72var stats = template.Must(template.New("stats").Parse(`{{"" -}}
73Unifications: {{.UnifyCount}}
74Disjuncts: {{.DisjunctCount}}`))
75
76func (s *Stats) String() string {
77 buf := strings.Builder{}
78 _ = stats.Execute(&buf, s)
79 return buf.String()
80}
81
82func (e *Evaluator) Stats() *Stats {
83 return &e.stats
84}
85
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +020086// TODO: Note: NewContext takes essentially a cue.Value. By making this
87// type more central, we can perhaps avoid context creation.
88
89func NewContext(r adt.Runtime, v *adt.Vertex) *adt.OpContext {
90 e := New(r)
91 return e.NewContext(v)
92}
93
94var printConfig = &debug.Config{Compact: true}
95
96func (e *Evaluator) NewContext(v *adt.Vertex) *adt.OpContext {
97 format := func(n adt.Node) string {
98 return debug.NodeString(e.r, n, printConfig)
99 }
100 return adt.New(v, &adt.Config{
101 Runtime: e.r,
102 Unifier: e,
103 Format: format,
104 })
105}
106
107var structSentinel = &adt.StructMarker{}
108
109var incompleteSentinel = &adt.Bottom{
110 Code: adt.IncompleteError,
111 Err: errors.Newf(token.NoPos, "incomplete"),
112}
113
114type Evaluator struct {
Marcel van Lohuizen62528c32020-09-10 09:29:45 +0200115 r adt.Runtime
116 index adt.StringIndexer
Marcel van Lohuizen17ade832020-07-15 20:18:40 +0200117
118 stats Stats
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200119}
120
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200121func (e *Evaluator) Eval(v *adt.Vertex) errors.Error {
122 if v.Value == nil {
123 ctx := adt.NewContext(e.r, e, v)
124 e.Unify(ctx, v, adt.Finalized)
125 }
126
127 // extract error if needed.
128 return nil
129}
130
131// Evaluate is used to evaluate a sub expression while evaluating a Vertex
132// with Unify. It may or may not return the original Vertex. It may also
133// terminate evaluation early if it has enough evidence that a certain value
134// can be the only value in a valid configuration. This means that an error
135// may go undetected at this point, as long as it is caught later.
136//
137func (e *Evaluator) Evaluate(c *adt.OpContext, v *adt.Vertex) adt.Value {
138 var resultValue adt.Value
139 if v.Value == nil {
140 save := *v
141 // Use node itself to allow for cycle detection.
Marcel van Lohuizend15def32020-07-19 18:17:40 +0200142 s := e.evalVertex(c, v, adt.Partial, nil)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200143
144 if d := s.disjunct; d != nil && len(d.Values) > 1 && d.NumDefaults != 1 {
145 v.Value = d
146 v.Arcs = nil
147 v.Structs = nil // TODO: maybe not do this.
148 // The conjuncts will have too much information. Better have no
149 // information than incorrect information.
150 for _, d := range d.Values {
151 d.Conjuncts = nil
Marcel van Lohuizenb68adfe2020-07-19 18:24:38 +0200152 for _, a := range d.Arcs {
153 for _, x := range a.Conjuncts {
154 // All the environments for embedded structs need to be
155 // dereferenced.
156 for env := x.Env; env != nil && env.Vertex == v; env = env.Up {
157 env.Vertex = d
158 }
159 }
160 }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200161 }
162 }
163
164 resultValue = v.Value
165
166 result := s.result()
167 *v = save
168
169 if result.Value != nil {
170 *v = *result
171 resultValue = result.Value
172 }
173
174 // TODO: this seems unnecessary as long as we have a better way
175 // to handle incomplete, and perhaps referenced. nodes.
176 if c.IsTentative() && isStruct(v) {
177 // TODO(perf): do something more efficient perhaps? This discards
178 // the computed arcs so far. Instead, we could have a separate
179 // marker to accumulate results. As this only happens within
180 // comprehensions, the effect is likely minimal, though.
181 arcs := v.Arcs
182 *v = save
183 return &adt.Vertex{
184 Parent: v.Parent,
185 Value: &adt.StructMarker{},
186 Arcs: arcs,
Marcel van Lohuizencfc6c8c2020-07-22 21:45:03 +0200187 Closed: result.Closed,
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200188 }
189 }
190 // *v = save // DO NOT ADD.
191 err, _ := resultValue.(*adt.Bottom)
192 // BEFORE RESTORING, copy the value to return one
193 // with the temporary arcs.
194 if !s.done() && (err == nil || err.IsIncomplete()) {
195 // Clear values afterwards
196 *v = save
197 }
198 if !s.done() && s.hasDisjunction() {
199 return &adt.Bottom{Code: adt.IncompleteError}
200 }
201 if s.hasResult() {
202 if b, _ := v.Value.(*adt.Bottom); b != nil {
203 *v = save
204 return b
205 }
206 // TODO: Only use result when not a cycle.
207 v = result
208 }
209 // TODO: Store if concrete and fully resolved.
210
211 } else {
212 b, _ := v.Value.(*adt.Bottom)
213 if b != nil {
214 return b
215 }
216 }
217
218 switch v.Value.(type) {
219 case nil:
220 // Error saved in result.
221 return resultValue // incomplete
222
223 case *adt.ListMarker, *adt.StructMarker:
224 return v
225
226 default:
227 return v.Value
228 }
229}
230
231// Unify implements adt.Unifier.
232//
233// May not evaluate the entire value, but just enough to be able to compute.
234//
235// Phase one: record everything concrete
236// Phase two: record incomplete
237// Phase three: record cycle.
238func (e *Evaluator) Unify(c *adt.OpContext, v *adt.Vertex, state adt.VertexStatus) {
Marcel van Lohuizend15def32020-07-19 18:17:40 +0200239 e.UnifyAccept(c, v, state, nil) //v.Closed)
240}
241
242// UnifyAccept is like Unify, but takes an extra argument to override the
243// accepted set of fields.
244//
245// Instead of deriving the allowed set of fields, it verifies this set by
246// consulting the given Acceptor. This can be useful when splitting an existing
247// values into individual conjuncts and then unifying some of its components
248// back into a new value. Under normal circumstances, this may not always
249// succeed as the missing context may result in stricter closedness rules.
250func (e *Evaluator) UnifyAccept(c *adt.OpContext, v *adt.Vertex, state adt.VertexStatus, accept adt.Acceptor) {
251
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200252 // defer c.PopVertex(c.PushVertex(v))
253
254 if state <= v.Status()+1 {
255 return
256 }
257
258 if x := v.Value; x != nil {
259 // if state == adt.Partial || x == cycle {
260 // return
261 // }
262 return
263 }
264
Marcel van Lohuizend15def32020-07-19 18:17:40 +0200265 n := e.evalVertex(c, v, state, accept)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200266
267 switch d := n.disjunct; {
268 case d != nil && len(d.Values) == 1:
269 *v = *(d.Values[0])
270
271 case d != nil && len(d.Values) > 0:
272 v.Value = d
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200273 // The conjuncts will have too much information. Better have no
274 // information than incorrect information.
275 for _, d := range d.Values {
Marcel van Lohuizenb68adfe2020-07-19 18:24:38 +0200276 // We clear the conjuncts for now. As these disjuncts are for API
277 // use only, we will fill them out when necessary (using Defaults).
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200278 d.Conjuncts = nil
Marcel van Lohuizenb68adfe2020-07-19 18:24:38 +0200279
280 // TODO: use a more principled form of dereferencing. For instance,
281 // disjuncts could already be assumed to be the given Vertex, and
282 // the the main vertex could be dereferenced during evaluation.
283 for _, a := range d.Arcs {
284 for _, x := range a.Conjuncts {
285 // All the environments for embedded structs need to be
286 // dereferenced.
287 for env := x.Env; env != nil && env.Vertex == v; env = env.Up {
288 env.Vertex = d
289 }
290 }
291 }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200292 }
Marcel van Lohuizenb68adfe2020-07-19 18:24:38 +0200293 v.Arcs = nil
294 // v.Structs = nil // TODO: should we keep or discard the Structs?
Marcel van Lohuizend15def32020-07-19 18:17:40 +0200295 v.Closed = newDisjunctionAcceptor(n.disjunct)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200296
297 default:
298 if r := n.result(); r.Value != nil {
299 *v = *r
300 }
301 }
302
303 // Else set it to something.
304
305 if v.Value == nil {
Marcel van Lohuizend15def32020-07-19 18:17:40 +0200306 panic("error")
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200307 }
308
309 // Check whether result is done.
310}
311
312// evalVertex computes the vertex results. The state indicates the minimum
313// status to which this vertex should be evaluated. It should be either
314// adt.Finalized or adt.Partial.
Marcel van Lohuizend15def32020-07-19 18:17:40 +0200315func (e *Evaluator) evalVertex(c *adt.OpContext, v *adt.Vertex, state adt.VertexStatus, accept adt.Acceptor) *nodeShared {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200316 shared := &nodeShared{
Marcel van Lohuizend15def32020-07-19 18:17:40 +0200317 ctx: c,
318 eval: e,
319 node: v,
320 stack: nil, // silence linter
321 accept: accept,
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200322 }
323 saved := *v
324
Marcel van Lohuizen62528c32020-09-10 09:29:45 +0200325 var closedInfo *acceptor
326 if v.Parent != nil {
327 closedInfo, _ = v.Parent.Closed.(*acceptor)
328 }
329
330 if !v.Label.IsInt() && closedInfo != nil {
331 ci := closedInfo
332 // Visit arcs recursively to validate and compute error.
333 switch ok, err := ci.verifyArc(c, v.Label, v); {
334 case err != nil:
335 // Record error in child node to allow recording multiple
336 // conflicts at the appropriate place, to allow valid fields to
337 // be represented normally and, most importantly, to avoid
338 // recursive processing of a disallowed field.
339 v.Value = err
340 v.SetValue(c, adt.Finalized, err)
341 return shared
342
343 case !ok: // hidden field
344 // A hidden field is except from checking. Ensure that the
345 // closedness doesn't carry over into children.
346 // TODO: make this more fine-grained per package, allowing
347 // checked restrictions to be defined within the package.
348 closedInfo = closedInfo.clone()
349 for i := range closedInfo.Canopy {
350 closedInfo.Canopy[i].IsDef = false
351 }
352 }
353 }
354
Marcel van Lohuizen651d3792020-07-20 10:36:31 +0200355 defer c.PopArc(c.PushArc(v))
356
Marcel van Lohuizen17ade832020-07-15 20:18:40 +0200357 e.stats.UnifyCount++
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200358 for i := 0; ; i++ {
Marcel van Lohuizen17ade832020-07-15 20:18:40 +0200359 e.stats.DisjunctCount++
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200360
361 // Clear any remaining error.
362 if err := c.Err(); err != nil {
363 panic("uncaught error")
364 }
365
366 // Set the cache to a cycle error to ensure a cyclic reference will result
367 // in an error if applicable. A cyclic error may be ignored for
368 // non-expression references. The cycle error may also be removed as soon
369 // as there is evidence what a correct value must be, but before all
370 // validation has taken place.
371 *v = saved
372 v.Value = cycle
Marcel van Lohuizen62528c32020-09-10 09:29:45 +0200373
374 if closedInfo != nil {
375 v.Closed = closedInfo.clone()
376 }
377
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200378 v.UpdateStatus(adt.Evaluating)
379
380 // If the result is a struct, it needs to be closed if:
381 // 1) this node introduces a definition
382 // 2) this node is a child of a node that introduces a definition,
383 // recursively.
384 // 3) this node embeds a closed struct.
385 needClose := v.Label.IsDef()
Marcel van Lohuizen62528c32020-09-10 09:29:45 +0200386 // if needClose {
387 // closedInfo.isClosed = true
388 // }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200389
390 n := &nodeContext{
Marcel van Lohuizenf0df4df2020-09-18 17:52:03 +0200391 arcMap: map[arcKey]bool{},
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200392 kind: adt.TopKind,
393 nodeShared: shared,
394 needClose: needClose,
395
396 // These get cleared upon proof to the contrary.
397 // isDefault: true,
398 isFinal: true,
399 }
400
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200401 for _, x := range v.Conjuncts {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200402 // TODO: needed for reentrancy. Investigate usefulness for cycle
403 // detection.
Marcel van Lohuizen62528c32020-09-10 09:29:45 +0200404 n.addExprConjunct(x)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200405 }
406
407 if i == 0 {
408 // Use maybeSetCache for cycle breaking
409 for n.maybeSetCache(); n.expandOne(); n.maybeSetCache() {
410 }
411 if v.Status() > adt.Evaluating && state <= adt.Partial {
412 // We have found a partial result. There may still be errors
413 // down the line which may result from further evaluating this
414 // field, but that will be caught when evaluating this field
415 // for real.
416 shared.setResult(v)
417 return shared
418 }
419 if !n.done() && len(n.disjunctions) > 0 && isEvaluating(v) {
420 // We disallow entering computations of disjunctions with
421 // incomplete data.
422 b := c.NewErrf("incomplete cause disjunction")
423 b.Code = adt.IncompleteError
424 v.SetValue(n.ctx, adt.Finalized, b)
425 shared.setResult(v)
426 return shared
427 }
428 }
429
430 // Handle disjunctions. If there are no disjunctions, this call is
431 // equivalent to calling n.postDisjunct.
432 if n.tryDisjuncts() {
433 if v.Value == nil {
434 v.Value = n.getValidators()
435 }
436
437 break
438 }
439 }
440
441 return shared
442}
443
444func isStruct(v *adt.Vertex) bool {
445 _, ok := v.Value.(*adt.StructMarker)
446 return ok
447}
448
449func (n *nodeContext) postDisjunct() {
450 ctx := n.ctx
451
Marcel van Lohuizend55e2b52020-08-25 18:04:24 +0200452 for {
453 // Use maybeSetCache for cycle breaking
454 for n.maybeSetCache(); n.expandOne(); n.maybeSetCache() {
455 }
456
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +0200457 if aList, id := n.addLists(ctx); aList != nil {
458 n.updateNodeType(adt.ListKind, aList, id)
Marcel van Lohuizend55e2b52020-08-25 18:04:24 +0200459 } else {
460 break
461 }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200462 }
463
Marcel van Lohuizend857f232020-07-23 16:00:19 +0200464 if n.aStruct != nil {
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +0200465 n.updateNodeType(adt.StructKind, n.aStruct, n.aStructID)
Marcel van Lohuizend857f232020-07-23 16:00:19 +0200466 }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200467
468 switch err := n.getErr(); {
469 case err != nil:
470 n.node.Value = err
471 n.errs = nil
472
473 default:
474 if isEvaluating(n.node) {
475 // TODO: this does not yet validate all values.
476
477 if !n.done() { // && !ctx.IsTentative() {
478 // collect incomplete errors.
479 // len(n.ifClauses) == 0 &&
480 // len(n.forClauses) == 0 &&
481 var err *adt.Bottom // n.incomplete
482 // err = n.incomplete
483 for _, d := range n.dynamicFields {
484 x, _ := ctx.Concrete(d.env, d.field.Key, "dynamic field")
485 b, _ := x.(*adt.Bottom)
486 err = adt.CombineErrors(nil, err, b)
487 }
488 for _, c := range n.forClauses {
489 f := func(env *adt.Environment, st *adt.StructLit) {}
490 err = adt.CombineErrors(nil, err, ctx.Yield(c.env, c.yield, f))
491 }
492 for _, x := range n.exprs {
493 x, _ := ctx.Evaluate(x.Env, x.Expr())
494 b, _ := x.(*adt.Bottom)
495 err = adt.CombineErrors(nil, err, b)
496 }
497 if err == nil {
498 // safeguard.
499 err = incompleteSentinel
500 }
501 n.node.Value = err
502 } else {
503 n.node.Value = nil
504 }
505 }
506
507 // We are no longer evaluating.
508 n.node.UpdateStatus(adt.Partial)
509
510 // Either set to Conjunction or error.
511 var v adt.Value = n.node.Value
Marcel van Lohuizend857f232020-07-23 16:00:19 +0200512 // TODO: verify and simplify the below code to determine whether
513 // something is a struct.
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200514 markStruct := false
Marcel van Lohuizend857f232020-07-23 16:00:19 +0200515 if n.aStruct != nil {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200516 markStruct = true
517 } else if len(n.node.Structs) > 0 {
Marcel van Lohuizend857f232020-07-23 16:00:19 +0200518 markStruct = n.kind&adt.StructKind != 0 && !n.hasTop
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200519 }
520 if v == nil && markStruct {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200521 n.node.Value = &adt.StructMarker{}
522 v = n.node
523 }
524 if v != nil && adt.IsConcrete(v) {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200525 if n.lowerBound != nil {
526 if b := ctx.Validate(n.lowerBound, v); b != nil {
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +0200527 // TODO(errors): make Validate return boolean and generate
528 // optimized conflict message. Also track and inject IDs
529 // to determine origin location.s
530 if e, _ := b.Err.(*adt.ValueError); e != nil {
531 e.AddPosition(n.lowerBound)
532 e.AddPosition(v)
533 }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200534 n.addBottom(b)
535 }
536 }
537 if n.upperBound != nil {
538 if b := ctx.Validate(n.upperBound, v); b != nil {
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +0200539 // TODO(errors): make Validate return boolean and generate
540 // optimized conflict message. Also track and inject IDs
541 // to determine origin location.s
542 if e, _ := b.Err.(*adt.ValueError); e != nil {
543 e.AddPosition(n.upperBound)
544 e.AddPosition(v)
545 }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200546 n.addBottom(b)
547 }
548 }
549 for _, v := range n.checks {
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +0200550 // TODO(errors): make Validate return boolean and generate
551 // optimized conflict message. Also track and inject IDs
552 // to determine origin location.s
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200553 if b := ctx.Validate(v, n.node); b != nil {
554 n.addBottom(b)
555 }
556 }
557
558 } else if !ctx.IsTentative() {
559 n.node.Value = n.getValidators()
560 }
561 // else if v == nil {
562 // n.node.Value = incompleteSentinel
563 // }
564
565 if v == nil {
566 break
567 }
568
569 switch {
570 case v.Kind() == adt.ListKind:
571 for _, a := range n.node.Arcs {
572 if a.Label.Typ() == adt.StringLabel {
Marcel van Lohuizen651d3792020-07-20 10:36:31 +0200573 n.addErr(ctx.Newf("list may not have regular fields"))
574 // TODO(errors): add positions for list and arc definitions.
575
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200576 }
577 }
578
579 // case !isStruct(n.node) && v.Kind() != adt.BottomKind:
580 // for _, a := range n.node.Arcs {
581 // if a.Label.IsRegular() {
582 // n.addErr(errors.Newf(token.NoPos,
Marcel van Lohuizen651d3792020-07-20 10:36:31 +0200583 // // TODO(errors): add positions of non-struct values and arcs.
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200584 // "cannot combine scalar values with arcs"))
585 // }
586 // }
587 }
588 }
589
Marcel van Lohuizencfc6c8c2020-07-22 21:45:03 +0200590 n.updateClosedInfo()
591
592 if cyclic := n.hasCycle && !n.hasNonCycle; cyclic {
593 n.node.Value = adt.CombineErrors(nil, n.node.Value, &adt.Bottom{
594 Code: adt.StructuralCycleError,
595 Err: ctx.Newf("structural cycle"),
596 Value: n.node.Value,
597 // TODO: probably, this should have the referenced arc.
598 })
599 } else {
600 // Visit arcs recursively to validate and compute error.
601 for _, a := range n.node.Arcs {
602 // Call UpdateStatus here to be absolutely sure the status is set
603 // correctly and that we are not regressing.
604 n.node.UpdateStatus(adt.EvaluatingArcs)
605 n.eval.Unify(ctx, a, adt.Finalized)
606 if err, _ := a.Value.(*adt.Bottom); err != nil {
607 n.node.AddChildError(err)
608 }
609 }
610 }
611
612 n.node.UpdateStatus(adt.Finalized)
613}
614
615func (n *nodeContext) updateClosedInfo() {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200616 if err := n.getErr(); err != nil {
617 if b, _ := n.node.Value.(*adt.Bottom); b != nil {
618 err = adt.CombineErrors(nil, b, err)
619 }
620 n.node.Value = err
621 // TODO: add return: if evaluation of arcs is important it can be done
622 // later. Logically we're done.
623 }
624
Marcel van Lohuizen62528c32020-09-10 09:29:45 +0200625 if n.node.IsList() {
626 return
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200627 }
628
Marcel van Lohuizen62528c32020-09-10 09:29:45 +0200629 a, _ := n.node.Closed.(*acceptor)
630 if a == nil {
631 if !n.node.IsList() && !n.needClose {
632 return
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200633 }
Marcel van Lohuizen62528c32020-09-10 09:29:45 +0200634 a = closedInfo(n.node)
635 }
636
637 // TODO: set this earlier.
638 n.needClose = n.needClose || a.isClosed
639 a.isClosed = n.needClose
640
641 // TODO: consider removing this. Now checking is done at the top of
642 // evalVertex, skipping one level of checks happens naturally again
643 // for Value.Unify (API).
644 ctx := n.ctx
645
646 if accept := n.nodeShared.accept; accept != nil {
647 for _, a := range n.node.Arcs {
648 if !accept.Accept(n.ctx, a.Label) {
649 label := a.Label.SelectorString(ctx)
650 n.node.Value = ctx.NewErrf(
651 "field `%s` not allowed by Acceptor", label)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200652 }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200653 }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200654 }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200655}
656
657// TODO: this is now a sentinel. Use a user-facing error that traces where
658// the cycle originates.
659var cycle = &adt.Bottom{
660 Err: errors.Newf(token.NoPos, "cycle error"),
661 Code: adt.CycleError,
662}
663
664func isEvaluating(v *adt.Vertex) bool {
665 isCycle := v.Status() == adt.Evaluating
666 if isCycle != (v.Value == cycle) {
667 panic(fmt.Sprintf("cycle data of sync %d vs %#v", v.Status(), v.Value))
668 }
669 return isCycle
670}
671
672type nodeShared struct {
673 eval *Evaluator
674 ctx *adt.OpContext
675 sub []*adt.Environment // Environment cache
676 node *adt.Vertex
677
678 // Disjunction handling
679 disjunct *adt.Disjunction
680 resultNode *nodeContext
681 result_ adt.Vertex
682 stack []int
Marcel van Lohuizend15def32020-07-19 18:17:40 +0200683
684 // Closedness override.
685 accept adt.Acceptor
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200686}
687
688func (n *nodeShared) result() *adt.Vertex {
689 return &n.result_
690}
691
692func (n *nodeShared) setResult(v *adt.Vertex) {
693 n.result_ = *v
694}
695
696func (n *nodeShared) hasResult() bool {
697 return n.resultNode != nil //|| n.hasResult_
698 // return n.resultNode != nil || n.hasResult_
699}
700
701func (n *nodeShared) done() bool {
702 // if d := n.disjunct; d == nil || len(n.disjunct.Values) == 0 {
703 // return false
704 // }
705 if n.resultNode == nil {
706 return false
707 }
708 return n.resultNode.done()
709}
710
711func (n *nodeShared) hasDisjunction() bool {
712 if n.resultNode == nil {
713 return false
714 }
715 return len(n.resultNode.disjunctions) > 0
716}
717
718func (n *nodeShared) isDefault() bool {
719 if n.resultNode == nil {
720 return false
721 }
722 return n.resultNode.defaultMode == isDefault
723}
724
Marcel van Lohuizenf0df4df2020-09-18 17:52:03 +0200725type arcKey struct {
726 arc *adt.Vertex
727 id adt.ID
728}
729
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200730// A nodeContext is used to collate all conjuncts of a value to facilitate
731// unification. Conceptually order of unification does not matter. However,
732// order has relevance when performing checks of non-monotic properities. Such
733// checks should only be performed once the full value is known.
734type nodeContext struct {
735 *nodeShared
736
737 // TODO:
738 // filter *adt.Vertex a subset of composite with concrete fields for
739 // bloom-like filtering of disjuncts. We should first verify, however,
740 // whether some breath-first search gives sufficient performance, as this
741 // should already ensure a quick-fail for struct disjunctions with
742 // discriminators.
743
Marcel van Lohuizenf0df4df2020-09-18 17:52:03 +0200744 arcMap map[arcKey]bool
745
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200746 // Current value (may be under construction)
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +0200747 scalar adt.Value // TODO: use Value in node.
748 scalarID adt.ID
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200749
750 // Concrete conjuncts
751 kind adt.Kind
Marcel van Lohuizend857f232020-07-23 16:00:19 +0200752 kindExpr adt.Expr // expr that adjust last value (for error reporting)
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +0200753 kindID adt.ID // for error tracing
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200754 lowerBound *adt.BoundValue // > or >=
755 upperBound *adt.BoundValue // < or <=
756 checks []adt.Validator // BuiltinValidator, other bound values.
757 errs *adt.Bottom
758 incomplete *adt.Bottom
759
760 // Struct information
761 dynamicFields []envDynamic
762 ifClauses []envYield
763 forClauses []envYield
Marcel van Lohuizen62528c32020-09-10 09:29:45 +0200764 // TODO: remove this and annotate directly in acceptor.
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200765 needClose bool
Marcel van Lohuizend857f232020-07-23 16:00:19 +0200766 aStruct adt.Expr
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +0200767 aStructID adt.ID
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200768 hasTop bool
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200769
770 // Expression conjuncts
771 lists []envList
772 vLists []*adt.Vertex
Marcel van Lohuizen62528c32020-09-10 09:29:45 +0200773 exprs []adt.Conjunct
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200774
Marcel van Lohuizen711bbb12020-07-06 17:16:30 +0200775 hasCycle bool // has conjunct with structural cycle
776 hasNonCycle bool // has conjunct without structural cycle
777
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200778 // Disjunction handling
779 disjunctions []envDisjunct
780 defaultMode defaultMode
781 isFinal bool
782}
783
Marcel van Lohuizen62528c32020-09-10 09:29:45 +0200784func closedInfo(n *adt.Vertex) *acceptor {
785 a, _ := n.Closed.(*acceptor)
786 if a == nil {
787 a = &acceptor{}
788 n.Closed = a
789 }
790 return a
791}
792
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +0200793// TODO(errors): return a dedicated ConflictError that can track original
794// positions on demand.
795//
796// Fully detailed origin tracking could be created on the back of CloseIDs
797// tracked in acceptor.Canopy. To make this fully functional, the following
798// still needs to be implemented:
799//
800// - We need to know the ID for every value involved in the conflict.
801// (There may be multiple if the result comes from a simplification).
802// - CloseIDs should be forked not only for definitions, but all references.
803// - Upon forking a CloseID, it should keep track of its enclosing CloseID
804// as well (probably as a pointer to the origin so that the reference
805// persists after compaction).
806//
807// The modifications to the CloseID algorithm may also benefit the computation
808// of `{ #A } == #A`, which currently is not done.
809//
810func (n *nodeContext) addConflict(
811 v1, v2 adt.Node,
812 k1, k2 adt.Kind,
813 id1, id2 adt.ID) {
814
815 ctx := n.ctx
816
817 var err *adt.ValueError
818 if k1 == k2 {
819 err = ctx.NewPosf(token.NoPos,
820 "conflicting values %s and %s", ctx.Str(v1), ctx.Str(v2))
821 } else {
822 err = ctx.NewPosf(token.NoPos,
823 "conflicting values %s and %s (mismatched types %s and %s)",
824 ctx.Str(v1), ctx.Str(v2), k1, k2)
825 }
826
827 ci := closedInfo(n.node)
828 err.AddPosition(v1)
829 err.AddPosition(v2)
830 err.AddPosition(ci.node(id1).Src)
831 err.AddPosition(ci.node(id2).Src)
832
833 n.addErr(err)
834}
835
836func (n *nodeContext) updateNodeType(k adt.Kind, v adt.Expr, id adt.ID) bool {
Marcel van Lohuizend857f232020-07-23 16:00:19 +0200837 ctx := n.ctx
838 kind := n.kind & k
839
840 switch {
841 case n.kind == adt.BottomKind,
842 k == adt.BottomKind:
843 return false
844
845 case kind == adt.BottomKind:
846 if n.kindExpr != nil {
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +0200847 n.addConflict(n.kindExpr, v, n.kind, k, n.kindID, id)
Marcel van Lohuizend857f232020-07-23 16:00:19 +0200848 } else {
849 n.addErr(ctx.Newf(
850 "conflicting value %s (mismatched types %s and %s)",
851 ctx.Str(v), n.kind, k))
852 }
853 }
854
855 n.kind = kind
856 n.kindExpr = v
857 return kind != adt.BottomKind
858}
859
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200860func (n *nodeContext) done() bool {
861 return len(n.dynamicFields) == 0 &&
862 len(n.ifClauses) == 0 &&
863 len(n.forClauses) == 0 &&
864 len(n.exprs) == 0
865}
866
867// hasErr is used to determine if an evaluation path, for instance a single
868// path after expanding all disjunctions, has an error.
869func (n *nodeContext) hasErr() bool {
870 if n.node.ChildErrors != nil {
871 return true
872 }
873 if n.node.Status() > adt.Evaluating && n.node.IsErr() {
874 return true
875 }
876 return n.ctx.HasErr() || n.errs != nil
877}
878
879func (n *nodeContext) getErr() *adt.Bottom {
880 n.errs = adt.CombineErrors(nil, n.errs, n.ctx.Err())
881 return n.errs
882}
883
884// getValidators sets the vertex' Value in case there was no concrete value.
885func (n *nodeContext) getValidators() adt.Value {
886 ctx := n.ctx
887
888 a := []adt.Value{}
889 // if n.node.Value != nil {
890 // a = append(a, n.node.Value)
891 // }
892 kind := adt.TopKind
893 if n.lowerBound != nil {
894 a = append(a, n.lowerBound)
895 kind &= n.lowerBound.Kind()
896 }
897 if n.upperBound != nil {
898 a = append(a, n.upperBound)
899 kind &= n.upperBound.Kind()
900 }
901 for _, c := range n.checks {
902 // Drop !=x if x is out of bounds with another bound.
903 if b, _ := c.(*adt.BoundValue); b != nil && b.Op == adt.NotEqualOp {
904 if n.upperBound != nil &&
905 adt.SimplifyBounds(ctx, n.kind, n.upperBound, b) != nil {
906 continue
907 }
908 if n.lowerBound != nil &&
909 adt.SimplifyBounds(ctx, n.kind, n.lowerBound, b) != nil {
910 continue
911 }
912 }
913 a = append(a, c)
914 kind &= c.Kind()
915 }
916 if kind&^n.kind != 0 {
917 a = append(a, &adt.BasicType{K: n.kind})
918 }
919
920 var v adt.Value
921 switch len(a) {
922 case 0:
923 // Src is the combined input.
924 v = &adt.BasicType{K: n.kind}
925
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200926 if len(n.node.Structs) > 0 {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200927 v = structSentinel
928
929 }
930
931 case 1:
932 v = a[0].(adt.Value)
933
934 default:
935 v = &adt.Conjunction{Values: a}
936 }
937
938 return v
939}
940
941func (n *nodeContext) maybeSetCache() {
942 if n.node.Status() > adt.Evaluating { // n.node.Value != nil
943 return
944 }
945 if n.scalar != nil {
946 n.node.SetValue(n.ctx, adt.Partial, n.scalar)
947 }
948 if n.errs != nil {
949 n.node.SetValue(n.ctx, adt.Partial, n.errs)
950 }
951}
952
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200953type envDynamic struct {
954 env *adt.Environment
955 field *adt.DynamicField
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +0200956 id adt.ID
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200957}
958
959type envYield struct {
960 env *adt.Environment
961 yield adt.Yielder
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +0200962 id adt.ID
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200963}
964
965type envList struct {
966 env *adt.Environment
967 list *adt.ListLit
968 n int64 // recorded length after evaluator
969 elipsis *adt.Ellipsis
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +0200970 id adt.ID
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200971}
972
973func (n *nodeContext) addBottom(b *adt.Bottom) {
974 n.errs = adt.CombineErrors(nil, n.errs, b)
975}
976
977func (n *nodeContext) addErr(err errors.Error) {
978 if err != nil {
979 n.errs = adt.CombineErrors(nil, n.errs, &adt.Bottom{
980 Err: err,
981 })
982 }
983}
984
985// addExprConjuncts will attempt to evaluate an adt.Expr and insert the value
986// into the nodeContext if successful or queue it for later evaluation if it is
987// incomplete or is not value.
Marcel van Lohuizen62528c32020-09-10 09:29:45 +0200988func (n *nodeContext) addExprConjunct(v adt.Conjunct) {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200989 env := v.Env
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +0200990 id := v.CloseID
991
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200992 switch x := v.Expr().(type) {
993 case adt.Value:
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +0200994 n.addValueConjunct(env, x, id)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +0200995
996 case *adt.BinaryExpr:
997 if x.Op == adt.AndOp {
Marcel van Lohuizen62528c32020-09-10 09:29:45 +0200998 n.addExprConjunct(adt.MakeConjunct(env, x.X, id))
999 n.addExprConjunct(adt.MakeConjunct(env, x.Y, id))
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001000 } else {
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001001 n.evalExpr(v)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001002 }
1003
1004 case *adt.StructLit:
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001005 n.addStruct(env, x, id)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001006
1007 case *adt.ListLit:
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001008 n.lists = append(n.lists, envList{env: env, list: x, id: id})
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001009
1010 case *adt.DisjunctionExpr:
1011 if n.disjunctions != nil {
1012 _ = n.disjunctions
1013 }
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001014 n.addDisjunction(env, x, id)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001015
1016 default:
1017 // Must be Resolver or Evaluator.
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001018 n.evalExpr(v)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001019 }
1020}
1021
1022// evalExpr is only called by addExprConjunct.
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001023func (n *nodeContext) evalExpr(v adt.Conjunct) {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001024 // Require an Environment.
1025 ctx := n.ctx
1026
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001027 closeID := v.CloseID
1028
Marcel van Lohuizen711bbb12020-07-06 17:16:30 +02001029 // TODO: see if we can do without these counters.
1030 for _, d := range v.Env.Deref {
1031 d.EvalCount++
1032 }
1033 for _, d := range v.Env.Cycles {
1034 d.SelfCount++
1035 }
1036 defer func() {
1037 for _, d := range v.Env.Deref {
1038 d.EvalCount--
1039 }
1040 for _, d := range v.Env.Cycles {
1041 d.SelfCount++
1042 }
1043 }()
1044
1045outer:
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001046 switch x := v.Expr().(type) {
1047 case adt.Resolver:
1048 arc, err := ctx.Resolve(v.Env, x)
1049 if err != nil {
1050 if err.IsIncomplete() {
1051 n.incomplete = adt.CombineErrors(nil, n.incomplete, err)
1052 } else {
1053 n.addBottom(err)
1054 break
1055 }
1056 }
1057 if arc == nil {
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001058 n.exprs = append(n.exprs, v)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001059 break
1060 }
1061
Marcel van Lohuizenf0df4df2020-09-18 17:52:03 +02001062 // We need to ensure that each arc is only unified once (or at least) a
1063 // bounded time, witch each conjunct. Comprehensions, for instance, may
1064 // distribute a value across many values that get unified back into the
1065 // same value. If such a value is a disjunction, than a disjunction of N
1066 // disjuncts will result in a factor N more unifications for each
1067 // occurrence of such value, resulting in exponential running time. This
1068 // is especially common values that are used as a type.
1069 //
1070 // However, unification is idempotent, so each such conjunct only needs
1071 // to be unified once. This cache checks for this and prevents an
1072 // exponential blowup in such case.
1073 //
1074 // TODO(perf): this cache ensures the conjuncts of an arc at most once
1075 // per ID. However, we really need to add the conjuncts of an arc only
1076 // once total, and then add the close information once per close ID
1077 // (pointer can probably be shared). Aside from being more performant,
1078 // this is probably the best way to guarantee that conjunctions are
1079 // linear in this case.
1080 if n.arcMap[arcKey{arc, v.CloseID}] {
1081 return
1082 }
1083 n.arcMap[arcKey{arc, v.CloseID}] = true
1084
Marcel van Lohuizen711bbb12020-07-06 17:16:30 +02001085 // Pass detection of structural cycles from parent to children.
1086 cyclic := false
1087 if v.Env != nil {
1088 // If a reference is in a tainted set, so is the value it refers to.
1089 cyclic = v.Env.Cyclic
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001090 }
1091
Marcel van Lohuizen711bbb12020-07-06 17:16:30 +02001092 status := arc.Status()
1093 for _, d := range v.Env.Deref {
1094 if d == arc {
1095 status = adt.EvaluatingArcs
1096 }
1097 }
1098
1099 switch status {
1100 case adt.Evaluating:
1101 // Reference cycle detected. We have reached a fixed point and
1102 // adding conjuncts at this point will not change the value. Also,
1103 // continuing to pursue this value will result in an infinite loop.
1104
1105 // TODO: add a mechanism so that the computation will only have to
1106 // be done once?
1107
1108 if arc == n.node {
1109 // TODO: we could use node sharing here. This may avoid an
1110 // exponential blowup during evaluation, like is possible with
1111 // YAML.
1112 break outer
1113 }
1114
1115 case adt.EvaluatingArcs:
1116 // Structural cycle detected. Continue evaluation as usual, but
1117 // keep track of whether any other conjuncts without structural
1118 // cycles are added. If not, evaluation of child arcs will end
1119 // with this node.
1120
1121 // For the purpose of determining whether at least one non-cyclic
1122 // conjuncts exists, we consider all conjuncts of a cyclic conjuncts
1123 // also cyclic.
1124
1125 cyclic = true
1126 n.hasCycle = true
1127
1128 // As the adt.EvaluatingArcs mechanism bypasses the self-reference
1129 // mechanism, we need to separately keep track of it here.
1130 // If this (originally) is a self-reference node, adding them
1131 // will result in recursively adding the same reference. For this
1132 // we also mark the node as evaluating.
1133 if arc.SelfCount > 0 {
1134 break outer
1135 }
1136
1137 // This count is added for values that are directly added below.
1138 // The count is handled separately for delayed values.
1139 arc.SelfCount++
1140 defer func() { arc.SelfCount-- }()
1141 }
1142
Marcel van Lohuizen15e8a052020-09-21 08:49:32 +02001143 if isDef(v.Expr()) { // should test whether closed, not isDef?
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001144 c := closedInfo(n.node)
1145 closeID = c.InsertDefinition(v.CloseID, x)
1146 n.needClose = true // TODO: is this still necessary?
1147 }
1148
Marcel van Lohuizen711bbb12020-07-06 17:16:30 +02001149 // TODO: uncommenting the following almost works, but causes some
1150 // faulty results in complex cycle handling between disjunctions.
1151 // The reason is that disjunctions must be eliminated if checks in
1152 // values on which they depend fail.
1153 ctx.Unify(ctx, arc, adt.Finalized)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001154
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001155 for _, c := range arc.Conjuncts {
1156 c = updateCyclic(c, cyclic, arc)
1157 c.CloseID = closeID
1158 n.addExprConjunct(c)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001159 }
1160
1161 case adt.Evaluator:
1162 // adt.Interpolation, adt.UnaryExpr, adt.BinaryExpr, adt.CallExpr
Marcel van Lohuizen711bbb12020-07-06 17:16:30 +02001163 // Could be unify?
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001164 val, complete := ctx.Evaluate(v.Env, v.Expr())
1165 if !complete {
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001166 n.exprs = append(n.exprs, v)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001167 break
1168 }
1169
1170 if v, ok := val.(*adt.Vertex); ok {
1171 // Handle generated disjunctions (as in the 'or' builtin).
1172 // These come as a Vertex, but should not be added as a value.
1173 b, ok := v.Value.(*adt.Bottom)
1174 if ok && b.IsIncomplete() && len(v.Conjuncts) > 0 {
1175 for _, c := range v.Conjuncts {
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001176 c.CloseID = closeID
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001177 n.addExprConjunct(c)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001178 }
1179 break
1180 }
1181 }
1182
1183 // TODO: insert in vertex as well
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001184 n.addValueConjunct(v.Env, val, closeID)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001185
1186 default:
1187 panic(fmt.Sprintf("unknown expression of type %T", x))
1188 }
1189}
1190
Marcel van Lohuizen15e8a052020-09-21 08:49:32 +02001191// isDef reports whether an expressions is a reference that references a
1192// definition anywhere in its selection path.
1193//
1194// TODO(performance): this should be merged with resolve(). But for now keeping
1195// this code isolated makes it easier to see what it is for.
1196func isDef(x adt.Expr) bool {
1197 switch r := x.(type) {
1198 case *adt.FieldReference:
1199 return r.Label.IsDef()
1200
1201 case *adt.SelectorExpr:
1202 if r.Sel.IsDef() {
1203 return true
1204 }
1205 return isDef(r.X)
1206
1207 case *adt.IndexExpr:
1208 return isDef(r.X)
1209 }
1210 return false
1211}
1212
Marcel van Lohuizen711bbb12020-07-06 17:16:30 +02001213// updateCyclicStatus looks for proof of non-cyclic conjuncts to override
1214// a structural cycle.
1215func (n *nodeContext) updateCyclicStatus(env *adt.Environment) {
1216 if env == nil || !env.Cyclic {
1217 // fmt.Printf("%p -- %d hasNonCycle\n", n.node, n.node.Label)
1218 n.hasNonCycle = true
1219 }
1220}
1221
1222func updateCyclic(c adt.Conjunct, cyclic bool, deref *adt.Vertex) adt.Conjunct {
1223 env := c.Env
1224 switch {
1225 case env == nil:
1226 if !cyclic && deref == nil {
1227 return c
1228 }
1229 env = &adt.Environment{Cyclic: cyclic}
1230 case deref == nil && env.Cyclic == cyclic:
1231 return c
1232 default:
1233 // The conjunct may still be in use in other fields, so we should
1234 // make a new copy to mark Cyclic only for this case.
1235 e := *env
1236 e.Cyclic = e.Cyclic || cyclic
1237 env = &e
1238 }
1239 if deref != nil {
1240 env.Deref = append(env.Deref, deref)
1241 env.Cycles = append(env.Cycles, deref)
1242 }
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001243 return adt.MakeConjunct(env, c.Expr(), c.CloseID)
Marcel van Lohuizen711bbb12020-07-06 17:16:30 +02001244}
1245
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001246func (n *nodeContext) addValueConjunct(env *adt.Environment, v adt.Value, id adt.ID) {
Marcel van Lohuizen711bbb12020-07-06 17:16:30 +02001247 n.updateCyclicStatus(env)
1248
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001249 ctx := n.ctx
1250
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001251 if x, ok := v.(*adt.Vertex); ok {
Marcel van Lohuizenc72ce5d2020-09-15 12:09:54 +02001252 if m, ok := x.Value.(*adt.StructMarker); ok {
1253 n.aStruct = x
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001254 n.aStructID = id
Marcel van Lohuizenc72ce5d2020-09-15 12:09:54 +02001255 if m.NeedClose {
1256 ci := closedInfo(n.node)
1257 ci.isClosed = true // TODO: remove
1258 id = ci.InsertDefinition(id, x)
1259 ci.Canopy[id].IsClosed = true
1260 ci.Canopy[id].IsDef = false
1261 }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001262 }
1263
Marcel van Lohuizenc72ce5d2020-09-15 12:09:54 +02001264 cyclic := env != nil && env.Cyclic
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001265
Marcel van Lohuizenc72ce5d2020-09-15 12:09:54 +02001266 if !x.IsData() && len(x.Conjuncts) > 0 {
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001267 if isComplexStruct(x) {
1268 closedInfo(n.node).InsertSubtree(id, n, x, cyclic)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001269 return
1270 }
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001271
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001272 for _, c := range x.Conjuncts {
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001273 c = updateCyclic(c, cyclic, nil)
1274 c.CloseID = id
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001275 n.addExprConjunct(c) // TODO: Pass from eval
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001276 }
1277 return
1278 }
1279
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001280 // TODO: evaluate value?
1281 switch v := x.Value.(type) {
1282 case *adt.ListMarker:
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001283 n.vLists = append(n.vLists, x)
1284 return
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001285
1286 case *adt.StructMarker:
1287 for _, a := range x.Arcs {
Marcel van Lohuizenc72ce5d2020-09-15 12:09:54 +02001288 c := adt.MakeConjunct(nil, a, id)
1289 c = updateCyclic(c, cyclic, nil)
1290 n.insertField(a.Label, c)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001291 }
1292
1293 default:
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001294 n.addValueConjunct(env, v, id)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001295
1296 for _, a := range x.Arcs {
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001297 // TODO(errors): report error when this is a regular field.
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001298 n.insertField(a.Label, adt.MakeConjunct(nil, a, id))
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001299 // sub, _ := n.node.GetArc(a.Label)
1300 // sub.Add(a)
1301 }
1302 }
1303
1304 return
1305 // TODO: Use the Closer to close other fields as well?
1306 }
1307
1308 if b, ok := v.(*adt.Bottom); ok {
1309 n.addBottom(b)
1310 return
1311 }
1312
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001313 if !n.updateNodeType(v.Kind(), v, id) {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001314 return
1315 }
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001316
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001317 switch x := v.(type) {
1318 case *adt.Disjunction:
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001319 n.addDisjunctionValue(env, x, id)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001320
1321 case *adt.Conjunction:
1322 for _, x := range x.Values {
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001323 n.addValueConjunct(env, x, id)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001324 }
1325
1326 case *adt.Top:
1327 n.hasTop = true
1328 // TODO: Is this correct. Needed for elipsis, but not sure for others.
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001329 // n.optionals = append(n.optionals, fieldSet{env: env, id: id, isOpen: true})
1330 if a, _ := n.node.Closed.(*acceptor); a != nil {
1331 // Embedding top indicates that now all possible values are allowed
1332 // and that we should no longer enforce closedness within this
1333 // conjunct.
1334 a.node(id).IsDef = false
1335 }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001336
1337 case *adt.BasicType:
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001338 // handled above
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001339
1340 case *adt.BoundValue:
1341 switch x.Op {
1342 case adt.LessThanOp, adt.LessEqualOp:
1343 if y := n.upperBound; y != nil {
1344 n.upperBound = nil
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001345 v := adt.SimplifyBounds(ctx, n.kind, x, y)
1346 if err := valueError(v); err != nil {
1347 err.AddPosition(v)
1348 err.AddPosition(n.upperBound)
1349 err.AddPosition(closedInfo(n.node).node(id).Src)
1350 }
1351 n.addValueConjunct(env, v, id)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001352 return
1353 }
1354 n.upperBound = x
1355
1356 case adt.GreaterThanOp, adt.GreaterEqualOp:
1357 if y := n.lowerBound; y != nil {
1358 n.lowerBound = nil
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001359 v := adt.SimplifyBounds(ctx, n.kind, x, y)
1360 if err := valueError(v); err != nil {
1361 err.AddPosition(v)
1362 err.AddPosition(n.lowerBound)
1363 err.AddPosition(closedInfo(n.node).node(id).Src)
1364 }
1365 n.addValueConjunct(env, v, id)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001366 return
1367 }
1368 n.lowerBound = x
1369
1370 case adt.EqualOp, adt.NotEqualOp, adt.MatchOp, adt.NotMatchOp:
Marcel van Lohuizen1fdc02a2020-09-29 19:05:47 +02001371 // This check serves as simplifier, but also to remove duplicates.
1372 k := 0
1373 match := false
1374 for _, c := range n.checks {
1375 if y, ok := c.(*adt.BoundValue); ok {
1376 switch z := adt.SimplifyBounds(ctx, n.kind, x, y); {
1377 case z == y:
1378 match = true
1379 case z == x:
1380 continue
1381 }
1382 }
1383 n.checks[k] = c
1384 k++
1385 }
1386 n.checks = n.checks[:k]
1387 if !match {
1388 n.checks = append(n.checks, x)
1389 }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001390 return
1391 }
1392
1393 case adt.Validator:
Marcel van Lohuizen1fdc02a2020-09-29 19:05:47 +02001394 // This check serves as simplifier, but also to remove duplicates.
1395 for i, y := range n.checks {
1396 if b := adt.SimplifyValidator(ctx, x, y); b != nil {
1397 n.checks[i] = b
1398 return
1399 }
1400 }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001401 n.checks = append(n.checks, x)
1402
1403 case *adt.Vertex:
1404 // handled above.
1405
1406 case adt.Value: // *NullLit, *BoolLit, *NumLit, *StringLit, *BytesLit
1407 if y := n.scalar; y != nil {
1408 if b, ok := adt.BinOp(ctx, adt.EqualOp, x, y).(*adt.Bool); !ok || !b.B {
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001409 n.addConflict(x, y, x.Kind(), y.Kind(), n.scalarID, id)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001410 }
1411 // TODO: do we need to explicitly add again?
1412 // n.scalar = nil
1413 // n.addValueConjunct(c, adt.BinOp(c, adt.EqualOp, x, y))
1414 break
1415 }
1416 n.scalar = x
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001417 n.scalarID = id
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001418
1419 default:
1420 panic(fmt.Sprintf("unknown value type %T", x))
1421 }
1422
1423 if n.lowerBound != nil && n.upperBound != nil {
1424 if u := adt.SimplifyBounds(ctx, n.kind, n.lowerBound, n.upperBound); u != nil {
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001425 if err := valueError(u); err != nil {
1426 err.AddPosition(n.lowerBound)
1427 err.AddPosition(n.upperBound)
1428 err.AddPosition(closedInfo(n.node).node(id).Src)
1429 }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001430 n.lowerBound = nil
1431 n.upperBound = nil
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001432 n.addValueConjunct(env, u, id)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001433 }
1434 }
1435}
1436
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001437func valueError(v adt.Value) *adt.ValueError {
1438 if v == nil {
1439 return nil
1440 }
1441 b, _ := v.(*adt.Bottom)
1442 if b == nil {
1443 return nil
1444 }
1445 err, _ := b.Err.(*adt.ValueError)
1446 if err == nil {
1447 return nil
1448 }
1449 return err
1450}
1451
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001452// addStruct collates the declarations of a struct.
1453//
1454// addStruct fulfills two additional pivotal functions:
Oleg Kovalovbdb45b32020-07-22 14:47:38 +02001455// 1) Implement vertex unification (this happens through De Bruijn indices
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001456// combined with proper set up of Environments).
1457// 2) Implied closedness for definitions.
1458//
1459func (n *nodeContext) addStruct(
1460 env *adt.Environment,
1461 s *adt.StructLit,
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001462 closeID adt.ID) {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001463
Marcel van Lohuizen711bbb12020-07-06 17:16:30 +02001464 n.updateCyclicStatus(env) // to handle empty structs.
1465
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001466 ctx := n.ctx
1467 n.node.AddStructs(s)
1468
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001469 // NOTE: This is a crucial point in the code:
1470 // Unification derferencing happens here. The child nodes are set to
1471 // an Environment linked to the current node. Together with the De Bruijn
1472 // indices, this determines to which Vertex a reference resolves.
1473
1474 // TODO(perf): consider using environment cache:
1475 // var childEnv *adt.Environment
1476 // for _, s := range n.nodeCache.sub {
1477 // if s.Up == env {
1478 // childEnv = s
1479 // }
1480 // }
1481 childEnv := &adt.Environment{
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001482 Up: env,
1483 Vertex: n.node,
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001484 }
Marcel van Lohuizen711bbb12020-07-06 17:16:30 +02001485 if env != nil {
1486 childEnv.Cyclic = env.Cyclic
1487 childEnv.Deref = env.Deref
1488 }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001489
1490 var hasOther, hasBulk adt.Node
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001491 hasEmbed := false
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001492
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001493 opt := fieldSet{pos: s, env: childEnv, id: closeID}
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001494
1495 for _, d := range s.Decls {
1496 switch x := d.(type) {
1497 case *adt.Field:
1498 opt.MarkField(ctx, x)
1499 // handle in next iteration.
1500
1501 case *adt.OptionalField:
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001502 if x.Label.IsString() {
1503 n.aStruct = s
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001504 n.aStructID = closeID
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001505 }
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001506 opt.AddOptional(ctx, x)
1507
1508 case *adt.DynamicField:
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001509 n.aStruct = s
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001510 n.aStructID = closeID
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001511 hasOther = x
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001512 n.dynamicFields = append(n.dynamicFields, envDynamic{childEnv, x, closeID})
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001513 opt.AddDynamic(ctx, childEnv, x)
1514
1515 case *adt.ForClause:
1516 hasOther = x
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001517 n.forClauses = append(n.forClauses, envYield{childEnv, x, closeID})
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001518
1519 case adt.Yielder:
1520 hasOther = x
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001521 n.ifClauses = append(n.ifClauses, envYield{childEnv, x, closeID})
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001522
1523 case adt.Expr:
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001524 hasEmbed = true
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001525 hasOther = x
1526
1527 // add embedding to optional
1528
1529 // TODO(perf): only do this if addExprConjunct below will result in
1530 // a fieldSet. Otherwise the entry will just be removed next.
1531 id := closedInfo(n.node).InsertEmbed(closeID, x)
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001532
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001533 // push and opo embedding type.
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001534 n.addExprConjunct(adt.MakeConjunct(childEnv, x, id))
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001535
1536 case *adt.BulkOptionalField:
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001537 n.aStruct = s
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001538 n.aStructID = closeID
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001539 hasBulk = x
1540 opt.AddBulk(ctx, x)
1541
1542 case *adt.Ellipsis:
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001543 n.aStruct = s
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001544 n.aStructID = closeID
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001545 hasBulk = x
1546 opt.AddEllipsis(ctx, x)
1547
1548 default:
1549 panic("unreachable")
1550 }
1551 }
1552
1553 if hasBulk != nil && hasOther != nil {
Marcel van Lohuizen651d3792020-07-20 10:36:31 +02001554 n.addErr(ctx.Newf("cannot mix bulk optional fields with dynamic fields, embeddings, or comprehensions within the same struct"))
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001555 }
1556
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001557 if !hasEmbed {
1558 n.aStruct = s
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001559 n.aStructID = closeID
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001560 }
1561
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001562 // Apply existing fields
1563 for _, arc := range n.node.Arcs {
1564 // Reuse adt.Acceptor interface.
1565 opt.MatchAndInsert(ctx, arc)
1566 }
1567
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001568 closedInfo(n.node).insertFieldSet(closeID, &opt)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001569
1570 for _, d := range s.Decls {
1571 switch x := d.(type) {
1572 case *adt.Field:
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001573 if x.Label.IsString() {
1574 n.aStruct = s
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001575 n.aStructID = closeID
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001576 }
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001577 n.insertField(x.Label, adt.MakeConjunct(childEnv, x, closeID))
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001578 }
1579 }
1580}
1581
1582func (n *nodeContext) insertField(f adt.Feature, x adt.Conjunct) *adt.Vertex {
1583 ctx := n.ctx
1584 arc, isNew := n.node.GetArc(f)
1585
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001586 // TODO: disallow adding conjuncts when cache set?
1587 arc.AddConjunct(x)
1588
1589 if isNew {
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001590 closedInfo(n.node).visitAllFieldSets(func(o *fieldSet) {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001591 o.MatchAndInsert(ctx, arc)
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001592 })
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001593 }
1594 return arc
1595}
1596
1597// expandOne adds dynamic fields to a node until a fixed point is reached.
1598// On each iteration, dynamic fields that cannot resolve due to incomplete
1599// values are skipped. They will be retried on the next iteration until no
1600// progress can be made. Note that a dynamic field may add more dynamic fields.
1601//
1602// forClauses are processed after all other clauses. A struct may be referenced
1603// before it is complete, meaning that fields added by other forms of injection
1604// may influence the result of a for clause _after_ it has already been
1605// processed. We could instead detect such insertion and feed it to the
1606// ForClause to generate another entry or have the for clause be recomputed.
1607// This seems to be too complicated and lead to iffy edge cases.
Marcel van Lohuizen651d3792020-07-20 10:36:31 +02001608// TODO(errors): detect when a field is added to a struct that is already used
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001609// in a for clause.
1610func (n *nodeContext) expandOne() (done bool) {
1611 if n.done() {
1612 return false
1613 }
1614
1615 var progress bool
1616
1617 if progress = n.injectDynamic(); progress {
1618 return true
1619 }
1620
Marcel van Lohuizen304b02e2020-07-27 22:22:42 +02001621 if progress = n.injectEmbedded(&(n.ifClauses)); progress {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001622 return true
1623 }
1624
Marcel van Lohuizen304b02e2020-07-27 22:22:42 +02001625 if progress = n.injectEmbedded(&(n.forClauses)); progress {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001626 return true
1627 }
1628
1629 // Do expressions after comprehensions, as comprehensions can never
1630 // refer to embedded scalars, whereas expressions may refer to generated
1631 // fields if we were to allow attributes to be defined alongside
1632 // scalars.
1633 exprs := n.exprs
1634 n.exprs = n.exprs[:0]
1635 for _, x := range exprs {
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001636 n.addExprConjunct(x)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001637
1638 // collect and and or
1639 }
1640 if len(n.exprs) < len(exprs) {
1641 return true
1642 }
1643
1644 // No progress, report error later if needed: unification with
1645 // disjuncts may resolve this later later on.
1646 return false
1647}
1648
1649// injectDynamic evaluates and inserts dynamic declarations.
1650func (n *nodeContext) injectDynamic() (progress bool) {
1651 ctx := n.ctx
1652 k := 0
1653
1654 a := n.dynamicFields
1655 for _, d := range n.dynamicFields {
1656 var f adt.Feature
1657 v, complete := ctx.Evaluate(d.env, d.field.Key)
1658 if !complete {
1659 a[k] = d
1660 k++
1661 continue
1662 }
1663 if b, _ := v.(*adt.Bottom); b != nil {
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001664 n.addValueConjunct(nil, b, d.id)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001665 continue
1666 }
1667 f = ctx.Label(v)
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001668 n.insertField(f, adt.MakeConjunct(d.env, d.field, d.id))
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001669 }
1670
1671 progress = k < len(n.dynamicFields)
1672
1673 n.dynamicFields = a[:k]
1674
1675 return progress
1676}
1677
1678// injectEmbedded evaluates and inserts embeddings. It first evaluates all
1679// embeddings before inserting the results to ensure that the order of
1680// evaluation does not matter.
Marcel van Lohuizen304b02e2020-07-27 22:22:42 +02001681func (n *nodeContext) injectEmbedded(all *[]envYield) (progress bool) {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001682 ctx := n.ctx
1683 type envStruct struct {
1684 env *adt.Environment
1685 s *adt.StructLit
1686 }
1687 var sa []envStruct
1688 f := func(env *adt.Environment, st *adt.StructLit) {
1689 sa = append(sa, envStruct{env, st})
1690 }
1691
1692 k := 0
Marcel van Lohuizen304b02e2020-07-27 22:22:42 +02001693 for i := 0; i < len(*all); i++ {
1694 d := (*all)[i]
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001695 sa = sa[:0]
1696
1697 if err := ctx.Yield(d.env, d.yield, f); err != nil {
1698 if err.IsIncomplete() {
Marcel van Lohuizen304b02e2020-07-27 22:22:42 +02001699 (*all)[k] = d
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001700 k++
1701 } else {
1702 // continue to collect other errors.
1703 n.addBottom(err)
1704 }
1705 continue
1706 }
1707
1708 for _, st := range sa {
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001709 n.addStruct(st.env, st.s, d.id)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001710 }
1711 }
1712
Marcel van Lohuizen304b02e2020-07-27 22:22:42 +02001713 *all = (*all)[:k]
1714 return k < len(*all)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001715}
1716
1717// addLists
1718//
1719// TODO: association arrays:
1720// If an association array marker was present in a struct, create a struct node
1721// instead of a list node. In either case, a node may only have list fields
1722// or struct fields and not both.
1723//
1724// addLists should be run after the fixpoint expansion:
1725// - it enforces that comprehensions may not refer to the list itself
1726// - there may be no other fields within the list.
1727//
1728// TODO(embeddedScalars): for embedded scalars, there should be another pass
1729// of evaluation expressions after expanding lists.
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001730func (n *nodeContext) addLists(c *adt.OpContext) (oneOfTheLists adt.Expr, anID adt.ID) {
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001731 if len(n.lists) == 0 && len(n.vLists) == 0 {
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001732 return nil, 0
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001733 }
1734
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001735 isOpen := true
1736 max := 0
1737 var maxNode adt.Expr
1738
Marcel van Lohuizend55e2b52020-08-25 18:04:24 +02001739 if m, ok := n.node.Value.(*adt.ListMarker); ok {
1740 isOpen = m.IsOpen
1741 max = len(n.node.Arcs)
1742 }
1743
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001744 for _, l := range n.vLists {
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001745 oneOfTheLists = l
1746
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001747 elems := l.Elems()
1748 isClosed := l.IsClosed(c)
1749
1750 switch {
1751 case len(elems) < max:
1752 if isClosed {
1753 n.invalidListLength(len(elems), max, l, maxNode)
1754 continue
1755 }
1756
1757 case len(elems) > max:
1758 if !isOpen {
1759 n.invalidListLength(max, len(elems), maxNode, l)
1760 continue
1761 }
1762 isOpen = !isClosed
1763 max = len(elems)
1764 maxNode = l
1765
1766 case isClosed:
1767 isOpen = false
1768 maxNode = l
1769 }
1770
1771 for _, a := range elems {
1772 if a.Conjuncts == nil {
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001773 n.insertField(a.Label, adt.MakeConjunct(nil, a.Value, 0))
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001774 continue
1775 }
1776 for _, c := range a.Conjuncts {
1777 n.insertField(a.Label, c)
1778 }
1779 }
1780 }
1781
1782outer:
1783 for i, l := range n.lists {
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001784 oneOfTheLists = l.list
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001785 anID = l.id
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001786
Marcel van Lohuizen711bbb12020-07-06 17:16:30 +02001787 n.updateCyclicStatus(l.env)
1788
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001789 index := int64(0)
1790 hasComprehension := false
1791 for j, elem := range l.list.Elems {
1792 switch x := elem.(type) {
1793 case adt.Yielder:
1794 err := c.Yield(l.env, x, func(e *adt.Environment, st *adt.StructLit) {
1795 label, err := adt.MakeLabel(x.Source(), index, adt.IntLabel)
1796 n.addErr(err)
1797 index++
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001798 n.insertField(label, adt.MakeConjunct(e, st, l.id))
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001799 })
1800 hasComprehension = true
Marcel van Lohuizen07e40c62020-07-22 21:14:11 +02001801 if err != nil && !err.IsIncomplete() {
1802 n.addBottom(err)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001803 }
1804
1805 case *adt.Ellipsis:
1806 if j != len(l.list.Elems)-1 {
Marcel van Lohuizen651d3792020-07-20 10:36:31 +02001807 n.addErr(c.Newf("ellipsis must be last element in list"))
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001808 }
1809
1810 n.lists[i].elipsis = x
1811
1812 default:
1813 label, err := adt.MakeLabel(x.Source(), index, adt.IntLabel)
1814 n.addErr(err)
1815 index++ // TODO: don't use insertField.
Marcel van Lohuizen3d863fc2020-09-03 19:58:22 +02001816 n.insertField(label, adt.MakeConjunct(l.env, x, l.id))
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001817 }
1818
1819 // Terminate early n case of runaway comprehension.
1820 if !isOpen && int(index) > max {
1821 n.invalidListLength(max, int(index), maxNode, l.list)
1822 continue outer
1823 }
1824 }
1825
1826 switch closed := n.lists[i].elipsis == nil; {
1827 case int(index) < max:
1828 if closed {
1829 n.invalidListLength(int(index), max, l.list, maxNode)
1830 continue
1831 }
1832
1833 case int(index) > max,
1834 closed && isOpen,
1835 (!closed == isOpen) && !hasComprehension:
1836 max = int(index)
1837 maxNode = l.list
1838 isOpen = !closed
1839 }
1840
1841 n.lists[i].n = index
1842 }
1843
1844 // add additionalItem values to list and construct optionals.
1845 elems := n.node.Elems()
1846 for _, l := range n.vLists {
1847 a, _ := l.Closed.(*acceptor)
1848 if a == nil {
1849 continue
1850 }
1851
1852 newElems := l.Elems()
1853 if len(newElems) >= len(elems) {
1854 continue // error generated earlier, if applicable.
1855 }
1856
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001857 // TODO: why not necessary?
1858 // n.optionals = append(n.optionals, a.fields...)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001859
1860 for _, arc := range elems[len(newElems):] {
1861 l.MatchAndInsert(c, arc)
1862 }
1863 }
1864
1865 for _, l := range n.lists {
1866 if l.elipsis == nil {
1867 continue
1868 }
1869
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001870 f := &fieldSet{pos: l.list, env: l.env, id: l.id}
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001871 f.AddEllipsis(c, l.elipsis)
1872
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001873 closedInfo(n.node).insertFieldSet(l.id, f)
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001874
1875 for _, arc := range elems[l.n:] {
1876 f.MatchAndInsert(c, arc)
1877 }
1878 }
1879
1880 sources := []ast.Expr{}
1881 // Add conjuncts for additional items.
1882 for _, l := range n.lists {
1883 if l.elipsis == nil {
1884 continue
1885 }
1886 if src, _ := l.elipsis.Source().(ast.Expr); src != nil {
1887 sources = append(sources, src)
1888 }
1889 }
1890
Marcel van Lohuizen62528c32020-09-10 09:29:45 +02001891 ci := closedInfo(n.node)
1892 ci.isList = true
1893 ci.openList = isOpen
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001894
Marcel van Lohuizend55e2b52020-08-25 18:04:24 +02001895 if m, ok := n.node.Value.(*adt.ListMarker); !ok {
1896 n.node.SetValue(c, adt.Partial, &adt.ListMarker{
1897 Src: ast.NewBinExpr(token.AND, sources...),
1898 IsOpen: isOpen,
1899 })
1900 } else {
1901 if expr, _ := m.Src.(ast.Expr); expr != nil {
1902 sources = append(sources, expr)
1903 }
1904 m.Src = ast.NewBinExpr(token.AND, sources...)
1905 m.IsOpen = m.IsOpen && isOpen
1906 }
1907
1908 n.lists = n.lists[:0]
1909 n.vLists = n.vLists[:0]
Marcel van Lohuizend857f232020-07-23 16:00:19 +02001910
Marcel van Lohuizen0eb7cc52020-10-02 10:00:34 +02001911 return oneOfTheLists, anID
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001912}
1913
1914func (n *nodeContext) invalidListLength(na, nb int, a, b adt.Expr) {
Marcel van Lohuizen651d3792020-07-20 10:36:31 +02001915 n.addErr(n.ctx.Newf("incompatible list lengths (%d and %d)", na, nb))
Marcel van Lohuizen0f935f82020-06-09 09:13:01 +02001916}