cuelang.org/go@v0.13.0/internal/core/adt/default.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 "slices" 19 ) 20 21 // Default returns the default value or itself if there is no default. 22 func Default(v Value) Value { 23 switch x := v.(type) { 24 case *Vertex: 25 return x.Default() 26 case *Disjunction: 27 return x.Default() 28 default: 29 return v 30 } 31 } 32 33 func (d *Disjunction) Default() Value { 34 switch d.NumDefaults { 35 case 0: 36 return d 37 case 1: 38 return d.Values[0] 39 default: 40 return &Disjunction{ 41 Src: d.Src, 42 Values: d.Values[:d.NumDefaults], 43 NumDefaults: 0, 44 } 45 } 46 } 47 48 // Default returns the default value or itself if there is no default. 49 // 50 // It also closes a list, representing its default value. 51 func (v *Vertex) Default() *Vertex { 52 v = v.DerefValue() 53 switch d := v.BaseValue.(type) { 54 default: 55 return v 56 57 case *Disjunction: 58 var w *Vertex 59 60 switch d.NumDefaults { 61 case 0: 62 return v 63 case 1: 64 w = ToVertex(Default(d.Values[0])) 65 default: 66 x := *v 67 x.state = nil 68 x.BaseValue = &Disjunction{ 69 Src: d.Src, 70 Values: d.Values[:d.NumDefaults], 71 NumDefaults: 0, 72 } 73 w = &x 74 w.Conjuncts = nil 75 } 76 77 if w.Conjuncts == nil { 78 for _, c := range v.Conjuncts { 79 // TODO: preserve field information. 80 expr, _ := stripNonDefaults(c.Elem()) 81 w.Conjuncts = append(w.Conjuncts, MakeRootConjunct(c.Env, expr)) 82 } 83 } 84 return w 85 86 case *ListMarker: 87 m := *d 88 m.IsOpen = false 89 90 w := *v 91 w.BaseValue = &m 92 w.state = nil 93 return &w 94 } 95 } 96 97 // TODO: this should go: record preexpanded disjunctions in Vertex. 98 func stripNonDefaults(elem Elem) (r Elem, stripped bool) { 99 expr, ok := elem.(Expr) 100 if !ok { 101 return elem, false 102 } 103 switch x := expr.(type) { 104 case *DisjunctionExpr: 105 if !x.HasDefaults { 106 return x, false 107 } 108 d := *x 109 d.Values = []Disjunct{} 110 for _, v := range x.Values { 111 if v.Default { 112 d.Values = append(d.Values, v) 113 } 114 } 115 if len(d.Values) == 1 { 116 return d.Values[0].Val, true 117 } 118 return &d, true 119 120 case *BinaryExpr: 121 if x.Op != AndOp { 122 return x, false 123 } 124 a, sa := stripNonDefaults(x.X) 125 b, sb := stripNonDefaults(x.Y) 126 if sa || sb { 127 bin := *x 128 bin.X = a.(Expr) 129 bin.Y = b.(Expr) 130 return &bin, true 131 } 132 return x, false 133 134 case *ConjunctGroup: 135 // NOTE: this code requires allocations unconditional. This should be 136 // mitigated once we optimize conjunct groupings. 137 isNew := false 138 a := slices.Clone(*x) 139 for i, c := range a { 140 a[i].x, ok = stripNonDefaults(c.Elem()) 141 if ok { 142 isNew = true 143 } 144 } 145 if isNew { 146 return &a, true 147 } 148 return x, false 149 150 default: 151 return x, false 152 } 153 }