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