this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 1572 lines 45 kB view raw
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}