cuelang.org/go@v0.10.1/cue/context.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 "cmp" 19 20 "cuelang.org/go/cue/ast" 21 "cuelang.org/go/cue/ast/astutil" 22 "cuelang.org/go/cue/build" 23 "cuelang.org/go/cue/errors" 24 "cuelang.org/go/cue/token" 25 "cuelang.org/go/internal/core/adt" 26 "cuelang.org/go/internal/core/compile" 27 "cuelang.org/go/internal/core/convert" 28 "cuelang.org/go/internal/core/debug" 29 "cuelang.org/go/internal/core/eval" 30 "cuelang.org/go/internal/core/runtime" 31 ) 32 33 // A Context is used for creating CUE Values. 34 // 35 // A Context keeps track of loaded instances, indices of internal 36 // representations of values, and defines the set of supported builtins. Any 37 // operation that involves two Values should originate from the same Context. 38 // 39 // Use [cuelang.org/go/cue/cuecontext.New] to create a new context. 40 type Context runtime.Runtime 41 42 func (c *Context) runtime() *runtime.Runtime { 43 rt := (*runtime.Runtime)(c) 44 if !rt.IsInitialized() { 45 panic("cue: uninitialized Context: use cuecontext.New instead of zero value") 46 } 47 48 return rt 49 } 50 51 func (c *Context) ctx() *adt.OpContext { 52 return newContext(c.runtime()) 53 } 54 55 // Context reports the Context with which this value was created. 56 func (v Value) Context() *Context { 57 return (*Context)(v.idx) 58 } 59 60 // A BuildOption defines options for the various build-related methods of 61 // Context. 62 type BuildOption func(o *runtime.Config) 63 64 // Scope defines a context in which to resolve unresolved identifiers. 65 // 66 // Only one scope may be given. It panics if more than one scope is given 67 // or if the Context in which scope was created differs from the one where 68 // this option is used. 69 func Scope(scope Value) BuildOption { 70 return func(o *runtime.Config) { 71 if o.Runtime != scope.idx { 72 panic("incompatible runtime") 73 } 74 if o.Scope != nil { 75 panic("more than one scope is given") 76 } 77 o.Scope = valueScope(scope) 78 } 79 } 80 81 // Filename assigns a filename to parsed content. 82 func Filename(filename string) BuildOption { 83 return func(o *runtime.Config) { o.Filename = filename } 84 } 85 86 // ImportPath defines the import path to use for building CUE. The import path 87 // influences the scope in which identifiers occurring in the input CUE are 88 // defined. Passing the empty string is equal to not specifying this option. 89 // 90 // This option is typically not necessary when building using a build.Instance, 91 // but takes precedence otherwise. 92 func ImportPath(path string) BuildOption { 93 return func(o *runtime.Config) { o.ImportPath = path } 94 } 95 96 // InferBuiltins allows unresolved references to bind to builtin packages with a 97 // unique package name. 98 // 99 // This option is intended for evaluating expressions in a context where import 100 // statements cannot be used. It is not recommended to use this for evaluating 101 // CUE files. 102 func InferBuiltins(elide bool) BuildOption { 103 return func(o *runtime.Config) { 104 o.Imports = func(x *ast.Ident) (pkgPath string) { 105 return o.Runtime.BuiltinPackagePath(x.Name) 106 } 107 } 108 } 109 110 func (c *Context) parseOptions(options []BuildOption) (cfg runtime.Config) { 111 cfg.Runtime = (*runtime.Runtime)(c) 112 for _, f := range options { 113 f(&cfg) 114 } 115 return cfg 116 } 117 118 // BuildInstance creates a Value from the given build.Instance. 119 // 120 // The returned Value will represent an error, accessible through Err, if any 121 // error occurred. 122 func (c *Context) BuildInstance(i *build.Instance, options ...BuildOption) Value { 123 cfg := c.parseOptions(options) 124 v, err := c.runtime().Build(&cfg, i) 125 if err != nil { 126 return c.makeError(err) 127 } 128 return c.make(v) 129 } 130 131 func (c *Context) makeError(err errors.Error) Value { 132 b := &adt.Bottom{Err: err} 133 node := &adt.Vertex{BaseValue: b} 134 node.ForceDone() 135 node.AddConjunct(adt.MakeRootConjunct(nil, b)) 136 return c.make(node) 137 } 138 139 // BuildInstances creates a Value for each of the given instances and reports 140 // the combined errors or nil if there were no errors. 141 func (c *Context) BuildInstances(instances []*build.Instance) ([]Value, error) { 142 var errs errors.Error 143 var a []Value 144 for _, b := range instances { 145 v, err := c.runtime().Build(nil, b) 146 if err != nil { 147 errs = errors.Append(errs, err) 148 a = append(a, c.makeError(err)) 149 } else { 150 a = append(a, c.make(v)) 151 } 152 } 153 return a, errs 154 } 155 156 // BuildFile creates a Value from f. 157 // 158 // The returned Value will represent an error, accessible through Err, if any 159 // error occurred. 160 func (c *Context) BuildFile(f *ast.File, options ...BuildOption) Value { 161 cfg := c.parseOptions(options) 162 return c.compile(c.runtime().CompileFile(&cfg, f)) 163 } 164 165 func (c *Context) compile(v *adt.Vertex, p *build.Instance) Value { 166 if p.Err != nil { 167 return c.makeError(p.Err) 168 } 169 return c.make(v) 170 } 171 172 // BuildExpr creates a Value from x. 173 // 174 // The returned Value will represent an error, accessible through Err, if any 175 // error occurred. 176 func (c *Context) BuildExpr(x ast.Expr, options ...BuildOption) Value { 177 r := c.runtime() 178 cfg := c.parseOptions(options) 179 180 ctx := c.ctx() 181 182 // TODO: move to runtime?: it probably does not make sense to treat BuildExpr 183 // and the expression resulting from CompileString differently. 184 astutil.ResolveExpr(x, errFn) 185 186 pkgPath := cmp.Or(cfg.ImportPath, anonymousPkg) 187 188 conjunct, err := compile.Expr(&cfg.Config, r, pkgPath, x) 189 if err != nil { 190 return c.makeError(err) 191 } 192 v := adt.Resolve(ctx, conjunct) 193 194 return c.make(v) 195 } 196 197 func errFn(pos token.Pos, msg string, args ...interface{}) {} 198 199 // resolveExpr binds unresolved expressions to values in the expression or v. 200 func resolveExpr(ctx *adt.OpContext, v Value, x ast.Expr) adt.Value { 201 cfg := &compile.Config{Scope: valueScope(v)} 202 203 astutil.ResolveExpr(x, errFn) 204 205 c, err := compile.Expr(cfg, ctx, anonymousPkg, x) 206 if err != nil { 207 return &adt.Bottom{Err: err} 208 } 209 return adt.Resolve(ctx, c) 210 } 211 212 // anonymousPkg reports a package path that can never resolve to a valid package. 213 const anonymousPkg = "_" 214 215 // CompileString parses and build a Value from the given source string. 216 // 217 // The returned Value will represent an error, accessible through Err, if any 218 // error occurred. 219 func (c *Context) CompileString(src string, options ...BuildOption) Value { 220 cfg := c.parseOptions(options) 221 return c.compile(c.runtime().Compile(&cfg, src)) 222 } 223 224 // CompileBytes parses and build a Value from the given source bytes. 225 // 226 // The returned Value will represent an error, accessible through Err, if any 227 // error occurred. 228 func (c *Context) CompileBytes(b []byte, options ...BuildOption) Value { 229 cfg := c.parseOptions(options) 230 return c.compile(c.runtime().Compile(&cfg, b)) 231 } 232 233 // TODO: fs.FS or custom wrapper? 234 // // CompileFile parses and build a Value from the given source bytes. 235 // // 236 // // The returned Value will represent an error, accessible through Err, if any 237 // // error occurred. 238 // func (c *Context) CompileFile(f fs.File, options ...BuildOption) Value { 239 // b, err := io.ReadAll(f) 240 // if err != nil { 241 // return c.makeError(errors.Promote(err, "parsing file system file")) 242 // } 243 // return c.compile(c.runtime().Compile("", b)) 244 // } 245 246 func (c *Context) make(v *adt.Vertex) Value { 247 opCtx := newContext(c.runtime()) 248 // TODO: this is currently needed to ensure that node is properly recognized 249 // as evaluated. Not dereferencing nodes, however, will have the benefit of 250 // retaining more information. Remove the indirection when the code will be 251 // able to properly handle this. 252 x := newValueRoot(c.runtime(), opCtx, v) 253 adt.AddStats(opCtx) 254 return x 255 } 256 257 // An EncodeOption defines options for the various encoding-related methods of 258 // Context. 259 type EncodeOption func(*encodeOptions) 260 261 type encodeOptions struct { 262 nilIsTop bool 263 } 264 265 func (o *encodeOptions) process(option []EncodeOption) { 266 for _, f := range option { 267 f(o) 268 } 269 } 270 271 // NilIsAny indicates whether a nil value is interpreted as null or _. 272 // 273 // The default is to interpret nil as _. 274 func NilIsAny(isAny bool) EncodeOption { 275 return func(o *encodeOptions) { o.nilIsTop = isAny } 276 } 277 278 // Encode converts a Go value to a CUE value. 279 // 280 // The returned Value will represent an error, accessible through Err, if any 281 // error occurred. 282 // 283 // Encode traverses the value v recursively. If an encountered value implements 284 // the json.Marshaler interface and is not a nil pointer, Encode calls its 285 // MarshalJSON method to produce JSON and convert that to CUE instead. If no 286 // MarshalJSON method is present but the value implements encoding.TextMarshaler 287 // instead, Encode calls its MarshalText method and encodes the result as a 288 // string. 289 // 290 // Otherwise, Encode uses the following type-dependent default encodings: 291 // 292 // Boolean values encode as CUE booleans. 293 // 294 // Floating point, integer, and *big.Int and *big.Float values encode as CUE 295 // numbers. 296 // 297 // String values encode as CUE strings coerced to valid UTF-8, replacing 298 // sequences of invalid bytes with the Unicode replacement rune as per Unicode's 299 // and W3C's recommendation. 300 // 301 // Array and slice values encode as CUE lists, except that []byte encodes as a 302 // bytes value, and a nil slice encodes as the null. 303 // 304 // Struct values encode as CUE structs. Each exported struct field becomes a 305 // member of the object, using the field name as the object key, unless the 306 // field is omitted for one of the reasons given below. 307 // 308 // The encoding of each struct field can be customized by the format string 309 // stored under the "json" key in the struct field's tag. The format string 310 // gives the name of the field, possibly followed by a comma-separated list of 311 // options. The name may be empty in order to specify options without overriding 312 // the default field name. 313 // 314 // The "omitempty" option specifies that the field should be omitted from the 315 // encoding if the field has an empty value, defined as false, 0, a nil pointer, 316 // a nil interface value, and any empty array, slice, map, or string. 317 // 318 // See the documentation for Go's json.Marshal for more details on the field 319 // tags and their meaning. 320 // 321 // Anonymous struct fields are usually encoded as if their inner exported 322 // fields were fields in the outer struct, subject to the usual Go visibility 323 // rules amended as described in the next paragraph. An anonymous struct field 324 // with a name given in its JSON tag is treated as having that name, rather than 325 // being anonymous. An anonymous struct field of interface type is treated the 326 // same as having that type as its name, rather than being anonymous. 327 // 328 // The Go visibility rules for struct fields are amended for when deciding which 329 // field to encode or decode. If there are multiple fields at the same level, 330 // and that level is the least nested (and would therefore be the nesting level 331 // selected by the usual Go rules), the following extra rules apply: 332 // 333 // 1) Of those fields, if any are JSON-tagged, only tagged fields are 334 // considered, even if there are multiple untagged fields that would otherwise 335 // conflict. 336 // 337 // 2) If there is exactly one field (tagged or not according to the first rule), 338 // that is selected. 339 // 340 // 3) Otherwise there are multiple fields, and all are ignored; no error occurs. 341 // 342 // Map values encode as CUE structs. The map's key type must either be a string, 343 // an integer type, or implement encoding.TextMarshaler. The map keys are sorted 344 // and used as CUE struct field names by applying the following rules, subject 345 // to the UTF-8 coercion described for string values above: 346 // 347 // - keys of any string type are used directly 348 // - encoding.TextMarshalers are marshaled 349 // - integer keys are converted to strings 350 // 351 // Pointer values encode as the value pointed to. A nil pointer encodes as the 352 // null CUE value. 353 // 354 // Interface values encode as the value contained in the interface. A nil 355 // interface value encodes as the null CUE value. The NilIsAny EncodingOption 356 // can be used to interpret nil as any (_) instead. 357 // 358 // Channel, complex, and function values cannot be encoded in CUE. Attempting to 359 // encode such a value results in the returned value being an error, accessible 360 // through the Err method. 361 func (c *Context) Encode(x interface{}, option ...EncodeOption) Value { 362 switch v := x.(type) { 363 case adt.Value: 364 return newValueRoot(c.runtime(), c.ctx(), v) 365 } 366 var options encodeOptions 367 options.process(option) 368 369 ctx := c.ctx() 370 // TODO: is true the right default? 371 expr := convert.GoValueToValue(ctx, x, options.nilIsTop) 372 n := &adt.Vertex{} 373 n.AddConjunct(adt.MakeRootConjunct(nil, expr)) 374 n.Finalize(ctx) 375 return c.make(n) 376 } 377 378 // Encode converts a Go type to a CUE value. 379 // 380 // The returned Value will represent an error, accessible through Err, if any 381 // error occurred. 382 func (c *Context) EncodeType(x interface{}, option ...EncodeOption) Value { 383 switch v := x.(type) { 384 case *adt.Vertex: 385 return c.make(v) 386 } 387 388 ctx := c.ctx() 389 expr, err := convert.GoTypeToExpr(ctx, x) 390 if err != nil { 391 return c.makeError(err) 392 } 393 n := &adt.Vertex{} 394 n.AddConjunct(adt.MakeRootConjunct(nil, expr)) 395 n.Finalize(ctx) 396 return c.make(n) 397 } 398 399 // NewList creates a Value that is a list of the given values. 400 // 401 // All Values must be created by c. 402 func (c *Context) NewList(v ...Value) Value { 403 a := make([]adt.Value, len(v)) 404 for i, x := range v { 405 if x.idx != (*runtime.Runtime)(c) { 406 panic("values must be from same Context") 407 } 408 a[i] = x.v 409 } 410 return c.make(c.ctx().NewList(a...)) 411 } 412 413 // TODO: 414 415 // func (c *Context) NewExpr(op Op, v ...Value) Value { 416 // return Value{} 417 // } 418 419 // func (c *Context) NewValue(v ...ValueElem) Value { 420 // return Value{} 421 // } 422 423 // func NewAttr(key string, values ...string) *Attribute { 424 // return &Attribute{} 425 // } 426 427 // // Clear unloads all previously-loaded imports. 428 // func (c *Context) Clear() { 429 // } 430 431 // // Values created up to the point of the Fork will be valid in both runtimes. 432 // func (c *Context) Fork() *Context { 433 // return nil 434 // } 435 436 // type ValueElem interface { 437 // } 438 439 // func NewField(sel Selector, value Value, attrs ...Attribute) ValueElem { 440 // return nil 441 // } 442 443 // func NewDocComment(text string) ValueElem { 444 // return nil 445 // } 446 447 // newContext returns a new evaluation context. 448 func newContext(idx *runtime.Runtime) *adt.OpContext { 449 if idx == nil { 450 return nil 451 } 452 return eval.NewContext(idx, nil) 453 } 454 455 func debugStr(ctx *adt.OpContext, v adt.Node) string { 456 return debug.NodeString(ctx, v, nil) 457 } 458 459 func str(c *adt.OpContext, v adt.Node) string { 460 return debugStr(c, v) 461 } 462 463 // eval returns the evaluated value. This may not be the vertex. 464 // 465 // Deprecated: use ctx.value 466 func (v Value) eval(ctx *adt.OpContext) adt.Value { 467 if v.v == nil { 468 panic("undefined value") 469 } 470 x := manifest(ctx, v.v) 471 return x.Value() 472 } 473 474 // TODO: change from Vertex to Vertex. 475 func manifest(ctx *adt.OpContext, v *adt.Vertex) *adt.Vertex { 476 v.Finalize(ctx) 477 return v 478 }