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