github.com/solo-io/cue@v0.4.7/cue/instance.go (about) 1 // Copyright 2018 The 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 cue 16 17 import ( 18 "github.com/solo-io/cue/cue/ast" 19 "github.com/solo-io/cue/cue/build" 20 "github.com/solo-io/cue/cue/errors" 21 "github.com/solo-io/cue/internal" 22 "github.com/solo-io/cue/internal/core/adt" 23 "github.com/solo-io/cue/internal/core/compile" 24 "github.com/solo-io/cue/internal/core/runtime" 25 ) 26 27 // An InstanceOrValue is implemented by Value and *Instance. 28 // 29 // This is a placeholder type that is used to allow Instance-based APIs to 30 // transition to Value-based APIs. The goals is to get rid of the Instance 31 // type before v1.0.0. 32 type InstanceOrValue interface { 33 Value() Value 34 35 internal() 36 } 37 38 func (Value) internal() {} 39 func (*Instance) internal() {} 40 41 // Value implements value.Instance. 42 func (v hiddenValue) Value() Value { return v } 43 44 // An Instance defines a single configuration based on a collection of 45 // underlying CUE files. 46 type Instance struct { 47 index *runtime.Runtime 48 49 root *adt.Vertex 50 51 ImportPath string 52 Dir string 53 PkgName string 54 DisplayName string 55 56 Incomplete bool // true if Pkg and all its dependencies are free of errors 57 Err errors.Error // non-nil if the package had errors 58 59 inst *build.Instance 60 } 61 62 type hiddenInstance = Instance 63 64 func addInst(x *runtime.Runtime, p *Instance) *Instance { 65 if p.inst == nil { 66 p.inst = &build.Instance{ 67 ImportPath: p.ImportPath, 68 PkgName: p.PkgName, 69 } 70 } 71 x.AddInst(p.ImportPath, p.root, p.inst) 72 x.SetBuildData(p.inst, p) 73 p.index = x 74 return p 75 } 76 77 func lookupInstance(x *runtime.Runtime, p *build.Instance) *Instance { 78 if x, ok := x.BuildData(p); ok { 79 return x.(*Instance) 80 } 81 return nil 82 } 83 84 func getImportFromBuild(x *runtime.Runtime, p *build.Instance, v *adt.Vertex) *Instance { 85 inst := lookupInstance(x, p) 86 87 if inst != nil { 88 return inst 89 } 90 91 inst = &Instance{ 92 ImportPath: p.ImportPath, 93 Dir: p.Dir, 94 PkgName: p.PkgName, 95 DisplayName: p.ImportPath, 96 root: v, 97 inst: p, 98 index: x, 99 } 100 if p.Err != nil { 101 inst.setListOrError(p.Err) 102 } 103 104 x.SetBuildData(p, inst) 105 106 return inst 107 } 108 109 func getImportFromNode(x *runtime.Runtime, v *adt.Vertex) *Instance { 110 p := x.GetInstanceFromNode(v) 111 if p == nil { 112 return nil 113 } 114 115 return getImportFromBuild(x, p, v) 116 } 117 118 func getImportFromPath(x *runtime.Runtime, id string) *Instance { 119 node, _ := x.LoadImport(id) 120 if node == nil { 121 return nil 122 } 123 b := x.GetInstanceFromNode(node) 124 inst := lookupInstance(x, b) 125 if inst == nil { 126 inst = &Instance{ 127 ImportPath: b.ImportPath, 128 PkgName: b.PkgName, 129 root: node, 130 inst: b, 131 index: x, 132 } 133 } 134 return inst 135 } 136 137 func init() { 138 internal.MakeInstance = func(value interface{}) interface{} { 139 v := value.(Value) 140 x := v.eval(v.ctx()) 141 st, ok := x.(*adt.Vertex) 142 if !ok { 143 st = &adt.Vertex{} 144 st.AddConjunct(adt.MakeRootConjunct(nil, x)) 145 } 146 return addInst(v.idx, &Instance{ 147 root: st, 148 }) 149 } 150 } 151 152 // newInstance creates a new instance. Use Insert to populate the instance. 153 func newInstance(x *runtime.Runtime, p *build.Instance, v *adt.Vertex) *Instance { 154 // TODO: associate root source with structLit. 155 inst := &Instance{ 156 root: v, 157 inst: p, 158 } 159 if p != nil { 160 inst.ImportPath = p.ImportPath 161 inst.Dir = p.Dir 162 inst.PkgName = p.PkgName 163 inst.DisplayName = p.ImportPath 164 if p.Err != nil { 165 inst.setListOrError(p.Err) 166 } 167 } 168 169 x.AddInst(p.ImportPath, v, p) 170 x.SetBuildData(p, inst) 171 inst.index = x 172 return inst 173 } 174 175 func (inst *Instance) setListOrError(err errors.Error) { 176 inst.Incomplete = true 177 inst.Err = errors.Append(inst.Err, err) 178 } 179 180 func (inst *Instance) setError(err errors.Error) { 181 inst.Incomplete = true 182 inst.Err = errors.Append(inst.Err, err) 183 } 184 185 func (inst *Instance) eval(ctx *adt.OpContext) adt.Value { 186 // TODO: remove manifest here? 187 v := manifest(ctx, inst.root) 188 return v 189 } 190 191 // ID returns the package identifier that uniquely qualifies module and 192 // package name. 193 func (inst *Instance) ID() string { 194 if inst == nil || inst.inst == nil { 195 return "" 196 } 197 return inst.inst.ID() 198 } 199 200 // Doc returns the package comments for this instance. 201 // 202 // Deprecated: use inst.Value().Doc() 203 func (inst *hiddenInstance) Doc() []*ast.CommentGroup { 204 return inst.Value().Doc() 205 } 206 207 // Value returns the root value of the configuration. If the configuration 208 // defines in emit value, it will be that value. Otherwise it will be all 209 // top-level values. 210 func (inst *Instance) Value() Value { 211 ctx := newContext(inst.index) 212 inst.root.Finalize(ctx) 213 return newVertexRoot(inst.index, ctx, inst.root) 214 } 215 216 // Eval evaluates an expression within an existing instance. 217 // 218 // Expressions may refer to builtin packages if they can be uniquely identified. 219 // 220 // Deprecated: use 221 // inst.Value().Context().BuildExpr(expr, Scope(inst.Value), InferBuiltins(true)) 222 func (inst *hiddenInstance) Eval(expr ast.Expr) Value { 223 v := inst.Value() 224 return v.Context().BuildExpr(expr, Scope(v), InferBuiltins(true)) 225 } 226 227 // DO NOT USE. 228 // 229 // Deprecated: do not use. 230 func Merge(inst ...*Instance) *Instance { 231 v := &adt.Vertex{} 232 233 i := inst[0] 234 ctx := newContext(i.index) 235 236 // TODO: interesting test: use actual unification and then on K8s corpus. 237 238 for _, i := range inst { 239 w := i.Value() 240 v.AddConjunct(adt.MakeRootConjunct(nil, w.v.ToDataAll())) 241 } 242 v.Finalize(ctx) 243 244 p := addInst(i.index, &Instance{ 245 root: v, 246 }) 247 return p 248 } 249 250 // Build creates a new instance from the build instances, allowing unbound 251 // identifier to bind to the top-level field in inst. The top-level fields in 252 // inst take precedence over predeclared identifier and builtin functions. 253 // 254 // Deprecated: use Context.Build 255 func (inst *hiddenInstance) Build(p *build.Instance) *Instance { 256 p.Complete() 257 258 idx := inst.index 259 r := inst.index 260 261 rErr := r.ResolveFiles(p) 262 263 cfg := &compile.Config{Scope: valueScope(Value{idx: r, v: inst.root})} 264 v, err := compile.Files(cfg, r, p.ID(), p.Files...) 265 266 v.AddConjunct(adt.MakeRootConjunct(nil, inst.root)) 267 268 i := newInstance(idx, p, v) 269 if rErr != nil { 270 i.setListOrError(rErr) 271 } 272 if i.Err != nil { 273 i.setListOrError(i.Err) 274 } 275 276 if err != nil { 277 i.setListOrError(err) 278 } 279 280 return i 281 } 282 283 func (inst *Instance) value() Value { 284 return newVertexRoot(inst.index, newContext(inst.index), inst.root) 285 } 286 287 // Lookup reports the value at a path starting from the top level struct. The 288 // Exists method of the returned value will report false if the path did not 289 // exist. The Err method reports if any error occurred during evaluation. The 290 // empty path returns the top-level configuration struct. Use LookupDef for definitions or LookupField for 291 // any kind of field. 292 // 293 // Deprecated: use Value.LookupPath 294 func (inst *hiddenInstance) Lookup(path ...string) Value { 295 return inst.value().Lookup(path...) 296 } 297 298 // LookupDef reports the definition with the given name within struct v. The 299 // Exists method of the returned value will report false if the definition did 300 // not exist. The Err method reports if any error occurred during evaluation. 301 // 302 // Deprecated: use Value.LookupPath 303 func (inst *hiddenInstance) LookupDef(path string) Value { 304 return inst.value().LookupDef(path) 305 } 306 307 // LookupField reports a Field at a path starting from v, or an error if the 308 // path is not. The empty path returns v itself. 309 // 310 // It cannot look up hidden or unexported fields. 311 // 312 // Deprecated: this API does not work with new-style definitions. Use 313 // FieldByName defined on inst.Value(). 314 // 315 // Deprecated: use Value.LookupPath 316 func (inst *hiddenInstance) LookupField(path ...string) (f FieldInfo, err error) { 317 v := inst.value() 318 for _, k := range path { 319 s, err := v.Struct() 320 if err != nil { 321 return f, err 322 } 323 324 f, err = s.FieldByName(k, true) 325 if err != nil { 326 return f, err 327 } 328 if f.IsHidden { 329 return f, errNotFound 330 } 331 v = f.Value 332 } 333 return f, err 334 } 335 336 // Fill creates a new instance with the values of the old instance unified with 337 // the given value. It is not possible to update the emit value. 338 // 339 // Values may be any Go value that can be converted to CUE, an ast.Expr or 340 // a Value. In the latter case, it will panic if the Value is not from the same 341 // Runtime. 342 // 343 // Deprecated: use Value.FillPath() 344 func (inst *hiddenInstance) Fill(x interface{}, path ...string) (*Instance, error) { 345 v := inst.Value().Fill(x, path...) 346 347 inst = addInst(inst.index, &Instance{ 348 root: v.v, 349 inst: nil, 350 351 // Omit ImportPath to indicate this is not an importable package. 352 Dir: inst.Dir, 353 PkgName: inst.PkgName, 354 Incomplete: inst.Incomplete, 355 }) 356 return inst, nil 357 }