blob: 70d43385acae1830ccdb22531fa52177110e78fa [file] [log] [blame]
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +01001// Copyright 2019 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
15package jsonschema
16
17// TODO:
18// - replace converter from YAML to CUE to CUE (schema) to CUE.
19// - define OpenAPI definitions als CUE.
20
21import (
22 "fmt"
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +020023 "math/bits"
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +010024 "sort"
25 "strings"
26
27 "cuelang.org/go/cue"
28 "cuelang.org/go/cue/ast"
29 "cuelang.org/go/cue/errors"
30 "cuelang.org/go/cue/token"
31 "cuelang.org/go/internal"
32)
33
Marcel van Lohuizen435989a2020-05-06 18:43:58 +020034// rootDefs defines the top-level name of the map of definitions that do not
35// have a valid identifier name.
36//
37// TODO: find something more principled, like allowing #."a-b" or `#a-b`.
38const rootDefs = "#def"
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +010039
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +010040// A decoder converts JSON schema to CUE.
41type decoder struct {
Marcel van Lohuizen47d98702020-01-17 21:51:39 +010042 cfg *Config
43
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +010044 errs errors.Error
45 imports map[string]*ast.Ident
46
47 definitions []ast.Decl
48}
49
50// addImport registers
51func (d *decoder) addImport(pkg string) *ast.Ident {
52 ident, ok := d.imports[pkg]
53 if !ok {
54 ident = ast.NewIdent(pkg)
55 d.imports[pkg] = ident
56 }
57 return ident
58}
59
Marcel van Lohuizen671b9562020-03-10 12:42:45 +010060func (d *decoder) decode(v cue.Value) *ast.File {
61 f := &ast.File{}
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +010062
Marcel van Lohuizenbd98b132020-03-05 15:38:21 +010063 if pkgName := d.cfg.PkgName; pkgName != "" {
64 pkg := &ast.Package{Name: ast.NewIdent(pkgName)}
Marcel van Lohuizen671b9562020-03-10 12:42:45 +010065 f.Decls = append(f.Decls, pkg)
66 }
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +010067
Marcel van Lohuizen671b9562020-03-10 12:42:45 +010068 var a []ast.Decl
69
70 if d.cfg.Root == "" {
Marcel van Lohuizen435989a2020-05-06 18:43:58 +020071 a = append(a, d.schema(nil, v)...)
Marcel van Lohuizen671b9562020-03-10 12:42:45 +010072 } else {
73 ref := d.parseRef(token.NoPos, d.cfg.Root)
74 if ref == nil {
75 return f
76 }
77 i, err := v.Lookup(ref...).Fields()
78 if err != nil {
79 d.errs = errors.Append(d.errs, errors.Promote(err, ""))
80 return nil
81 }
82 for i.Next() {
83 ref := append(ref, i.Label())
Marcel van Lohuizen435989a2020-05-06 18:43:58 +020084 lab := d.mapRef(i.Value().Pos(), "", ref)
85 if len(lab) == 0 {
Marcel van Lohuizen671b9562020-03-10 12:42:45 +010086 return nil
87 }
Marcel van Lohuizen435989a2020-05-06 18:43:58 +020088 decls := d.schema(lab, i.Value())
Marcel van Lohuizen671b9562020-03-10 12:42:45 +010089 a = append(a, decls...)
90 }
Marcel van Lohuizenbd98b132020-03-05 15:38:21 +010091 }
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +010092
93 var imports []string
94 for k := range d.imports {
95 imports = append(imports, k)
96 }
97 sort.Strings(imports)
98
99 if len(imports) > 0 {
100 x := &ast.ImportDecl{}
101 for _, p := range imports {
102 x.Specs = append(x.Specs, ast.NewImport(nil, p))
103 }
Marcel van Lohuizen671b9562020-03-10 12:42:45 +0100104 f.Decls = append(f.Decls, x)
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100105 }
106
Marcel van Lohuizen671b9562020-03-10 12:42:45 +0100107 f.Decls = append(f.Decls, a...)
108 f.Decls = append(f.Decls, d.definitions...)
109
110 return f
111}
112
Marcel van Lohuizen435989a2020-05-06 18:43:58 +0200113func (d *decoder) schema(ref []ast.Label, v cue.Value) (a []ast.Decl) {
Marcel van Lohuizen671b9562020-03-10 12:42:45 +0100114 root := state{decoder: d}
115
Marcel van Lohuizen435989a2020-05-06 18:43:58 +0200116 var name ast.Label
Marcel van Lohuizen671b9562020-03-10 12:42:45 +0100117 inner := len(ref) - 1
Marcel van Lohuizen435989a2020-05-06 18:43:58 +0200118
119 if inner >= 0 {
120 name = ref[inner]
121 root.isSchema = true
122 }
Marcel van Lohuizen671b9562020-03-10 12:42:45 +0100123
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200124 expr, state := root.schemaState(v, allTypes, false)
Marcel van Lohuizen671b9562020-03-10 12:42:45 +0100125
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100126 tags := []string{}
127 if state.jsonschema != "" {
128 tags = append(tags, fmt.Sprintf("schema=%q", state.jsonschema))
129 }
130 if state.id != "" {
131 tags = append(tags, fmt.Sprintf("id=%q", state.id))
132 }
Marcel van Lohuizen435989a2020-05-06 18:43:58 +0200133
134 if name == nil {
135 if len(tags) > 0 {
136 body := strings.Join(tags, ",")
137 a = append(a, &ast.Attribute{
138 Text: fmt.Sprintf("@jsonschema(%s)", body)})
139 }
140
141 if state.deprecated {
142 a = append(a, &ast.Attribute{Text: "@deprecated()"})
143 }
144 } else {
145 if len(tags) > 0 {
146 a = append(a, addTag(name, "jsonschema", strings.Join(tags, ",")))
147 }
148
149 if state.deprecated {
150 a = append(a, addTag(name, "deprecated", ""))
151 }
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100152 }
153
Marcel van Lohuizen435989a2020-05-06 18:43:58 +0200154 if name != nil {
155 f := &ast.Field{
156 Label: name,
157 Value: expr,
158 }
159
160 a = append(a, f)
161 } else if st, ok := expr.(*ast.StructLit); ok {
162 a = append(a, st.Elts...)
163 } else {
164 a = append(a, &ast.EmbedDecl{Expr: expr})
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100165 }
166
Marcel van Lohuizen671b9562020-03-10 12:42:45 +0100167 state.doc(a[0])
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100168
Marcel van Lohuizen671b9562020-03-10 12:42:45 +0100169 for i := inner - 1; i >= 0; i-- {
170 a = []ast.Decl{&ast.Field{
Marcel van Lohuizen435989a2020-05-06 18:43:58 +0200171 Label: ref[i],
Marcel van Lohuizen671b9562020-03-10 12:42:45 +0100172 Value: &ast.StructLit{Elts: a},
173 }}
Marcel van Lohuizen435989a2020-05-06 18:43:58 +0200174 expr = ast.NewStruct(ref[i], expr)
Marcel van Lohuizen671b9562020-03-10 12:42:45 +0100175 }
176
177 return a
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100178}
179
180func (d *decoder) errf(n cue.Value, format string, args ...interface{}) ast.Expr {
Marcel van Lohuizen671b9562020-03-10 12:42:45 +0100181 d.warnf(n.Pos(), format, args...)
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100182 return &ast.BadExpr{From: n.Pos()}
183}
184
Marcel van Lohuizen671b9562020-03-10 12:42:45 +0100185func (d *decoder) warnf(p token.Pos, format string, args ...interface{}) {
186 d.addErr(errors.Newf(p, format, args...))
187}
188
189func (d *decoder) addErr(err errors.Error) {
190 d.errs = errors.Append(d.errs, err)
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100191}
192
193func (d *decoder) number(n cue.Value) ast.Expr {
Marcel van Lohuizenf4649b22020-02-28 16:50:45 +0100194 return n.Syntax(cue.Final()).(ast.Expr)
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100195}
196
197func (d *decoder) uint(n cue.Value) ast.Expr {
198 _, err := n.Uint64()
199 if err != nil {
200 d.errf(n, "invalid uint")
201 }
Marcel van Lohuizenf4649b22020-02-28 16:50:45 +0100202 return n.Syntax(cue.Final()).(ast.Expr)
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100203}
204
205func (d *decoder) bool(n cue.Value) ast.Expr {
Marcel van Lohuizenf4649b22020-02-28 16:50:45 +0100206 return n.Syntax(cue.Final()).(ast.Expr)
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100207}
208
209func (d *decoder) boolValue(n cue.Value) bool {
210 x, err := n.Bool()
211 if err != nil {
212 d.errf(n, "invalid bool")
213 }
214 return x
215}
216
217func (d *decoder) string(n cue.Value) ast.Expr {
Marcel van Lohuizenf4649b22020-02-28 16:50:45 +0100218 return n.Syntax(cue.Final()).(ast.Expr)
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100219}
220
221func (d *decoder) strValue(n cue.Value) (s string, ok bool) {
222 s, err := n.String()
223 if err != nil {
224 d.errf(n, "invalid string")
225 return "", false
226 }
227 return s, true
228}
229
230// const draftCutoff = 5
231
232type state struct {
233 *decoder
234
Marcel van Lohuizen435989a2020-05-06 18:43:58 +0200235 isSchema bool // for omitting ellipsis in an ast.File
236
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200237 parent *state
238
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100239 path []string
240
241 pos cue.Value
242
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100243 typeOptional bool
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200244 usedTypes cue.Kind
245 allowedTypes cue.Kind
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100246
247 default_ ast.Expr
248 examples []ast.Expr
249 title string
250 description string
251 deprecated bool
252 jsonschema string
253 id string
254
255 conjuncts []ast.Expr
256
257 obj *ast.StructLit
258 closeStruct bool
259 patterns []ast.Expr
260
261 list *ast.ListLit
262}
263
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200264func (s *state) hasConstraints() bool {
265 return len(s.conjuncts) > 0 ||
266 len(s.patterns) > 0 ||
267 s.title != "" ||
268 s.description != "" ||
Marcel van Lohuizenb99d3642020-04-14 16:26:33 +0200269 s.obj != nil
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200270}
271
272const allTypes = cue.NullKind | cue.BoolKind | cue.NumberKind | cue.IntKind |
273 cue.StringKind | cue.ListKind | cue.StructKind
274
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100275// finalize constructs a CUE type from the collected constraints.
276func (s *state) finalize() (e ast.Expr) {
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100277 conjuncts := []ast.Expr{}
278 disjuncts := []ast.Expr{}
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200279
280 add := func(e ast.Expr) {
281 disjuncts = append(disjuncts, e) // TODO: use setPos
282 }
283
284 types := s.allowedTypes &^ s.usedTypes
285 if types == allTypes {
286 add(ast.NewIdent("_"))
287 types = 0
288 }
289 if types&cue.FloatKind != 0 {
290 add(ast.NewIdent("number"))
291 types &^= cue.IntKind
292 }
293 for types != 0 {
294 k := cue.Kind(1 << uint(bits.TrailingZeros(uint(types))))
295 types &^= k
296
297 switch k {
298 case cue.NullKind:
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100299 // TODO: handle OpenAPI restrictions.
300 add(ast.NewIdent("null"))
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200301 case cue.BoolKind:
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100302 add(ast.NewIdent("bool"))
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200303 case cue.StringKind:
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100304 add(ast.NewIdent("string"))
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200305 case cue.IntKind:
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100306 add(ast.NewIdent("int"))
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200307 case cue.ListKind:
308 add(ast.NewList(&ast.Ellipsis{}))
309 case cue.StructKind:
Marcel van Lohuizenb236d4a2020-02-07 13:14:49 +0100310 add(ast.NewStruct(&ast.Ellipsis{}))
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100311 }
312 }
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100313
314 conjuncts = append(conjuncts, s.conjuncts...)
315
316 if s.obj != nil {
Marcel van Lohuizen435989a2020-05-06 18:43:58 +0200317 // TODO: may need to explicitly close.
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100318 if !s.closeStruct {
319 s.obj.Elts = append(s.obj.Elts, &ast.Ellipsis{})
320 }
321 conjuncts = append(conjuncts, s.obj)
322 }
323
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200324 if len(conjuncts) > 0 {
325 disjuncts = append(disjuncts,
326 ast.NewBinExpr(token.AND, conjuncts...))
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100327 }
328
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200329 if len(disjuncts) == 0 {
330 e = &ast.BottomLit{}
331 } else {
332 e = ast.NewBinExpr(token.OR, disjuncts...)
333 }
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100334
335 if s.default_ != nil {
336 // check conditions where default can be skipped.
337 switch x := s.default_.(type) {
338 case *ast.ListLit:
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200339 if s.usedTypes == cue.ListKind && len(x.Elts) == 0 {
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100340 return e
341 }
342 }
343 e = ast.NewBinExpr(token.OR, e, &ast.UnaryExpr{Op: token.MUL, X: s.default_})
344 }
345 return e
346}
347
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200348func isAny(s ast.Expr) bool {
349 i, ok := s.(*ast.Ident)
350 return ok && i.Name == "_"
351}
352
Marcel van Lohuizenbd98b132020-03-05 15:38:21 +0100353func (s *state) comment() *ast.CommentGroup {
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100354 // Create documentation.
355 doc := strings.TrimSpace(s.title)
356 if s.description != "" {
357 if doc != "" {
358 doc += "\n\n"
359 }
360 doc += s.description
361 doc = strings.TrimSpace(doc)
362 }
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100363 // TODO: add examples as well?
Marcel van Lohuizenbd98b132020-03-05 15:38:21 +0100364 if doc == "" {
365 return nil
366 }
367 return internal.NewComment(true, doc)
368}
369
370func (s *state) doc(n ast.Node) {
371 doc := s.comment()
372 if doc != nil {
373 ast.SetComments(n, []*ast.CommentGroup{doc})
374 }
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100375}
376
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200377func (s *state) addConjunct(e ast.Expr) {
378 if !isAny(e) {
379 s.conjuncts = append(s.conjuncts, e)
380 }
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100381}
382
383func (s *state) schema(n cue.Value) ast.Expr {
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200384 expr, _ := s.schemaState(n, allTypes, false)
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100385 // TODO: report unused doc.
386 return expr
387}
388
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200389// schemaState is a low-level API for schema. isLogical specifies whether the
390// caller is a logical operator like anyOf, allOf, oneOf, or not.
391func (s *state) schemaState(n cue.Value, types cue.Kind, isLogical bool) (ast.Expr, *state) {
392 state := &state{
Marcel van Lohuizen435989a2020-05-06 18:43:58 +0200393 isSchema: s.isSchema,
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200394 decoder: s.decoder,
395 allowedTypes: types,
396 path: s.path,
397 pos: n,
398 }
399 if isLogical {
400 state.parent = s
401 }
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100402
403 if n.Kind() != cue.StructKind {
404 return s.errf(n, "schema expects mapping node, found %s", n.Kind()), state
405 }
406
407 // do multiple passes over the constraints to ensure they are done in order.
408 for pass := 0; pass < 3; pass++ {
409 state.processMap(n, func(key string, value cue.Value) {
410 // Convert each constraint into a either a value or a functor.
411 c := constraintMap[key]
412 if c == nil {
Marcel van Lohuizen0059b2b2020-04-14 15:31:11 +0200413 if pass == 0 && s.cfg.Strict {
414 // TODO: value is not the correct possition, albeit close. Fix this.
415 s.warnf(value.Pos(), "unsupported constraint %q", key)
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100416 }
417 return
418 }
419 if c.phase == pass {
420 c.fn(value, state)
421 }
422 })
423 }
424
425 return state.finalize(), state
426}
427
428func (s *state) value(n cue.Value) ast.Expr {
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200429 k := n.Kind()
430 s.usedTypes |= k
431 s.allowedTypes &= k
432 switch k {
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100433 case cue.ListKind:
434 a := []ast.Expr{}
435 for i, _ := n.List(); i.Next(); {
436 a = append(a, s.value(i.Value()))
437 }
438 return setPos(ast.NewList(a...), n)
439
440 case cue.StructKind:
441 a := []ast.Decl{}
442 s.processMap(n, func(key string, n cue.Value) {
443 a = append(a, &ast.Field{
444 Label: ast.NewString(key),
445 Value: s.value(n),
446 })
447 })
Marcel van Lohuizen435989a2020-05-06 18:43:58 +0200448 // TODO: only open when s.isSchema?
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100449 a = append(a, &ast.Ellipsis{})
450 return setPos(&ast.StructLit{Elts: a}, n)
451
452 default:
453 if !n.IsConcrete() {
Marcel van Lohuizen1370f0a2020-04-15 11:27:13 +0200454 s.errf(n, "invalid non-concrete value")
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100455 }
Marcel van Lohuizenf4649b22020-02-28 16:50:45 +0100456 return n.Syntax(cue.Final()).(ast.Expr)
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100457 }
458}
459
460// processMap processes a yaml node, expanding merges.
461//
462// TODO: in some cases we can translate merges into CUE embeddings.
463// This may also prevent exponential blow-up (as may happen when
464// converting YAML to JSON).
465func (s *state) processMap(n cue.Value, f func(key string, n cue.Value)) {
466 saved := s.path
467 defer func() { s.path = saved }()
468
469 // TODO: intercept references to allow for optimized performance.
470 for i, _ := n.Fields(); i.Next(); {
471 key := i.Label()
472 s.path = append(saved, key)
473 f(key, i.Value())
474 }
475}
476
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200477func (s *state) listItems(name string, n cue.Value, allowEmpty bool) (a []cue.Value) {
478 if n.Kind() != cue.ListKind {
479 s.errf(n, `value of %q must be an array, found %v`, name, n.Kind())
480 }
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100481 for i, _ := n.List(); i.Next(); {
482 a = append(a, i.Value())
483 }
Marcel van Lohuizen78e21c12020-04-14 15:24:34 +0200484 if !allowEmpty && len(a) == 0 {
485 s.errf(n, `array for %q must be non-empty`, name)
486 }
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100487 return a
488}
489
490// excludeFields returns a CUE expression that can be used to exclude the
491// fields of the given declaration in a label expression. For instance, for
492//
493// { foo: 1, bar: int }
494//
495// it creates
496//
497// "^(foo|bar)$"
498//
499// which can be used in a label expression to define types for all fields but
500// those existing:
501//
502// [!~"^(foo|bar)$"]: string
503//
504func excludeFields(decls []ast.Decl) ast.Expr {
505 var a []string
506 for _, d := range decls {
507 f, ok := d.(*ast.Field)
508 if !ok {
509 continue
510 }
511 str, _, _ := ast.LabelName(f.Label)
512 if str != "" {
513 a = append(a, str)
514 }
515 }
516 re := fmt.Sprintf("^(%s)$", strings.Join(a, "|"))
517 return &ast.UnaryExpr{Op: token.NMAT, X: ast.NewString(re)}
518}
519
Marcel van Lohuizen435989a2020-05-06 18:43:58 +0200520func addTag(field ast.Label, tag, value string) *ast.Field {
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100521 return &ast.Field{
Marcel van Lohuizen435989a2020-05-06 18:43:58 +0200522 Label: field,
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100523 Value: ast.NewIdent("_"),
524 Attrs: []*ast.Attribute{
Daniel Martí066ede62020-02-11 15:07:27 +0000525 {Text: fmt.Sprintf("@%s(%s)", tag, value)},
Marcel van Lohuizen6cb08782020-01-13 18:03:27 +0100526 },
527 }
528}
529
530func setPos(e ast.Expr, v cue.Value) ast.Expr {
531 ast.SetPos(e, v.Pos())
532 return e
533}