github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/internal/core/adt/composite.go (about) 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 15 package adt 16 17 import ( 18 "fmt" 19 20 "github.com/joomcode/cue/cue/ast" 21 "github.com/joomcode/cue/cue/errors" 22 "github.com/joomcode/cue/cue/token" 23 ) 24 25 // TODO: unanswered questions about structural cycles: 26 // 27 // 1. When detecting a structural cycle, should we consider this as: 28 // a) an unevaluated value, 29 // b) an incomplete error (which does not affect parent validity), or 30 // c) a special value. 31 // 32 // Making it an error is the simplest way to ensure reentrancy is disallowed: 33 // without an error it would require an additional mechanism to stop reentrancy 34 // from continuing to process. Even worse, in some cases it may only partially 35 // evaluate, resulting in unexpected results. For this reason, we are taking 36 // approach `b` for now. 37 // 38 // This has some consequences of how disjunctions are treated though. Consider 39 // 40 // list: { 41 // head: _ 42 // tail: list | null 43 // } 44 // 45 // When making it an error, evaluating the above will result in 46 // 47 // list: { 48 // head: _ 49 // tail: null 50 // } 51 // 52 // because list will result in a structural cycle, and thus an error, it will be 53 // stripped from the disjunction. This may or may not be a desirable property. A 54 // nice thing is that it is not required to write `list | *null`. A disadvantage 55 // is that this is perhaps somewhat inexplicit. 56 // 57 // When not making it an error (and simply cease evaluating child arcs upon 58 // cycle detection), the result would be: 59 // 60 // list: { 61 // head: _ 62 // tail: list | null 63 // } 64 // 65 // In other words, an evaluation would result in a cycle and thus an error. 66 // Implementations can recognize such cases by having unevaluated arcs. An 67 // explicit structure cycle marker would probably be less error prone. 68 // 69 // Note that in both cases, a reference to list will still use the original 70 // conjuncts, so the result will be the same for either method in this case. 71 // 72 // 73 // 2. Structural cycle allowance. 74 // 75 // Structural cycle detection disallows reentrancy as well. This means one 76 // cannot use structs for recursive computation. This will probably preclude 77 // evaluation of some configuration. Given that there is no real alternative 78 // yet, we could allow structural cycle detection to be optionally disabled. 79 80 // An Environment links the parent scopes for identifier lookup to a composite 81 // node. Each conjunct that make up node in the tree can be associated with 82 // a different environment (although some conjuncts may share an Environment). 83 type Environment struct { 84 Up *Environment 85 Vertex *Vertex 86 87 // DynamicLabel is only set when instantiating a field from a pattern 88 // constraint. It is used to resolve label references. 89 DynamicLabel Feature 90 91 // TODO(perf): make the following public fields a shareable struct as it 92 // mostly is going to be the same for child nodes. 93 94 // Cyclic indicates a structural cycle was detected for this conjunct or one 95 // of its ancestors. 96 Cyclic bool 97 98 // Deref keeps track of nodes that should dereference to Vertex. It is used 99 // for detecting structural cycle. 100 // 101 // The detection algorithm is based on Tomabechi's quasi-destructive graph 102 // unification. This detection requires dependencies to be resolved into 103 // fully dereferenced vertices. This is not the case in our algorithm: 104 // the result of evaluating conjuncts is placed into dereferenced vertices 105 // _after_ they are evaluated, but the Environment still points to the 106 // non-dereferenced context. 107 // 108 // In order to be able to detect structural cycles, we need to ensure that 109 // at least one node that is part of a cycle in the context in which 110 // conjunctions are evaluated dereferences correctly. 111 // 112 // The only field necessary to detect a structural cycle, however, is 113 // the Status field of the Vertex. So rather than dereferencing a node 114 // proper, it is sufficient to copy the Status of the dereferenced nodes 115 // to these nodes (will always be EvaluatingArcs). 116 Deref []*Vertex 117 118 // Cycles contains vertices for which cycles are detected. It is used 119 // for tracking self-references within structural cycles. 120 // 121 // Unlike Deref, Cycles is not incremented with child nodes. 122 // TODO: Cycles is always a tail end of Deref, so this can be optimized. 123 Cycles []*Vertex 124 125 cache map[Expr]Value 126 } 127 128 type ID int32 129 130 // evalCached is used to look up let expressions. Caching let expressions 131 // prevents a possible combinatorial explosion. 132 func (e *Environment) evalCached(c *OpContext, x Expr) Value { 133 if v, ok := x.(Value); ok { 134 return v 135 } 136 v, ok := e.cache[x] 137 if !ok { 138 if e.cache == nil { 139 e.cache = map[Expr]Value{} 140 } 141 env, src := c.e, c.src 142 c.e, c.src = e, x.Source() 143 v = c.evalState(x, Partial) // TODO: should this be Finalized? 144 c.e, c.src = env, src 145 if b, ok := v.(*Bottom); !ok || !b.IsIncomplete() { 146 e.cache[x] = v 147 } 148 } 149 return v 150 } 151 152 // A Vertex is a node in the value tree. It may be a leaf or internal node. 153 // It may have arcs to represent elements of a fully evaluated struct or list. 154 // 155 // For structs, it only contains definitions and concrete fields. 156 // optional fields are dropped. 157 // 158 // It maintains source information such as a list of conjuncts that contributed 159 // to the value. 160 type Vertex struct { 161 // Parent links to a parent Vertex. This parent should only be used to 162 // access the parent's Label field to find the relative location within a 163 // tree. 164 Parent *Vertex 165 166 // Label is the feature leading to this vertex. 167 Label Feature 168 169 // State: 170 // eval: nil, BaseValue: nil -- unevaluated 171 // eval: *, BaseValue: nil -- evaluating 172 // eval: *, BaseValue: * -- finalized 173 // 174 state *nodeContext 175 // TODO: move the following status fields to nodeContext. 176 177 // status indicates the evaluation progress of this vertex. 178 status VertexStatus 179 180 // isData indicates that this Vertex is to be interepreted as data: pattern 181 // and additional constraints, as well as optional fields, should be 182 // ignored. 183 isData bool 184 Closed bool 185 nonMonotonicReject bool 186 nonMonotonicInsertGen int32 187 nonMonotonicLookupGen int32 188 189 // EvalCount keeps track of temporary dereferencing during evaluation. 190 // If EvalCount > 0, status should be considered to be EvaluatingArcs. 191 EvalCount int32 192 193 // SelfCount is used for tracking self-references. 194 SelfCount int32 195 196 // BaseValue is the value associated with this vertex. For lists and structs 197 // this is a sentinel value indicating its kind. 198 BaseValue BaseValue 199 200 // ChildErrors is the collection of all errors of children. 201 ChildErrors *Bottom 202 203 // The parent of nodes can be followed to determine the path within the 204 // configuration of this node. 205 // Value Value 206 Arcs []*Vertex // arcs are sorted in display order. 207 208 // Conjuncts lists the structs that ultimately formed this Composite value. 209 // This includes all selected disjuncts. 210 // 211 // This value may be nil, in which case the Arcs are considered to define 212 // the final value of this Vertex. 213 Conjuncts []Conjunct 214 215 // Structs is a slice of struct literals that contributed to this value. 216 // This information is used to compute the topological sort of arcs. 217 Structs []*StructInfo 218 } 219 220 func (v *Vertex) Clone() *Vertex { 221 c := *v 222 c.state = nil 223 return &c 224 } 225 226 type StructInfo struct { 227 *StructLit 228 229 Env *Environment 230 231 CloseInfo 232 233 // Embed indicates the struct in which this struct is embedded (originally), 234 // or nil if this is a root structure. 235 // Embed *StructInfo 236 // Context *RefInfo // the location from which this struct originates. 237 Disable bool 238 239 Embedding bool 240 } 241 242 // TODO(perf): this could be much more aggressive for eliminating structs that 243 // are immaterial for closing. 244 func (s *StructInfo) useForAccept() bool { 245 if c := s.closeInfo; c != nil { 246 return !c.noCheck 247 } 248 return true 249 } 250 251 // VertexStatus indicates the evaluation progress of a Vertex. 252 type VertexStatus int8 253 254 const ( 255 // Unprocessed indicates a Vertex has not been processed before. 256 // Value must be nil. 257 Unprocessed VertexStatus = iota 258 259 // Evaluating means that the current Vertex is being evaluated. If this is 260 // encountered it indicates a reference cycle. Value must be nil. 261 Evaluating 262 263 // Partial indicates that the result was only partially evaluated. It will 264 // need to be fully evaluated to get a complete results. 265 // 266 // TODO: this currently requires a renewed computation. Cache the 267 // nodeContext to allow reusing the computations done so far. 268 Partial 269 270 // AllArcs is request only. It must be past Partial, but 271 // before recursively resolving arcs. 272 AllArcs 273 274 // EvaluatingArcs indicates that the arcs of the Vertex are currently being 275 // evaluated. If this is encountered it indicates a structural cycle. 276 // Value does not have to be nil 277 EvaluatingArcs 278 279 // Finalized means that this node is fully evaluated and that the results 280 // are save to use without further consideration. 281 Finalized 282 ) 283 284 func (s VertexStatus) String() string { 285 switch s { 286 case Unprocessed: 287 return "unprocessed" 288 case Evaluating: 289 return "evaluating" 290 case Partial: 291 return "partial" 292 case AllArcs: 293 return "allarcs" 294 case EvaluatingArcs: 295 return "evaluatingArcs" 296 case Finalized: 297 return "finalized" 298 default: 299 return "unknown" 300 } 301 } 302 303 func (v *Vertex) Status() VertexStatus { 304 if v.EvalCount > 0 { 305 return EvaluatingArcs 306 } 307 return v.status 308 } 309 310 func (v *Vertex) UpdateStatus(s VertexStatus) { 311 Assertf(v.status <= s+1, "attempt to regress status from %d to %d", v.Status(), s) 312 313 if s == Finalized && v.BaseValue == nil { 314 // panic("not finalized") 315 } 316 v.status = s 317 } 318 319 // Value returns the Value of v without definitions if it is a scalar 320 // or itself otherwise. 321 func (v *Vertex) Value() Value { 322 switch x := v.BaseValue.(type) { 323 case nil: 324 return nil 325 case *StructMarker, *ListMarker: 326 return v 327 case Value: 328 // TODO: recursively descend into Vertex? 329 return x 330 default: 331 panic(fmt.Sprintf("unexpected type %T", v.BaseValue)) 332 } 333 } 334 335 // isUndefined reports whether a vertex does not have a useable BaseValue yet. 336 func (v *Vertex) isUndefined() bool { 337 switch v.BaseValue { 338 case nil, cycle: 339 return true 340 } 341 return false 342 } 343 344 func (x *Vertex) IsConcrete() bool { 345 return x.Concreteness() <= Concrete 346 } 347 348 // IsData reports whether v should be interpreted in data mode. In other words, 349 // it tells whether optional field matching and non-regular fields, like 350 // definitions and hidden fields, should be ignored. 351 func (v *Vertex) IsData() bool { 352 return v.isData || len(v.Conjuncts) == 0 353 } 354 355 // ToDataSingle creates a new Vertex that represents just the regular fields 356 // of this vertex. Arcs are left untouched. 357 // It is used by cue.Eval to convert nodes to data on per-node basis. 358 func (v *Vertex) ToDataSingle() *Vertex { 359 w := *v 360 w.isData = true 361 w.state = nil 362 w.status = Finalized 363 return &w 364 } 365 366 // ToDataAll returns a new v where v and all its descendents contain only 367 // the regular fields. 368 func (v *Vertex) ToDataAll() *Vertex { 369 arcs := make([]*Vertex, 0, len(v.Arcs)) 370 for _, a := range v.Arcs { 371 if a.Label.IsRegular() { 372 arcs = append(arcs, a.ToDataAll()) 373 } 374 } 375 w := *v 376 w.state = nil 377 w.status = Finalized 378 379 w.BaseValue = toDataAll(w.BaseValue) 380 w.Arcs = arcs 381 w.isData = true 382 w.Conjuncts = make([]Conjunct, len(v.Conjuncts)) 383 // TODO(perf): this is not strictly necessary for evaluation, but it can 384 // hurt performance greatly. Drawback is that it may disable ordering. 385 for _, s := range w.Structs { 386 s.Disable = true 387 } 388 copy(w.Conjuncts, v.Conjuncts) 389 for i, c := range w.Conjuncts { 390 if v, _ := c.x.(Value); v != nil { 391 w.Conjuncts[i].x = toDataAll(v).(Value) 392 } 393 } 394 return &w 395 } 396 397 func toDataAll(v BaseValue) BaseValue { 398 switch x := v.(type) { 399 default: 400 return x 401 402 case *Vertex: 403 return x.ToDataAll() 404 405 // The following cases are always erroneous, but we handle them anyway 406 // to avoid issues with the closedness algorithm down the line. 407 case *Disjunction: 408 d := *x 409 d.Values = make([]*Vertex, len(x.Values)) 410 for i, v := range x.Values { 411 d.Values[i] = v.ToDataAll() 412 } 413 return &d 414 415 case *Conjunction: 416 c := *x 417 c.Values = make([]Value, len(x.Values)) 418 for i, v := range x.Values { 419 // This case is okay because the source is of type Value. 420 c.Values[i] = toDataAll(v).(Value) 421 } 422 return &c 423 } 424 } 425 426 // func (v *Vertex) IsEvaluating() bool { 427 // return v.Value == cycle 428 // } 429 430 func (v *Vertex) IsErr() bool { 431 // if v.Status() > Evaluating { 432 if _, ok := v.BaseValue.(*Bottom); ok { 433 return true 434 } 435 // } 436 return false 437 } 438 439 func (v *Vertex) Err(c *OpContext, state VertexStatus) *Bottom { 440 c.Unify(v, state) 441 if b, ok := v.BaseValue.(*Bottom); ok { 442 return b 443 } 444 return nil 445 } 446 447 // func (v *Vertex) Evaluate() 448 449 func (v *Vertex) Finalize(c *OpContext) { 450 // Saving and restoring the error context prevents v from panicking in 451 // case the caller did not handle existing errors in the context. 452 err := c.errs 453 c.errs = nil 454 c.Unify(v, Finalized) 455 c.errs = err 456 } 457 458 func (v *Vertex) AddErr(ctx *OpContext, b *Bottom) { 459 v.SetValue(ctx, Finalized, CombineErrors(nil, v.Value(), b)) 460 } 461 462 func (v *Vertex) SetValue(ctx *OpContext, state VertexStatus, value BaseValue) *Bottom { 463 v.BaseValue = value 464 v.UpdateStatus(state) 465 return nil 466 } 467 468 // ToVertex wraps v in a new Vertex, if necessary. 469 func ToVertex(v Value) *Vertex { 470 switch x := v.(type) { 471 case *Vertex: 472 return x 473 default: 474 n := &Vertex{ 475 status: Finalized, 476 BaseValue: x, 477 } 478 n.AddConjunct(MakeRootConjunct(nil, v)) 479 return n 480 } 481 } 482 483 // Unwrap returns the possibly non-concrete scalar value of v or nil if v is 484 // a list, struct or of undefined type. 485 func Unwrap(v Value) Value { 486 x, ok := v.(*Vertex) 487 if !ok { 488 return v 489 } 490 x = x.Indirect() 491 if n := x.state; n != nil && isCyclePlaceholder(x.BaseValue) { 492 if n.errs != nil && !n.errs.IsIncomplete() { 493 return n.errs 494 } 495 if n.scalar != nil { 496 return n.scalar 497 } 498 } 499 return x.Value() 500 } 501 502 // Indirect unrolls indirections of Vertex values. These may be introduced, 503 // for instance, by temporary bindings such as comprehension values. 504 // It returns v itself if v does not point to another Vertex. 505 func (v *Vertex) Indirect() *Vertex { 506 for { 507 arc, ok := v.BaseValue.(*Vertex) 508 if !ok { 509 return v 510 } 511 v = arc 512 } 513 } 514 515 // OptionalType is a bit field of the type of optional constraints in use by an 516 // Acceptor. 517 type OptionalType int8 518 519 const ( 520 HasField OptionalType = 1 << iota // X: T 521 HasDynamic // (X): T or "\(X)": T 522 HasPattern // [X]: T 523 HasComplexPattern // anything but a basic type 524 HasAdditional // ...T 525 IsOpen // Defined for all fields 526 ) 527 528 func (v *Vertex) Kind() Kind { 529 // This is possible when evaluating comprehensions. It is potentially 530 // not known at this time what the type is. 531 switch { 532 case v.state != nil: 533 return v.state.kind 534 case v.BaseValue == nil: 535 return TopKind 536 default: 537 return v.BaseValue.Kind() 538 } 539 } 540 541 func (v *Vertex) OptionalTypes() OptionalType { 542 var mask OptionalType 543 for _, s := range v.Structs { 544 mask |= s.OptionalTypes() 545 } 546 return mask 547 } 548 549 // IsOptional reports whether a field is explicitly defined as optional, 550 // as opposed to whether it is allowed by a pattern constraint. 551 func (v *Vertex) IsOptional(label Feature) bool { 552 for _, s := range v.Structs { 553 if s.IsOptional(label) { 554 return true 555 } 556 } 557 return false 558 } 559 560 func (v *Vertex) accepts(ok, required bool) bool { 561 return ok || (!required && !v.Closed) 562 } 563 564 func (v *Vertex) IsClosedStruct() bool { 565 switch x := v.BaseValue.(type) { 566 default: 567 return false 568 569 case *StructMarker: 570 if x.NeedClose { 571 return true 572 } 573 574 case *Disjunction: 575 } 576 return v.Closed || isClosed(v) 577 } 578 579 func (v *Vertex) IsClosedList() bool { 580 if x, ok := v.BaseValue.(*ListMarker); ok { 581 return !x.IsOpen 582 } 583 return false 584 } 585 586 // TODO: return error instead of boolean? (or at least have version that does.) 587 func (v *Vertex) Accept(ctx *OpContext, f Feature) bool { 588 if x, ok := v.BaseValue.(*Disjunction); ok { 589 for _, v := range x.Values { 590 if v.Accept(ctx, f) { 591 return true 592 } 593 } 594 return false 595 } 596 597 if f.IsInt() { 598 switch v.BaseValue.(type) { 599 case *ListMarker: 600 // TODO(perf): use precomputed length. 601 if f.Index() < len(v.Elems()) { 602 return true 603 } 604 return !v.IsClosedList() 605 606 default: 607 return v.Kind()&ListKind != 0 608 } 609 } 610 611 if k := v.Kind(); k&StructKind == 0 && f.IsString() { 612 // If the value is bottom, we may not really know if this used to 613 // be a struct. 614 if k != BottomKind || len(v.Structs) == 0 { 615 return false 616 } 617 } 618 619 if f.IsHidden() || !v.IsClosedStruct() || v.Lookup(f) != nil { 620 return true 621 } 622 623 // TODO(perf): collect positions in error. 624 defer ctx.ReleasePositions(ctx.MarkPositions()) 625 626 return v.accepts(Accept(ctx, v, f)) 627 } 628 629 // MatchAndInsert finds the conjuncts for optional fields, pattern 630 // constraints, and additional constraints that match f and inserts them in 631 // arc. Use f is 0 to match all additional constraints only. 632 func (v *Vertex) MatchAndInsert(ctx *OpContext, arc *Vertex) { 633 if !v.Accept(ctx, arc.Label) { 634 return 635 } 636 637 // Go backwards to simulate old implementation. 638 for i := len(v.Structs) - 1; i >= 0; i-- { 639 s := v.Structs[i] 640 if s.Disable { 641 continue 642 } 643 s.MatchAndInsert(ctx, arc) 644 } 645 } 646 647 func (v *Vertex) IsList() bool { 648 _, ok := v.BaseValue.(*ListMarker) 649 return ok 650 } 651 652 // Lookup returns the Arc with label f if it exists or nil otherwise. 653 func (v *Vertex) Lookup(f Feature) *Vertex { 654 for _, a := range v.Arcs { 655 if a.Label == f { 656 a = a.Indirect() 657 return a 658 } 659 } 660 return nil 661 } 662 663 // Elems returns the regular elements of a list. 664 func (v *Vertex) Elems() []*Vertex { 665 // TODO: add bookkeeping for where list arcs start and end. 666 a := make([]*Vertex, 0, len(v.Arcs)) 667 for _, x := range v.Arcs { 668 if x.Label.IsInt() { 669 a = append(a, x) 670 } 671 } 672 return a 673 } 674 675 // GetArc returns a Vertex for the outgoing arc with label f. It creates and 676 // ads one if it doesn't yet exist. 677 func (v *Vertex) GetArc(c *OpContext, f Feature) (arc *Vertex, isNew bool) { 678 arc = v.Lookup(f) 679 if arc == nil { 680 for _, a := range v.state.usedArcs { 681 if a.Label == f { 682 arc = a 683 v.Arcs = append(v.Arcs, arc) 684 isNew = true 685 if c.nonMonotonicInsertNest > 0 { 686 a.nonMonotonicInsertGen = c.nonMonotonicGeneration 687 } 688 break 689 } 690 } 691 } 692 if arc == nil { 693 arc = &Vertex{Parent: v, Label: f} 694 v.Arcs = append(v.Arcs, arc) 695 isNew = true 696 if c.nonMonotonicInsertNest > 0 { 697 arc.nonMonotonicInsertGen = c.nonMonotonicGeneration 698 } 699 } 700 if c.nonMonotonicInsertNest == 0 { 701 arc.nonMonotonicInsertGen = 0 702 } 703 return arc, isNew 704 } 705 706 func (v *Vertex) Source() ast.Node { 707 if v != nil { 708 if b, ok := v.BaseValue.(Value); ok { 709 return b.Source() 710 } 711 } 712 return nil 713 } 714 715 // AddConjunct adds the given Conjuncts to v if it doesn't already exist. 716 func (v *Vertex) AddConjunct(c Conjunct) *Bottom { 717 if v.BaseValue != nil { 718 // TODO: investigate why this happens at all. Removing it seems to 719 // change the order of fields in some cases. 720 // 721 // This is likely a bug in the evaluator and should not happen. 722 return &Bottom{Err: errors.Newf(token.NoPos, "cannot add conjunct")} 723 } 724 v.addConjunct(c) 725 return nil 726 } 727 728 func (v *Vertex) addConjunct(c Conjunct) { 729 for _, x := range v.Conjuncts { 730 if x == c { 731 return 732 } 733 } 734 v.Conjuncts = append(v.Conjuncts, c) 735 } 736 737 func (v *Vertex) AddStruct(s *StructLit, env *Environment, ci CloseInfo) *StructInfo { 738 info := StructInfo{ 739 StructLit: s, 740 Env: env, 741 CloseInfo: ci, 742 } 743 for _, t := range v.Structs { 744 if *t == info { 745 return t 746 } 747 } 748 t := &info 749 v.Structs = append(v.Structs, t) 750 return t 751 } 752 753 // Path computes the sequence of Features leading from the root to of the 754 // instance to this Vertex. 755 // 756 // NOTE: this is for debugging purposes only. 757 func (v *Vertex) Path() []Feature { 758 return appendPath(nil, v) 759 } 760 761 func appendPath(a []Feature, v *Vertex) []Feature { 762 if v.Parent == nil { 763 return a 764 } 765 a = appendPath(a, v.Parent) 766 if v.Label != 0 { 767 // A Label may be 0 for programmatically inserted nodes. 768 a = append(a, v.Label) 769 } 770 return a 771 } 772 773 // An Conjunct is an Environment-Expr pair. The Environment is the starting 774 // point for reference lookup for any reference contained in X. 775 type Conjunct struct { 776 Env *Environment 777 x Node 778 779 // CloseInfo is a unique number that tracks a group of conjuncts that need 780 // belong to a single originating definition. 781 CloseInfo CloseInfo 782 } 783 784 // TODO(perf): replace with composite literal if this helps performance. 785 786 // MakeRootConjunct creates a conjunct from the given environment and node. 787 // It panics if x cannot be used as an expression. 788 func MakeRootConjunct(env *Environment, x Node) Conjunct { 789 return MakeConjunct(env, x, CloseInfo{}) 790 } 791 792 func MakeConjunct(env *Environment, x Node, id CloseInfo) Conjunct { 793 if env == nil { 794 // TODO: better is to pass one. 795 env = &Environment{} 796 } 797 switch x.(type) { 798 case Elem, interface{ expr() Expr }: 799 default: 800 panic(fmt.Sprintf("invalid Node type %T", x)) 801 } 802 return Conjunct{env, x, id} 803 } 804 805 func (c *Conjunct) Source() ast.Node { 806 return c.x.Source() 807 } 808 809 func (c *Conjunct) Field() Node { 810 return c.x 811 } 812 813 // Elem retrieves the Elem form of the contained conjunct. 814 // If it is a Field, it will return the field value. 815 func (c *Conjunct) Elem() Elem { 816 switch x := c.x.(type) { 817 case interface{ expr() Expr }: 818 return x.expr() 819 case Elem: 820 return x 821 default: 822 panic("unreachable") 823 } 824 } 825 826 // Expr retrieves the expression form of the contained conjunct. 827 // If it is a field or comprehension, it will return its associated value. 828 func (c *Conjunct) Expr() Expr { 829 switch x := c.x.(type) { 830 case Expr: 831 return x 832 // TODO: comprehension. 833 case interface{ expr() Expr }: 834 return x.expr() 835 default: 836 panic("unreachable") 837 } 838 }