this repo has no description
1// 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
15package adt
16
17import (
18 "fmt"
19 "iter"
20 "slices"
21
22 "cuelang.org/go/cue/ast"
23 "cuelang.org/go/cue/errors"
24 "cuelang.org/go/cue/token"
25 "cuelang.org/go/internal/iterutil"
26)
27
28// TODO: unanswered questions about structural cycles:
29//
30// 1. When detecting a structural cycle, should we consider this as:
31// a) an unevaluated value,
32// b) an incomplete error (which does not affect parent validity), or
33// c) a special value.
34//
35// Making it an error is the simplest way to ensure reentrancy is disallowed:
36// without an error it would require an additional mechanism to stop reentrancy
37// from continuing to process. Even worse, in some cases it may only partially
38// evaluate, resulting in unexpected results. For this reason, we are taking
39// approach `b` for now.
40//
41// This has some consequences of how disjunctions are treated though. Consider
42//
43// list: {
44// head: _
45// tail: list | null
46// }
47//
48// When making it an error, evaluating the above will result in
49//
50// list: {
51// head: _
52// tail: null
53// }
54//
55// because list will result in a structural cycle, and thus an error, it will be
56// stripped from the disjunction. This may or may not be a desirable property. A
57// nice thing is that it is not required to write `list | *null`. A disadvantage
58// is that this is perhaps somewhat inexplicit.
59//
60// When not making it an error (and simply cease evaluating child arcs upon
61// cycle detection), the result would be:
62//
63// list: {
64// head: _
65// tail: list | null
66// }
67//
68// In other words, an evaluation would result in a cycle and thus an error.
69// Implementations can recognize such cases by having unevaluated arcs. An
70// explicit structure cycle marker would probably be less error prone.
71//
72// Note that in both cases, a reference to list will still use the original
73// conjuncts, so the result will be the same for either method in this case.
74//
75//
76// 2. Structural cycle allowance.
77//
78// Structural cycle detection disallows reentrancy as well. This means one
79// cannot use structs for recursive computation. This will probably preclude
80// evaluation of some configuration. Given that there is no real alternative
81// yet, we could allow structural cycle detection to be optionally disabled.
82
83// An Environment links the parent scopes for identifier lookup to a composite
84// node. Each conjunct that make up node in the tree can be associated with
85// a different environment (although some conjuncts may share an Environment).
86type Environment struct {
87 Up *Environment
88
89 // Vertex should not be accessed directly in most cases.
90 // Use DerefVertex(ctx) instead to handle overlay mappings correctly.
91 //
92 // TODO(mvdan): unexport this field, or give it a longer name
93 // to clarify it should not be read directly in most cases?
94 Vertex *Vertex
95
96 // DynamicLabel is only set when instantiating a field from a pattern
97 // constraint. It is used to resolve label references.
98 DynamicLabel Feature
99
100 // TODO(perf): make the following public fields a shareable struct as it
101 // mostly is going to be the same for child nodes.
102
103 // TODO: This can probably move into the nodeContext, making it a map from
104 // conjunct to Value.
105 cache map[cacheKey]Value
106}
107
108// Equal reports whether e and f refer to the same node.
109func (e *Environment) Equal(ctx *OpContext, f *Environment) bool {
110 return e.Up == f.Up && e.DerefVertex(ctx) == f.DerefVertex(ctx)
111}
112
113type cacheKey struct {
114 Expr Expr
115 Arc *Vertex
116}
117
118// DerefVertex returns the dereferenced vertex for this environment.
119// It must be used instead of directly accessing the Vertex field
120// to handle overlay mappings correctly during disjunction evaluation.
121func (e *Environment) DerefVertex(ctx *OpContext) *Vertex {
122 if ctx == nil {
123 return e.Vertex
124 }
125 return ctx.deref(e.Vertex)
126}
127
128func (e *Environment) up(ctx *OpContext, count int32) *Environment {
129 for i := int32(0); i < count; i++ {
130 e = e.Up
131 ctx.Assertf(ctx.Pos(), e.DerefVertex(ctx) != nil, "Environment.up encountered a nil vertex")
132 }
133 return e
134}
135
136// A Vertex is a node in the value tree. It may be a leaf or internal node.
137// It may have arcs to represent elements of a fully evaluated struct or list.
138//
139// For structs, it only contains definitions and concrete fields.
140// optional fields are dropped.
141//
142// It maintains source information such as a list of conjuncts that contributed
143// to the value.
144type Vertex struct {
145 // Parent links to a parent Vertex. This parent should only be used to
146 // access the parent's Label field to find the relative location within a
147 // tree.
148 Parent *Vertex
149
150 // State:
151 // eval: nil, BaseValue: nil -- unevaluated
152 // eval: *, BaseValue: nil -- evaluating
153 // eval: *, BaseValue: * -- finalized
154 //
155 state *nodeContext
156 // TODO: move to nodeContext.
157 overlay *Vertex
158
159 // Label is the feature leading to this vertex.
160 Label Feature
161
162 // TODO: move the following fields to nodeContext.
163
164 // status indicates the evaluation progress of this vertex.
165 status vertexStatus
166
167 // isData indicates that this Vertex is to be interpreted as data: pattern
168 // and additional constraints, as well as optional fields, should be
169 // ignored.
170 isData bool
171
172 // ClosedRecursive indicates whether this Vertex is recursively closed.
173 // This is the case, for instance, if it is a node in a definition or if one
174 // of the conjuncts, or ancestor conjuncts, is a definition.
175 ClosedRecursive bool
176
177 // ClosedNonRecursive indicates that this Vertex has been closed for this
178 // level only. This supports the close builtin.
179 ClosedNonRecursive bool
180
181 // Opened is set when a node that is opened with @experiment(explicitopen)
182 // is structure shared. This will override any of the above booleans.
183 OpenedShared bool
184
185 // HasEllipsis indicates that this Vertex is open by means of an ellipsis.
186 // TODO: combine this field with Closed once we removed the old evaluator.
187 HasEllipsis bool
188
189 // MultiLet indicates whether multiple let fields were added from
190 // different sources. If true, a LetReference must be resolved using
191 // the per-Environment value cache.
192 MultiLet bool
193
194 // IsDynamic signifies whether this struct is computed as part of an
195 // expression and not part of the static evaluation tree.
196 // Used for cycle detection.
197 IsDynamic bool
198
199 // IsPatternConstraint indicates that this Vertex is an entry in
200 // Vertex.PatternConstraints.
201 IsPatternConstraint bool
202
203 // nonRooted indicates that this Vertex originates within the context of
204 // a dynamic, or inlined, Vertex (e.g. `{out: ...}.out``). Note that,
205 // through reappropriation, this Vertex may become rooted down the line.
206 // Use the !IsDetached method to determine whether this Vertex became
207 // rooted.
208 nonRooted bool // indicates that there is no path from the root of the tree.
209
210 // anonymous indicates that this Vertex is being computed without an
211 // addressable context, or in other words, a context for which there is
212 // np path from the root of the file. Typically, the only addressable
213 // contexts are fields. Examples of fields that are not addressable are
214 // the for source of comprehensions and let fields or let clauses.
215 anonymous bool
216
217 // IsDisjunct indicates this Vertex is a disjunct resulting from a
218 // disjunction evaluation.
219 IsDisjunct bool
220
221 // IsShared is true if BaseValue holds a Vertex of a node of another path.
222 // If a node is shared, the user should be careful with traversal.
223 // The debug printer, for instance, takes extra care not to print in a loop.
224 IsShared bool
225
226 // ArcType indicates the level of optionality of this arc.
227 ArcType ArcType
228
229 // BaseValue is the value associated with this vertex. For lists and structs
230 // this is a sentinel value indicating its kind.
231 BaseValue BaseValue
232
233 // ChildErrors is the collection of all errors of children.
234 ChildErrors *Bottom
235
236 // The parent of nodes can be followed to determine the path within the
237 // configuration of this node.
238 // Value Value
239 Arcs []*Vertex // arcs are sorted in display order.
240
241 // PatternConstraints are additional constraints that match more nodes.
242 // Constraints that match existing Arcs already have their conjuncts
243 // mixed in.
244 // TODO: either put in StructMarker/ListMarker or integrate with Arcs
245 // so that this pointer is unnecessary.
246 PatternConstraints *Constraints
247
248 // Conjuncts lists the structs that ultimately formed this Composite value.
249 // This includes all selected disjuncts.
250 //
251 // This value may be nil, in which case the Arcs are considered to define
252 // the final value of this Vertex.
253 //
254 // TODO: all access to Conjuncts should go through functions like
255 // [Vertex.LeafConjuncts] and [Vertex.AllConjuncts].
256 // We should probably make this an unexported field.
257 Conjuncts ConjunctGroup
258
259 // Structs is a slice of struct literals that contributed to this value.
260 // This information is used to compute the topological sort of arcs.
261 Structs []StructInfo
262}
263
264func deref(v *Vertex) *Vertex {
265 v = v.DerefValue()
266 n := v.state
267 if n != nil {
268 v = n.underlying
269 }
270 if v == nil {
271 panic("unexpected nil underlying with non-nil state")
272 }
273 return v
274}
275
276func equalDeref(a, b *Vertex) bool {
277 return deref(a) == deref(b)
278}
279
280// newInlineVertex creates a Vertex that is needed for computation, but for
281// which there is no CUE path defined from the root Vertex.
282func (ctx *OpContext) newInlineVertex(parent *Vertex, v BaseValue, a ...Conjunct) *Vertex {
283 // TODO: parent is an unused parameter here. Setting [Vertex.Parent] to it
284 // improves paths in a bunch of errors, fixing regressions compared to evalv2.
285 // However, it also breaks a few tests. Perhaps try with evalv4.
286 n := &Vertex{
287 BaseValue: v,
288 IsDynamic: true,
289 ArcType: ArcMember,
290 Conjuncts: a,
291 }
292 if len(ctx.freeScope) > 0 {
293 state := ctx.freeScope[len(ctx.freeScope)-1]
294 state.toFree = append(state.toFree, n)
295 }
296 if ctx.inDetached > 0 {
297 n.anonymous = true
298 }
299 return n
300
301}
302
303// updateArcType updates v.ArcType if t is more restrictive.
304func (v *Vertex) updateArcType(t ArcType) {
305 if t >= v.ArcType {
306 return
307 }
308 if v.ArcType == ArcNotPresent {
309 return
310 }
311 s := v.state
312 if s != nil && v.isFinal() {
313 c := s.ctx
314 if s.scheduler.frozen.meets(arcTypeKnown) {
315 p := token.NoPos
316 if src := c.Source(); src != nil {
317 p = src.Pos()
318 }
319 parent := v.Parent
320 parent.reportFieldCycleError(c, p, v.Label)
321 return
322 }
323 }
324 if v.Parent != nil && v.Parent.ArcType == ArcPending && v.Parent.state != nil {
325 // TODO: check that state is always non-nil.
326 v.Parent.state.unshare()
327 }
328 v.ArcType = t
329}
330
331// isDefined indicates whether this arc is a "value" field, and not a constraint
332// or void arc.
333func (v *Vertex) isDefined() bool {
334 return v.ArcType == ArcMember
335}
336
337// IsConstraint reports whether the Vertex is an optional or required field.
338func (v *Vertex) IsConstraint() bool {
339 return v.ArcType == ArcOptional || v.ArcType == ArcRequired
340}
341
342// IsDefined indicates whether this arc is defined meaning it is not a
343// required or optional constraint and not a "void" arc.
344// It will evaluate the arc, and thus evaluate any comprehension, to make this
345// determination.
346func (v *Vertex) IsDefined(c *OpContext) bool {
347 if v.isDefined() {
348 return true
349 }
350 if v.Parent != nil && v.Parent.status == finalized {
351 return false
352 }
353 v.Finalize(c)
354 return v.isDefined()
355}
356
357// Rooted reports if it is known there is a path from the root of the tree to
358// this Vertex. If this returns false, it may still be rooted if the node
359// originated from an inline struct, but was later reappropriated.
360func (v *Vertex) Rooted() bool {
361 return !v.nonRooted && !v.Label.IsLet() && !v.IsDynamic
362}
363
364// Internal is like !Rooted, but also counts internal let nodes as internal.
365func (v *Vertex) Internal() bool {
366 return v.nonRooted || v.anonymous || v.IsDynamic
367}
368
369// IsDetached reports whether this Vertex does not have a path from the root.
370func (v *Vertex) IsDetached() bool {
371 // v might have resulted from an inline struct that was subsequently shared.
372 // In this case, it is still rooted.
373 for v != nil {
374 if v.Rooted() {
375 return false
376 }
377 // Already take into account the provisionally assigned parent.
378 if v.state != nil && v.state.parent != nil {
379 v = v.state.parent
380 } else {
381 v = v.Parent
382 }
383 }
384
385 return true
386}
387
388// MayAttach reports whether this Vertex may attach to another arc.
389// The behavior is undefined if IsDetached is true.
390func (v *Vertex) MayAttach() bool {
391 return !v.Label.IsLet() && !v.anonymous
392}
393
394//go:generate go tool stringer -type=ArcType -trimprefix=Arc
395
396type ArcType uint8
397
398const (
399 // ArcMember means that this arc is a normal non-optional field
400 // (including regular, hidden, and definition fields).
401 ArcMember ArcType = iota
402
403 // ArcRequired is like optional, but requires that a field be specified.
404 // Fields are of the form foo!.
405 ArcRequired
406
407 // ArcOptional represents fields of the form foo? and defines constraints
408 // for foo in case it is defined.
409 ArcOptional
410
411 // ArcPending means that it is not known yet whether an arc exists and that
412 // its conjuncts need to be processed to find out. This happens when an arc
413 // is provisionally added as part of a comprehension, but when this
414 // comprehension has not yet yielded any results.
415 //
416 // TODO: make this a separate state so that we can track which arcs still
417 // have unresolved comprehensions.
418 ArcPending
419
420 // ArcNotPresent indicates that this arc is not present and, unlike
421 // ArcPending, needs no further processing.
422 ArcNotPresent
423
424 // TODO: define a type for optional arcs. This will be needed for pulling
425 // in optional fields into the Vertex, which, in turn, is needed for
426 // structure sharing, among other things.
427 // We could also define types for required fields and potentially lets.
428)
429
430// ConstraintFromToken converts a given AST constraint token to the
431// corresponding ArcType.
432func ConstraintFromToken(t token.Token) ArcType {
433 switch t {
434 case token.OPTION:
435 return ArcOptional
436 case token.NOT:
437 return ArcRequired
438 }
439 return ArcMember
440}
441
442// Token reports the token corresponding to the constraint represented by a,
443// or token.ILLEGAL otherwise.
444func (a ArcType) Token() (t token.Token) {
445 switch a {
446 case ArcOptional:
447 t = token.OPTION
448 case ArcRequired:
449 t = token.NOT
450 }
451 return t
452}
453
454// Suffix reports the field suffix for the given ArcType if it is a
455// constraint or the empty string otherwise.
456func (a ArcType) Suffix() string {
457 switch a {
458 case ArcOptional:
459 return "?"
460 case ArcRequired:
461 return "!"
462
463 // For debugging internal state. This is not CUE syntax.
464 case ArcPending:
465 return "*"
466 case ArcNotPresent:
467 return "-"
468 }
469 return ""
470}
471
472func (v *Vertex) Clone() *Vertex {
473 c := *v
474 c.state = nil
475 return &c
476}
477
478type StructInfo struct {
479 *StructLit
480
481 // Repeats tracks how many additional times this struct appeared via [Vertex.AddStruct].
482 // This is used by toposort to give proper weight to repeated structs.
483 Repeats int
484
485 // Embed indicates the struct in which this struct is embedded (originally),
486 // or nil if this is a root structure.
487 // Embed *StructInfo
488 // Context *RefInfo // the location from which this struct originates.
489}
490
491// vertexStatus indicates the evaluation progress of a Vertex.
492type vertexStatus int8
493
494//go:generate go tool stringer -type=vertexStatus
495
496const (
497 // unprocessed indicates a Vertex has not been processed before.
498 // Value must be nil.
499 unprocessed vertexStatus = iota
500
501 // evaluating means that the current Vertex is being evaluated. If this is
502 // encountered it indicates a reference cycle. Value must be nil.
503 evaluating
504
505 // partial indicates that the result was only partially evaluated. It will
506 // need to be fully evaluated to get a complete results.
507 //
508 // TODO: this currently requires a renewed computation. Cache the
509 // nodeContext to allow reusing the computations done so far.
510 partial
511
512 // conjuncts is the state reached when all conjuncts have been evaluated,
513 // but without recursively processing arcs.
514 conjuncts
515
516 // finalized means that this node is fully evaluated and that the results
517 // are save to use without further consideration.
518 finalized
519)
520
521// Wrap creates a Vertex that takes w as a shared value. This allows users
522// to set different flags for a wrapped Vertex.
523func (c *OpContext) Wrap(v *Vertex, id CloseInfo) *Vertex {
524 w := c.newInlineVertex(nil, nil, v.Conjuncts...)
525 n := w.getState(c)
526 n.share(makeAnonymousConjunct(nil, v, nil), v, id)
527 return w
528}
529
530// Status returns the status of the current node. When reading the status, one
531// should always use this method over directly reading status field.
532//
533// NOTE: this only matters for EvalV3 and beyonds, so a lot of the old code
534// might still access it directly.
535func (v *Vertex) Status() vertexStatus {
536 v = v.DerefValue()
537 return v.status
538}
539
540// ForceDone prevents v from being evaluated.
541func (v *Vertex) ForceDone() {
542 v.updateStatus(finalized)
543}
544
545// IsUnprocessed reports whether v is unprocessed.
546func (v *Vertex) IsUnprocessed() bool {
547 return v.Status() == unprocessed
548}
549
550func (v *Vertex) updateStatus(s vertexStatus) {
551 if !isCyclePlaceholder(v.BaseValue) {
552 if !v.IsErr() && v.state != nil {
553 Assertf(v.state.ctx, v.Status() <= s+1, "attempt to regress status from %d to %d", v.Status(), s)
554 }
555 }
556
557 if s == finalized && v.BaseValue == nil {
558 // TODO: for debugging.
559 // panic("not finalized")
560 }
561 v.status = s
562}
563
564// setParentDone signals v that the conjuncts of all ancestors have been
565// processed.
566// If all conjuncts of this node have been set, all arcs will be notified
567// of this parent being done.
568//
569// Note: once a vertex has started evaluation (state != nil), insertField will
570// cause all conjuncts to be immediately processed. This means that if all
571// ancestors of this node processed their conjuncts, and if this node has
572// processed all its conjuncts as well, all nodes that it embedded will have
573// received all their conjuncts as well, after which this node will have been
574// notified of these conjuncts.
575func (v *Vertex) setParentDone() {
576 // Could set "Conjuncts" flag of arc at this point.
577 if n := v.state; n != nil {
578 for _, a := range v.Arcs {
579 a.setParentDone()
580 }
581 }
582}
583
584// LeafConjuncts iterates over all conjuncts that are leaves of the [ConjunctGroup] tree.
585func (v *Vertex) LeafConjuncts() iter.Seq[Conjunct] {
586 return func(yield func(Conjunct) bool) {
587 _ = iterConjuncts(v.Conjuncts, yield)
588 }
589}
590
591func iterConjuncts(a []Conjunct, yield func(Conjunct) bool) bool {
592 // TODO: note that this is iterAllConjuncts but without yielding ConjunctGroups.
593 // Can we reuse the code in a simple enough way?
594 for _, c := range a {
595 switch x := c.x.(type) {
596 case *ConjunctGroup:
597 if !iterConjuncts(*x, yield) {
598 return false
599 }
600 default:
601 if !yield(c) {
602 return false
603 }
604 }
605 }
606 return true
607}
608
609// ConjunctsSeq iterates over all conjuncts that are leafs in the list of trees given.
610func ConjunctsSeq(a []Conjunct) iter.Seq[Conjunct] {
611 return func(yield func(Conjunct) bool) {
612 _ = iterConjuncts(a, yield)
613 }
614}
615
616// AllConjuncts iterates through all conjuncts of v, including [ConjunctGroup]s.
617// Note that ConjunctGroups do not have an Environment associated with them.
618// The boolean reports whether the conjunct is a leaf.
619func (v *Vertex) AllConjuncts() iter.Seq2[Conjunct, bool] {
620 return func(yield func(Conjunct, bool) bool) {
621 _ = iterAllConjuncts(v.Conjuncts, yield)
622 }
623}
624
625func iterAllConjuncts(a []Conjunct, yield func(c Conjunct, isLeaf bool) bool) bool {
626 for _, c := range a {
627 switch x := c.x.(type) {
628 case *ConjunctGroup:
629 if !yield(c, false) {
630 return false
631 }
632 if !iterAllConjuncts(*x, yield) {
633 return false
634 }
635 default:
636 if !yield(c, true) {
637 return false
638 }
639 }
640 }
641 return true
642}
643
644// HasConjuncts reports whether v has any conjuncts.
645func (v *Vertex) HasConjuncts() bool {
646 return len(v.Conjuncts) > 0
647}
648
649// SingleConjunct reports whether there is a single leaf conjunct and returns 1
650// if so. It will return 0 if there are no conjuncts or 2 if there are more than
651// 1.
652//
653// This is an often-used operation.
654func (v *Vertex) SingleConjunct() (c Conjunct, count int) {
655 if v == nil {
656 return c, 0
657 }
658 for c = range v.LeafConjuncts() {
659 if count++; count > 1 {
660 break
661 }
662 }
663 return c, count
664}
665
666// ConjunctAt assumes a Vertex represents a top-level Vertex, such as one
667// representing a file or a let expressions, where all conjuncts appear at the
668// top level. It may panic if this condition is not met.
669func (v *Vertex) ConjunctAt(i int) Conjunct {
670 return v.Conjuncts[i]
671}
672
673// Value returns the Value of v without definitions if it is a scalar
674// or itself otherwise.
675func (v *Vertex) Value() Value {
676 switch x := v.BaseValue.(type) {
677 case nil:
678 return nil
679 case *StructMarker, *ListMarker:
680 return v
681 case Value:
682 // TODO: recursively descend into Vertex?
683 return x
684 default:
685 panic(fmt.Sprintf("unexpected type %T", v.BaseValue))
686 }
687}
688
689// isUndefined reports whether a vertex does not have a useable BaseValue yet.
690func (v *Vertex) isUndefined() bool {
691 if !v.isDefined() {
692 return true
693 }
694 switch v.BaseValue {
695 case nil, cycle:
696 return true
697 }
698 return false
699}
700
701// isFinal reports whether this node may no longer be modified.
702func (v *Vertex) isFinal() bool {
703 // TODO(deref): the accounting of what is final should be recorded
704 // in the original node. Remove this dereference once the old
705 // evaluator has been removed.
706 return v.Status() == finalized
707}
708
709func (x *Vertex) IsConcrete() bool {
710 return x.Concreteness() <= Concrete
711}
712
713// IsData reports whether v should be interpreted in data mode. In other words,
714// it tells whether optional field matching and non-regular fields, like
715// definitions and hidden fields, should be ignored.
716func (v *Vertex) IsData() bool {
717 return v.isData || !v.HasConjuncts()
718}
719
720// ToDataSingle creates a new Vertex that represents just the regular fields
721// of this vertex. Arcs are left untouched.
722// It is used by cue.Eval to convert nodes to data on per-node basis.
723func (v *Vertex) ToDataSingle() *Vertex {
724 v = v.DerefValue()
725 w := *v
726 w.isData = true
727 w.state = nil
728 w.status = finalized
729 return &w
730}
731
732// ToDataAll returns a new v where v and all its descendents contain only
733// the regular fields.
734func (v *Vertex) ToDataAll(ctx *OpContext) *Vertex {
735 // Create a map to track processed vertices to avoid duplicate processing
736 processed := make(map[*Vertex]*Vertex)
737
738 // TODO(evalv3): for EvalV3 we could call finalize only here.
739
740 return v.toDataAllRec(ctx, processed)
741}
742
743func (v *Vertex) toDataAllRec(ctx *OpContext, processed map[*Vertex]*Vertex) *Vertex {
744 // Check if this vertex has already been processed
745 if result, exists := processed[v]; exists {
746 return result
747 }
748
749 v.Finalize(ctx) // Needed recursively for eval v2.
750
751 arcs := make([]*Vertex, 0, len(v.Arcs))
752 for _, a := range v.Arcs {
753 if !a.IsDefined(ctx) {
754 continue
755 }
756 if a.Label.IsRegular() {
757 arcs = append(arcs, a.toDataAllRec(ctx, processed))
758 }
759 }
760 w := *v
761 w.state = nil
762 w.status = finalized
763
764 w.BaseValue = toDataAllBaseValue(ctx, w.BaseValue, processed)
765 w.Arcs = arcs
766 w.isData = true
767
768 // Converting to dat drops constraints and non-regular fields. This means
769 // that the domain on which they are defined is reduced, which will change
770 // closedness properties. We therefore remove closedness. Note that data,
771 // in general and JSON specifically, is not closed.
772 w.ClosedRecursive = false
773 w.ClosedNonRecursive = false
774
775 w.Conjuncts = slices.Clone(v.Conjuncts)
776
777 for i, c := range w.Conjuncts {
778 if v, _ := c.x.(Value); v != nil {
779 w.Conjuncts[i].x = toDataAllBaseValue(ctx, v, processed).(Value)
780 }
781 // Always reset all CloseInfo fields to zero. Normally only the top
782 // conjuncts matter and get inserted and conjuncts of recursive arcs
783 // never come in play. ToDataAll is an exception.
784 w.Conjuncts[i].CloseInfo = w.Conjuncts[i].CloseInfo.clearCloseCheck()
785 }
786
787 // Store the processed vertex before returning
788 processed[v] = &w
789 return &w
790}
791
792func toDataAllBaseValue(ctx *OpContext, v BaseValue, processed map[*Vertex]*Vertex) BaseValue {
793 switch x := v.(type) {
794 default:
795 return x
796
797 case *Vertex:
798 return x.toDataAllRec(ctx, processed)
799
800 case *Disjunction:
801 d := *x
802 values := x.Values
803 // Data mode involves taking default values and if there is an
804 // unambiguous default value, we should convert that to data as well.
805 switch x.NumDefaults {
806 case 0:
807 case 1:
808 return toDataAllBaseValue(ctx, values[0], processed)
809 default:
810 values = values[:x.NumDefaults]
811 }
812 d.Values = make([]Value, len(values))
813 for i, v := range values {
814 switch x := v.(type) {
815 case *Vertex:
816 d.Values[i] = x.toDataAllRec(ctx, processed)
817 default:
818 d.Values[i] = x
819 }
820 }
821 return &d
822
823 case *Conjunction:
824 c := *x
825 c.Values = make([]Value, len(x.Values))
826 for i, v := range x.Values {
827 // This case is okay because the source is of type Value.
828 c.Values[i] = toDataAllBaseValue(ctx, v, processed).(Value)
829 }
830 return &c
831 }
832}
833
834// IsFinal reports whether value v can still become more specific, when only
835// considering regular fields.
836//
837// TODO: move this functionality as a method on cue.Value.
838func IsFinal(v Value) bool {
839 return isFinal(v, false)
840}
841
842func isFinal(v Value, isClosed bool) bool {
843 switch x := v.(type) {
844 case *Vertex:
845 closed := isClosed || x.ClosedNonRecursive || x.ClosedRecursive
846
847 // This also dereferences the value.
848 if v, ok := x.BaseValue.(Value); ok {
849 return isFinal(v, closed)
850 }
851
852 // If it is not closed, it can still become more specific.
853 if !closed {
854 return false
855 }
856
857 for _, a := range x.Arcs {
858 if !a.Label.IsRegular() {
859 continue
860 }
861 if a.ArcType > ArcMember && !a.IsErr() {
862 return false
863 }
864 if !isFinal(a, false) {
865 return false
866 }
867 }
868 return true
869
870 case *Bottom:
871 // Incomplete errors could be resolved by making a struct more specific.
872 return x.Code <= StructuralCycleError
873
874 default:
875 return v.Concreteness() <= Concrete
876 }
877}
878
879// func (v *Vertex) IsEvaluating() bool {
880// return v.Value == cycle
881// }
882
883// IsErr is a convenience function to check whether a Vertex represents an
884// error currently. It does not finalize the value, so it is possible that
885// v may become erroneous after this call.
886func (v *Vertex) IsErr() bool {
887 // if v.Status() > Evaluating {
888 return v.Bottom() != nil
889}
890
891// Err finalizes v, if it isn't yet, and returns an error if v evaluates to an
892// error or nil otherwise.
893func (v *Vertex) Err(c *OpContext) *Bottom {
894 v.Finalize(c)
895 return v.Bottom()
896}
897
898// Bottom reports whether v is currently erroneous It does not finalize the
899// value, so it is possible that v may become erroneous after this call.
900func (v *Vertex) Bottom() *Bottom {
901 // TODO: should we consider errors recorded in the state?
902 v = v.DerefValue()
903 if b, ok := v.BaseValue.(*Bottom); ok {
904 return b
905 }
906 return nil
907}
908
909// func (v *Vertex) Evaluate()
910
911// Unify unifies two values and returns the result.
912//
913// TODO: introduce: Open() wrapper that indicates closedness should be ignored.
914//
915// Change Value to Node to allow any kind of type to be passed.
916func Unify(c *OpContext, a, b Value) *Vertex {
917 v := &Vertex{}
918
919 // We set the parent of the context to be able to detect structural cycles
920 // early enough to error on schemas used for validation.
921 if n := c.vertex; n != nil {
922 v.Parent = n.Parent
923 v.Label = n.Label
924 }
925
926 addConjuncts(c, v, a)
927 addConjuncts(c, v, b)
928
929 s := v.getState(c)
930 // As this is a new node, we should drop all the requirements from
931 // parent nodes, as these will not be aligned with the reinsertion
932 // of the conjuncts.
933 s.dropParentRequirements = true
934 if p := c.vertex; p != nil && p.state != nil && s != nil {
935 s.hasNonCyclic = p.state.hasNonCyclic
936 }
937
938 v.Finalize(c)
939
940 if c.vertex != nil {
941 v.Label = c.vertex.Label
942 }
943
944 return v
945}
946
947func addConjuncts(ctx *OpContext, dst *Vertex, src Value) {
948 closeInfo := ctx.CloseInfo()
949 closeInfo.FromDef = false
950 c := MakeConjunct(nil, src, closeInfo)
951
952 if v, ok := src.(*Vertex); ok {
953 // TODO(v1.0.0): we should determine whether to apply the new semantics
954 // for closedness. However, this is not applicable for a Vertex.
955 // Ultimately, this logic should be removed.
956
957 // By default, all conjuncts in a node are considered to be not
958 // mutually closed. This means that if one of the arguments to Unify
959 // closes, but is acquired to embedding, the closeness information
960 // is disregarded. For instance, for Unify(a, b) where a and b are
961 //
962 // a: {#D, #D: d: f: int}
963 // b: {d: e: 1}
964 //
965 // we expect 'e' to be not allowed.
966 //
967 // In order to do so, we wrap the outer conjunct in a separate
968 // scope that will be closed in the presence of closed embeddings
969 // independently from the other conjuncts.
970 n := dst.getBareState(ctx)
971 c.CloseInfo = n.splitScope(nil, c.CloseInfo)
972
973 // Even if a node is marked as ClosedRecursive, it may be that this
974 // is the first node that references a definition.
975 // We approximate this to see if the path leading up to this
976 // value is a defintion. This is not fully accurate. We could
977 // investigate the closedness information contained in the parent.
978 for p := v; p != nil; p = p.Parent {
979 if p.Label.IsDef() {
980 c.CloseInfo.TopDef = true
981 break
982 }
983 }
984 }
985
986 dst.AddConjunct(c)
987}
988
989func (v *Vertex) Finalize(c *OpContext) {
990 // Saving and restoring the error context prevents v from panicking in
991 // case the caller did not handle existing errors in the context.
992 err := c.errs
993 c.errs = nil
994 c.unify(v, Flags{
995 status: finalized,
996 condition: allKnown,
997 mode: finalize,
998 checkTypos: true,
999 })
1000 c.errs = err
1001}
1002
1003func (v *Vertex) Unify(c *OpContext, flags Flags) {
1004 // Saving and restoring the error context prevents v from panicking in
1005 // case the caller did not handle existing errors in the context.
1006 err := c.errs
1007 c.errs = nil
1008 c.unify(v, flags)
1009 c.errs = err
1010}
1011
1012// CompleteArcs ensures the set of arcs has been computed.
1013func (v *Vertex) CompleteArcs(c *OpContext) {
1014 c.unify(v, Flags{
1015 status: conjuncts,
1016 condition: allKnown,
1017 mode: finalize,
1018 checkTypos: true,
1019 })
1020}
1021
1022func (v *Vertex) CompleteArcsOnly(c *OpContext) {
1023 c.unify(v, Flags{
1024 status: conjuncts,
1025 condition: fieldSetKnown,
1026 mode: finalize,
1027 checkTypos: false,
1028 })
1029}
1030
1031func (v *Vertex) AddErr(ctx *OpContext, b *Bottom) {
1032 v.SetValue(ctx, CombineErrors(nil, v.Value(), b))
1033}
1034
1035// SetValue sets the value of a node.
1036func (v *Vertex) SetValue(ctx *OpContext, value BaseValue) *Bottom {
1037 return v.setValue(ctx, finalized, value)
1038}
1039
1040func (v *Vertex) setValue(ctx *OpContext, state vertexStatus, value BaseValue) *Bottom {
1041 v.BaseValue = value
1042 // TODO: should not set status here for new evaluator.
1043 v.updateStatus(state)
1044 return nil
1045}
1046
1047func (n *nodeContext) setBaseValue(value BaseValue) {
1048 n.node.BaseValue = value
1049}
1050
1051// swapBaseValue swaps the BaseValue of a node with the given value and returns
1052// the previous value.
1053func (n *nodeContext) swapBaseValue(value BaseValue) (saved BaseValue) {
1054 saved = n.node.BaseValue
1055 n.setBaseValue(value)
1056 return saved
1057}
1058
1059// ToVertex wraps v in a new Vertex, if necessary.
1060func ToVertex(v Value) *Vertex {
1061 switch x := v.(type) {
1062 case *Vertex:
1063 return x
1064 default:
1065 n := &Vertex{
1066 status: finalized,
1067 BaseValue: x,
1068 }
1069 n.AddConjunct(MakeRootConjunct(nil, v))
1070 return n
1071 }
1072}
1073
1074// Unwrap returns the possibly non-concrete scalar value of v, v itself for
1075// lists and structs, or nil if v is an undefined type.
1076func Unwrap(v Value) Value {
1077 x, ok := v.(*Vertex)
1078 if !ok {
1079 return v
1080 }
1081 // TODO(deref): BaseValue is currently overloaded to track cycles as well
1082 // as the actual or dereferenced value. Once the old evaluator can be
1083 // removed, we should use the new cycle tracking mechanism for cycle
1084 // detection and keep BaseValue clean.
1085 x = x.DerefValue()
1086 if n := x.state; n != nil && isCyclePlaceholder(x.BaseValue) {
1087 if n.errs != nil && !n.errs.IsIncomplete() {
1088 return n.errs
1089 }
1090 if n.scalar != nil {
1091 return n.scalar
1092 }
1093 }
1094 return x.Value()
1095}
1096
1097func (v *Vertex) Kind() Kind {
1098 // This is possible when evaluating comprehensions. It is potentially
1099 // not known at this time what the type is.
1100 switch {
1101 case v.state != nil && v.state.kind == BottomKind:
1102 return BottomKind
1103 case v.BaseValue != nil && !isCyclePlaceholder(v.BaseValue):
1104 return v.BaseValue.Kind()
1105 case v.state != nil:
1106 return v.state.kind
1107 default:
1108 return TopKind
1109 }
1110}
1111
1112// IsOptional reports whether a field is explicitly defined as optional,
1113// as opposed to whether it is allowed by a pattern constraint.
1114func (v *Vertex) IsOptional(label Feature) bool {
1115 for _, a := range v.Arcs {
1116 if a.Label == label {
1117 return a.IsConstraint()
1118 }
1119 }
1120 return false
1121}
1122
1123func (v *Vertex) accepts(ok, required bool) bool {
1124 return ok || (!required && !v.ClosedRecursive)
1125}
1126
1127// IsOpenStruct reports whether any field that is not contained within v is allowed.
1128//
1129// TODO: merge this function with IsClosedStruct and possibly IsClosedList.
1130// right now this causes too many issues if we do so.
1131func (v *Vertex) IsOpenStruct() bool {
1132 // TODO: move this check to IsClosedStruct. Right now this causes too many
1133 // changes in the debug output, and it also appears to be not entirely
1134 // correct.
1135 if v.HasEllipsis {
1136 return true
1137 }
1138 if v.ClosedNonRecursive {
1139 return false
1140 }
1141 if v.IsClosedStruct() {
1142 return false
1143 }
1144 return true
1145}
1146
1147func (v *Vertex) IsClosedStruct() bool {
1148 // TODO: add this check. Right now this causes issues. It will have
1149 // to be carefully introduced.
1150 // if v.HasEllipsis {
1151 // return false
1152 // }
1153 switch v.BaseValue.(type) {
1154 default:
1155 return false
1156
1157 case *Vertex:
1158 return v.ClosedRecursive && !v.HasEllipsis
1159
1160 case *StructMarker:
1161 case *Disjunction:
1162 }
1163 return isClosed(v)
1164}
1165
1166func (v *Vertex) IsClosedList() bool {
1167 if x, ok := v.BaseValue.(*ListMarker); ok {
1168 return !x.IsOpen
1169 }
1170 return false
1171}
1172
1173// TODO: return error instead of boolean? (or at least have version that does.)
1174func (v *Vertex) Accept(ctx *OpContext, f Feature) bool {
1175 // TODO(#543): remove this check.
1176 if f.IsDef() {
1177 return true
1178 }
1179
1180 if f.IsHidden() || f.IsLet() {
1181 return true
1182 }
1183
1184 // TODO(deref): right now a dereferenced value holds all the necessary
1185 // closedness information. In the future we may want to allow sharing nodes
1186 // with different closedness information. In that case, we should reconsider
1187 // the use of this dereference. Consider, for instance:
1188 //
1189 // #a: b // this node is currently not shared, but could be.
1190 // b: {c: 1}
1191 v = v.DerefValue()
1192 if x, ok := v.BaseValue.(*Disjunction); ok {
1193 for _, v := range x.Values {
1194 if x, ok := v.(*Vertex); ok && x.Accept(ctx, f) {
1195 return true
1196 }
1197 }
1198 return false
1199 }
1200
1201 if f.IsInt() {
1202 switch v.BaseValue.(type) {
1203 case *ListMarker:
1204 // TODO(perf): use precomputed length.
1205 if f.Index() < iterutil.Count(v.Elems()) {
1206 return true
1207 }
1208 return !v.IsClosedList()
1209
1210 default:
1211 return v.Kind()&ListKind != 0
1212 }
1213 }
1214
1215 if k := v.Kind(); k&StructKind == 0 && f.IsString() {
1216 // If the value is bottom, we may not really know if this used to
1217 // be a struct.
1218 if k != BottomKind || len(v.Structs) == 0 {
1219 return false
1220 }
1221 }
1222
1223 if v.IsOpenStruct() || v.Lookup(f) != nil {
1224 return true
1225 }
1226
1227 // TODO(perf): collect positions in error.
1228 defer ctx.ReleasePositions(ctx.MarkPositions())
1229
1230 return v.accepts(Accept(ctx, v, f))
1231}
1232
1233// MatchAndInsert finds the conjuncts for optional fields, pattern
1234// constraints, and additional constraints that match f and inserts them in
1235// arc. Use f is 0 to match all additional constraints only.
1236func (v *Vertex) MatchAndInsert(ctx *OpContext, arc *Vertex) {
1237 if !v.Accept(ctx, arc.Label) {
1238 return
1239 }
1240
1241 // Go backwards to simulate old implementation.
1242
1243 // This is the equivalent for the new implementation.
1244 if pcs := v.PatternConstraints; pcs != nil {
1245 for _, pc := range pcs.Pairs {
1246 if matchPattern(ctx, pc.Pattern, arc.Label) {
1247 for _, c := range pc.Constraint.Conjuncts {
1248 env := *(c.Env)
1249 if arc.Label.Index() < MaxIndex {
1250 env.DynamicLabel = arc.Label
1251 }
1252 c.Env = &env
1253
1254 arc.insertConjunct(ctx, c, c.CloseInfo, ArcMember, true, false)
1255 }
1256 }
1257 }
1258 }
1259
1260 if len(arc.Conjuncts) == 0 && v.HasEllipsis {
1261 // TODO: consider adding an Ellipsis fields to the Constraints struct
1262 // to record the original position of the elllipsis.
1263 c := MakeRootConjunct(nil, &Top{})
1264 arc.insertConjunct(ctx, c, c.CloseInfo, ArcOptional, false, false)
1265 }
1266}
1267func (v *Vertex) IsList() bool {
1268 _, ok := v.BaseValue.(*ListMarker)
1269 return ok
1270}
1271
1272// Lookup returns the Arc with label f if it exists or nil otherwise.
1273func (v *Vertex) Lookup(f Feature) *Vertex {
1274 for _, a := range v.Arcs {
1275 if a.Label == f {
1276 // TODO(P1)/TODO(deref): this indirection should ultimately be
1277 // eliminated: the original node may have useful information (like
1278 // original conjuncts) that are eliminated after indirection. We
1279 // should leave it up to the user of Lookup at what point an
1280 // indirection is necessary.
1281 a = a.DerefValue()
1282 return a
1283 }
1284 }
1285 return nil
1286}
1287
1288// LookupRaw returns the Arc with label f if it exists or nil otherwise.
1289//
1290// TODO: with the introduction of structure sharing, it is not always correct
1291// to indirect the arc. At the very least, this discards potential useful
1292// information. We introduce LookupRaw to avoid having to delete the
1293// information. Ultimately, this should become Lookup, or better, we should
1294// have a higher-level API for accessing values.
1295func (v *Vertex) LookupRaw(f Feature) *Vertex {
1296 for _, a := range v.Arcs {
1297 if a.Label == f {
1298 return a
1299 }
1300 }
1301 return nil
1302}
1303
1304// Elems returns the regular elements of a list.
1305func (v *Vertex) Elems() iter.Seq[*Vertex] {
1306 return func(yield func(*Vertex) bool) {
1307 // TODO: add bookkeeping for where list arcs start and end.
1308 for _, x := range v.Arcs {
1309 if x.Label.IsInt() {
1310 if !yield(x) {
1311 break
1312 }
1313 }
1314 }
1315 }
1316}
1317
1318func (v *Vertex) Init(c *OpContext) {
1319 v.getState(c)
1320}
1321
1322// GetArc returns a Vertex for the outgoing arc with label f. It creates and
1323// ads one if it doesn't yet exist.
1324func (v *Vertex) GetArc(c *OpContext, f Feature, t ArcType) (arc *Vertex, isNew bool) {
1325 arc = v.Lookup(f)
1326 if arc != nil {
1327 arc.updateArcType(t)
1328 return arc, false
1329 }
1330
1331 return nil, false
1332}
1333
1334func (v *Vertex) Source() ast.Node {
1335 if v != nil {
1336 if b, ok := v.BaseValue.(Value); ok {
1337 return b.Source()
1338 }
1339 }
1340 return nil
1341}
1342
1343// InsertConjunct is a low-level method to insert a conjunct into a Vertex.
1344// It should only be used by the compiler. It does not consider any logic
1345// that is necessary if a conjunct is added to a Vertex that is already being
1346// evaluated.
1347func (v *Vertex) InsertConjunct(c Conjunct) {
1348 v.Conjuncts = append(v.Conjuncts, c)
1349}
1350
1351// InsertConjunctsFrom is a low-level method to insert a conjuncts into a Vertex
1352// from another Vertex.
1353func (v *Vertex) InsertConjunctsFrom(w *Vertex) {
1354 v.Conjuncts = append(v.Conjuncts, w.Conjuncts...)
1355}
1356
1357// AddConjunct adds the given Conjuncts to v if it doesn't already exist.
1358func (v *Vertex) AddConjunct(c Conjunct) *Bottom {
1359 if v.BaseValue != nil && !isCyclePlaceholder(v.BaseValue) {
1360 // TODO: investigate why this happens at all. Removing it seems to
1361 // change the order of fields in some cases.
1362 //
1363 // This is likely a bug in the evaluator and should not happen.
1364 return &Bottom{
1365 Err: errors.Newf(token.NoPos, "cannot add conjunct"),
1366 Node: v,
1367 }
1368 }
1369 if !v.hasConjunct(c) {
1370 v.addConjunctUnchecked(c)
1371 }
1372 return nil
1373}
1374
1375func (v *Vertex) hasConjunct(c Conjunct) (added bool) {
1376 switch f := c.x.(type) {
1377 case *BulkOptionalField, *Ellipsis:
1378 case *Field:
1379 v.updateArcType(f.ArcType)
1380 case *DynamicField:
1381 v.updateArcType(f.ArcType)
1382 default:
1383 v.ArcType = ArcMember
1384 }
1385 var ctx *OpContext
1386 if v.state != nil {
1387 ctx = v.state.ctx
1388 }
1389 p, _ := findConjunct(ctx, v.Conjuncts, c)
1390 return p >= 0
1391}
1392
1393// findConjunct reports the position of c within cs or -1 if it is not found.
1394//
1395// NOTE: we are not comparing closeContexts. The intended use of this function
1396// is only to add to list of conjuncts within a closeContext.
1397func findConjunct(ctx *OpContext, cs []Conjunct, c Conjunct) (int, Conjunct) {
1398 for i, x := range cs {
1399 // TODO: disregard certain fields from comparison (e.g. Refs)?
1400 if x.x == c.x && x.Env.Equal(ctx, c.Env) {
1401 return i, x
1402 }
1403 }
1404 return -1, Conjunct{}
1405}
1406
1407func (v *Vertex) addConjunctUnchecked(c Conjunct) {
1408 v.Conjuncts = append(v.Conjuncts, c)
1409}
1410
1411func (v *Vertex) AddStruct(s *StructLit) {
1412 for i, t := range v.Structs {
1413 if t.StructLit == s {
1414 v.Structs[i].Repeats++
1415 return
1416 }
1417 }
1418 info := StructInfo{
1419 StructLit: s,
1420 }
1421 v.Structs = append(v.Structs, info)
1422}
1423
1424// Path computes the sequence of Features leading from the root to of the
1425// instance to this Vertex.
1426//
1427// NOTE: this is for debugging purposes only.
1428func (v *Vertex) Path() []Feature {
1429 return appendPath(nil, v)
1430}
1431
1432func appendPath(a []Feature, v *Vertex) []Feature {
1433 if v.Parent == nil {
1434 return a
1435 }
1436 a = appendPath(a, v.Parent)
1437 // Skip if the node is a structure-shared node that has been assingned to
1438 // the parent as it's new location: in this case the parent node will
1439 // have the desired label.
1440 if v.Label != 0 && v.Parent.BaseValue != v {
1441 // A Label may be 0 for programmatically inserted nodes.
1442 a = append(a, v.Label)
1443 }
1444 return a
1445}
1446
1447// A Conjunct is an Environment-Expr pair. The Environment is the starting
1448// point for reference lookup for any reference contained in X.
1449type Conjunct struct {
1450 Env *Environment
1451 x Node
1452
1453 // CloseInfo is a unique number that tracks a group of conjuncts that need
1454 // belong to a single originating definition.
1455 CloseInfo CloseInfo
1456}
1457
1458// MakeConjunct creates a conjunct from current Environment and CloseInfo of c.
1459func (c *OpContext) MakeConjunct(x Expr) Conjunct {
1460 return MakeConjunct(c.e, x, c.ci)
1461}
1462
1463// TODO(perf): replace with composite literal if this helps performance.
1464
1465// MakeRootConjunct creates a conjunct from the given environment and node.
1466// It panics if x cannot be used as an expression.
1467func MakeRootConjunct(env *Environment, x Node) Conjunct {
1468 return MakeConjunct(env, x, CloseInfo{})
1469}
1470
1471func MakeConjunct(env *Environment, x Node, id CloseInfo) Conjunct {
1472 if env == nil {
1473 // TODO: better is to pass one.
1474 env = &Environment{}
1475 }
1476 switch x.(type) {
1477 case Elem, interface{ expr() Expr }:
1478 default:
1479 panic(fmt.Sprintf("invalid Node type %T", x))
1480 }
1481 return Conjunct{env, x, id}
1482}
1483
1484func (c *Conjunct) Source() ast.Node {
1485 return c.x.Source()
1486}
1487
1488func (c *Conjunct) Field() Node {
1489 switch x := c.x.(type) {
1490 case *Comprehension:
1491 return x.Value
1492 default:
1493 return c.x
1494 }
1495}
1496
1497// Elem retrieves the Elem form of the contained conjunct.
1498// If it is a Field, it will return the field value.
1499func (c Conjunct) Elem() Elem {
1500 switch x := c.x.(type) {
1501 case interface{ expr() Expr }:
1502 return x.expr()
1503 case Elem:
1504 return x
1505 default:
1506 panic("unreachable")
1507 }
1508}
1509
1510// Expr retrieves the expression form of the contained conjunct. If it is a
1511// field or comprehension, it will return its associated value. This is only to
1512// be used for syntactic operations where evaluation of the expression is not
1513// required. To get an expression paired with the correct environment, use
1514// EnvExpr.
1515//
1516// TODO: rename to RawExpr.
1517func (c *Conjunct) Expr() Expr {
1518 return ToExpr(c.x)
1519}
1520
1521// EnvExpr returns the expression form of the contained conjunct alongside an
1522// Environment in which this expression should be evaluated.
1523func (c Conjunct) EnvExpr() (*Environment, Expr) {
1524 return EnvExpr(c.Env, c.Elem())
1525}
1526
1527// EnvExpr returns the expression represented by Elem alongside an Environment
1528// with the necessary adjustments in which the resulting expression can be
1529// evaluated.
1530func EnvExpr(env *Environment, elem Elem) (*Environment, Expr) {
1531 for {
1532 switch x := elem.(type) {
1533 case *ConjunctGroup:
1534 if len(*x) == 1 {
1535 c := (*x)[0]
1536 env = c.Env
1537 elem = c.Elem()
1538 continue
1539 }
1540 case *Comprehension:
1541 env = linkChildren(env, x)
1542 c := MakeConjunct(env, x.Value, CloseInfo{})
1543 elem = c.Elem()
1544 continue
1545 }
1546 break
1547 }
1548 return env, ToExpr(elem)
1549}
1550
1551// ToExpr extracts the underlying expression for a Node. If something is already
1552// an Expr, it will return it as is, if it is a field, it will return its value,
1553// and for comprehensions it returns the yielded struct.
1554func ToExpr(n Node) Expr {
1555 for {
1556 switch x := n.(type) {
1557 case *ConjunctGroup:
1558 if len(*x) != 1 {
1559 return x
1560 }
1561 n = (*x)[0].x
1562 case Expr:
1563 return x
1564 case interface{ expr() Expr }:
1565 n = x.expr()
1566 case *Comprehension:
1567 n = x.Value
1568 default:
1569 panic("unreachable")
1570 }
1571 }
1572}