blob: 7f00b4edef503d2b4151a24b042e4cca70753871 [file] [log] [blame]
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +01001// 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
15package cue
16
17import (
18 "fmt"
Marcel van Lohuizen369e4232019-02-15 10:59:29 +040019 "strings"
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010020
21 "cuelang.org/go/cue/ast"
22 "cuelang.org/go/cue/build"
Marcel van Lohuizen6ceb6012019-02-18 18:30:38 +010023 "cuelang.org/go/cue/literal"
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010024 "cuelang.org/go/cue/token"
Marcel van Lohuizene9fd2142019-04-12 15:46:31 +020025 "cuelang.org/go/internal"
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010026)
27
28// insertFile inserts the given file at the root of the instance.
29//
30// The contents will be merged (unified) with any pre-existing value. In this
31// case an error may be reported, but only if the merge failed at the top-level.
32// Other errors will be recorded at the respective values in the tree.
33//
34// There should be no unresolved identifiers in file, meaning the Node field
35// of all identifiers should be set to a non-nil value.
36func (inst *Instance) insertFile(f *ast.File) error {
37 // TODO: insert by converting to value first so that the trim command can
38 // also remove top-level fields.
39 // First process single file.
40 v := newVisitor(inst.index, inst.inst, inst.rootStruct, inst.scope)
41 v.astState.astMap[f] = inst.rootStruct
42 result := v.walk(f)
43 if isBottom(result) {
44 return result.(*bottom)
45 }
46
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010047 return nil
48}
49
50type astVisitor struct {
51 *astState
Marcel van Lohuizen66db9202018-12-17 19:02:08 +010052 object *structLit
Marcel van Lohuizen079451a2019-05-15 14:51:11 +020053 // For single line fields, the doc comment is applied to the inner-most
54 // field value.
55 //
56 // // This comment is for bar.
57 // foo bar: value
58 //
59 doc *docNode
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +010060
61 inSelector int
62}
63
64func (v *astVisitor) ctx() *context {
65 return v.astState.ctx
66}
67
68type astState struct {
69 ctx *context
70 *index
71 inst *build.Instance
72
73 litParser *litParser
74 resolveRoot *structLit
75
76 // make unique per level to avoid reuse of structs being an issue.
77 astMap map[ast.Node]scope
78}
79
80func (s *astState) mapScope(n ast.Node) (m scope) {
81 if m = s.astMap[n]; m == nil {
82 m = newStruct(newNode(n))
83 s.astMap[n] = m
84 }
85 return m
86}
87
88func (s *astState) setScope(n ast.Node, v scope) {
89 if m, ok := s.astMap[n]; ok && m != v {
90 panic("already defined")
91 }
92 s.astMap[n] = v
93}
94
95func newVisitor(idx *index, inst *build.Instance, obj, resolveRoot *structLit) *astVisitor {
96 ctx := idx.newContext()
Marcel van Lohuizend4847d92019-02-18 23:27:34 +010097 return newVisitorCtx(ctx, inst, obj, resolveRoot)
98}
99
100func newVisitorCtx(ctx *context, inst *build.Instance, obj, resolveRoot *structLit) *astVisitor {
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100101 v := &astVisitor{
102 object: obj,
103 }
104 v.astState = &astState{
105 ctx: ctx,
106 index: ctx.index,
107 inst: inst,
108 litParser: &litParser{ctx: ctx},
109 resolveRoot: resolveRoot,
110 astMap: map[ast.Node]scope{},
111 }
112 return v
113}
114
115func (v *astVisitor) error(n ast.Node, args ...interface{}) value {
116 return v.mkErr(newNode(n), args...)
117}
118
119func (v *astVisitor) resolve(n *ast.Ident) value {
120 ctx := v.ctx()
121 label := v.label(n.Name, true)
122 if r := v.resolveRoot; r != nil {
Marcel van Lohuizen0e2bcd52019-04-03 22:33:14 +0200123 for _, a := range r.arcs {
124 if a.feature == label {
125 return &selectorExpr{newExpr(n),
126 &nodeRef{baseValue: newExpr(n), node: r}, label}
127 }
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100128 }
129 if v.inSelector > 0 {
130 if p := getBuiltinShorthandPkg(ctx, n.Name); p != nil {
131 return &nodeRef{baseValue: newExpr(n), node: p}
132 }
133 }
134 }
135 return nil
136}
137
138func (v *astVisitor) loadImport(imp *ast.ImportSpec) evaluated {
139 ctx := v.ctx()
Marcel van Lohuizen6ceb6012019-02-18 18:30:38 +0100140 path, err := literal.Unquote(imp.Path.Value)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100141 if err != nil {
142 return ctx.mkErr(newNode(imp), "illformed import spec")
143 }
Marcel van Lohuizen0e2bcd52019-04-03 22:33:14 +0200144 // TODO: allow builtin *and* imported package. The result is a unified
145 // struct.
Marcel van Lohuizen8bc02e52019-04-01 13:14:07 +0200146 if p := getBuiltinPkg(ctx, path); p != nil {
147 return p
148 }
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100149 bimp := v.inst.LookupImport(path)
150 if bimp == nil {
151 return ctx.mkErr(newNode(imp), "package %q not found", path)
152 }
153 impInst := v.index.loadInstance(bimp)
154 return impInst.rootValue.evalPartial(ctx)
155}
156
157// We probably don't need to call Walk.s
158func (v *astVisitor) walk(astNode ast.Node) (value value) {
159 switch n := astNode.(type) {
160 case *ast.File:
161 obj := v.object
162 v1 := &astVisitor{
163 astState: v.astState,
164 object: obj,
165 }
166 for _, e := range n.Decls {
167 switch x := e.(type) {
168 case *ast.EmitDecl:
169 if v1.object.emit == nil {
170 v1.object.emit = v1.walk(x.Expr)
171 } else {
172 v1.object.emit = mkBin(v.ctx(), token.NoPos, opUnify, v1.object.emit, v1.walk(x.Expr))
173 }
174 default:
175 v1.walk(e)
176 }
177 }
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100178 value = obj
179
180 case *ast.ImportDecl:
181 for _, s := range n.Specs {
182 v.walk(s)
183 }
184
185 case *ast.ImportSpec:
186 val := v.loadImport(n)
187 if !isBottom(val) {
188 v.setScope(n, val.(*structLit))
189 }
190
191 case *ast.StructLit:
192 obj := v.mapScope(n).(*structLit)
193 v1 := &astVisitor{
194 astState: v.astState,
195 object: obj,
196 }
Marcel van Lohuizen079451a2019-05-15 14:51:11 +0200197 passDoc := len(n.Elts) == 1 && !n.Lbrace.IsValid() && v.doc != nil
198 if passDoc {
199 v1.doc = v.doc
200 }
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100201 for _, e := range n.Elts {
202 switch x := e.(type) {
203 case *ast.EmitDecl:
204 // Only allowed at top-level.
205 v1.error(x, "emitting values is only allowed at top level")
206 case *ast.Field, *ast.Alias:
207 v1.walk(e)
208 case *ast.ComprehensionDecl:
209 v1.walk(x)
210 }
211 }
Marcel van Lohuizen079451a2019-05-15 14:51:11 +0200212 if passDoc {
213 v.doc = v1.doc // signal usage of document back to parent.
214 }
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100215 value = obj
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100216
217 case *ast.ComprehensionDecl:
218 yielder := &yield{baseValue: newExpr(n.Field.Value)}
Marcel van Lohuizen66db9202018-12-17 19:02:08 +0100219 fc := &fieldComprehension{
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100220 baseValue: newDecl(n),
221 clauses: wrapClauses(v, yielder, n.Clauses),
222 }
223 field := n.Field
224 switch x := field.Label.(type) {
225 case *ast.Interpolation:
226 yielder.key = v.walk(x)
227 yielder.value = v.walk(field.Value)
228
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100229 case *ast.TemplateLabel:
230 f := v.label(x.Ident.Name, true)
231
232 sig := &params{}
233 sig.add(f, &basicType{newNode(field.Label), stringKind})
234 template := &lambdaExpr{newExpr(field.Value), sig, nil}
235
236 v.setScope(field, template)
237 template.value = v.walk(field.Value)
238 yielder.value = template
Marcel van Lohuizen66db9202018-12-17 19:02:08 +0100239 fc.isTemplate = true
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100240
241 case *ast.BasicLit, *ast.Ident:
242 name, ok := ast.LabelName(x)
243 if !ok {
244 return v.error(x, "invalid field name: %v", x)
245 }
Marcel van Lohuizenf23fbff2018-12-20 12:23:16 +0100246
247 // TODO: if the clauses do not contain a guard, we know that this
248 // field will always be added and we can move the comprehension one
249 // level down. This, in turn, has the advantage that it is more
250 // likely that the cross-reference limitation for field
251 // comprehensions is not violated. To ensure compatibility between
252 // implementations, though, we should relax the spec as well.
253 // The cross-reference rule is simple and this relaxation seems a
254 // bit more complex.
255
256 // TODO: for now we can also consider making this an error if
257 // the list of clauses does not contain if and make a suggestion
258 // to rewrite it.
259
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100260 if name != "" {
261 yielder.key = &stringLit{newNode(x), name}
262 yielder.value = v.walk(field.Value)
263 }
264
265 default:
266 panic("cue: unknown label type")
267 }
268 // yielder.key = v.walk(n.Field.Label)
269 // yielder.value = v.walk(n.Field.Value)
Marcel van Lohuizen66db9202018-12-17 19:02:08 +0100270 v.object.comprehensions = append(v.object.comprehensions, fc)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100271
272 case *ast.Field:
Marcel van Lohuizen08a0ef22019-03-28 09:12:19 +0100273 opt := n.Optional != token.NoPos
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100274 switch x := n.Label.(type) {
275 case *ast.Interpolation:
276 yielder := &yield{baseValue: newNode(x)}
Marcel van Lohuizen66db9202018-12-17 19:02:08 +0100277 fc := &fieldComprehension{
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100278 baseValue: newDecl(n),
279 clauses: yielder,
280 }
281 yielder.key = v.walk(x)
282 yielder.value = v.walk(n.Value)
Marcel van Lohuizen08a0ef22019-03-28 09:12:19 +0100283 yielder.opt = opt
Marcel van Lohuizen66db9202018-12-17 19:02:08 +0100284 v.object.comprehensions = append(v.object.comprehensions, fc)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100285
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100286 case *ast.TemplateLabel:
287 f := v.label(x.Ident.Name, true)
288
289 sig := &params{}
290 sig.add(f, &basicType{newNode(n.Label), stringKind})
Marcel van Lohuizen079451a2019-05-15 14:51:11 +0200291 template := &lambdaExpr{newNode(n), sig, nil}
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100292
293 v.setScope(n, template)
294 template.value = v.walk(n.Value)
295
296 if v.object.template == nil {
297 v.object.template = template
298 } else {
299 v.object.template = mkBin(v.ctx(), token.NoPos, opUnify, v.object.template, template)
300 }
301
302 case *ast.BasicLit, *ast.Ident:
Marcel van Lohuizene9fd2142019-04-12 15:46:31 +0200303 if internal.DropOptional && opt {
304 break
305 }
Marcel van Lohuizenb9b62d32019-03-14 23:50:15 +0100306 attrs, err := createAttrs(v.ctx(), newNode(n), n.Attrs)
307 if err != nil {
308 return err
309 }
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100310 f, ok := v.nodeLabel(x)
311 if !ok {
312 return v.error(n.Label, "invalid field name: %v", n.Label)
313 }
314 if f != 0 {
Marcel van Lohuizen079451a2019-05-15 14:51:11 +0200315 var leftOverDoc *docNode
316 for _, c := range n.Comments() {
317 if c.Position == 0 {
318 leftOverDoc = v.doc
319 v.doc = &docNode{n: n}
320 break
321 }
322 }
323 val := v.walk(n.Value)
324 v.object.insertValue(v.ctx(), f, opt, val, attrs, v.doc)
325 v.doc = leftOverDoc
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100326 }
327
328 default:
329 panic("cue: unknown label type")
330 }
331
332 case *ast.Alias:
333 // parsed verbatim at reference.
334
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100335 case *ast.ListComprehension:
336 yielder := &yield{baseValue: newExpr(n.Expr)}
337 lc := &listComprehension{
338 newExpr(n),
339 wrapClauses(v, yielder, n.Clauses),
340 }
341 // we don't support key for lists (yet?)
342 yielder.value = v.walk(n.Expr)
343 return lc
344
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100345 // Expressions
346 case *ast.Ident:
347 if n.Node == nil {
348 if value = v.resolve(n); value != nil {
349 break
350 }
351
352 switch n.Name {
353 case "_":
354 return &top{newExpr(n)}
355 case "string":
356 return &basicType{newExpr(n), stringKind}
357 case "bytes":
358 return &basicType{newExpr(n), bytesKind}
359 case "bool":
360 return &basicType{newExpr(n), boolKind}
361 case "int":
362 return &basicType{newExpr(n), intKind}
363 case "float":
364 return &basicType{newExpr(n), floatKind}
365 case "number":
366 return &basicType{newExpr(n), numKind}
367 case "duration":
368 return &basicType{newExpr(n), durationKind}
369
370 case "len":
371 return lenBuiltin
Marcel van Lohuizena460fe82019-04-26 10:20:51 +0200372 case "and":
373 return andBuiltin
374 case "or":
375 return orBuiltin
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100376 }
377 if r, ok := predefinedRanges[n.Name]; ok {
378 return r
379 }
380
381 value = v.error(n, "reference %q not found", n.Name)
382 break
383 }
384
385 if a, ok := n.Node.(*ast.Alias); ok {
386 value = v.walk(a.Expr)
387 break
388 }
389
390 label := v.label(n.Name, true)
391 if n.Scope != nil {
392 n2 := v.mapScope(n.Scope)
393 value = &nodeRef{baseValue: newExpr(n), node: n2}
394 value = &selectorExpr{newExpr(n), value, label}
395 } else {
396 n2 := v.mapScope(n.Node)
397 value = &nodeRef{baseValue: newExpr(n), node: n2}
398 }
399
400 case *ast.BottomLit:
401 value = v.error(n, "from source")
402
403 case *ast.BadDecl:
404 // nothing to do
405
406 case *ast.BadExpr:
407 value = v.error(n, "invalid expression")
408
409 case *ast.BasicLit:
410 value = v.litParser.parse(n)
411
412 case *ast.Interpolation:
413 if len(n.Elts) == 0 {
414 return v.error(n, "invalid interpolation")
415 }
416 first, ok1 := n.Elts[0].(*ast.BasicLit)
417 last, ok2 := n.Elts[len(n.Elts)-1].(*ast.BasicLit)
418 if !ok1 || !ok2 {
419 return v.error(n, "invalid interpolation")
420 }
421 if len(n.Elts) == 1 {
422 value = v.walk(n.Elts[0])
423 break
424 }
425 lit := &interpolation{baseValue: newExpr(n), k: stringKind}
426 value = lit
Marcel van Lohuizen6ceb6012019-02-18 18:30:38 +0100427 info, prefixLen, _, err := literal.ParseQuotes(first.Value, last.Value)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100428 if err != nil {
429 return v.error(n, "invalid interpolation: %v", err)
430 }
Marcel van Lohuizen369e4232019-02-15 10:59:29 +0400431 prefix := ""
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100432 for i := 0; i < len(n.Elts); i += 2 {
433 l, ok := n.Elts[i].(*ast.BasicLit)
434 if !ok {
435 return v.error(n, "invalid interpolation")
436 }
Marcel van Lohuizen369e4232019-02-15 10:59:29 +0400437 s := l.Value
438 if !strings.HasPrefix(s, prefix) {
439 return v.error(l, "invalid interpolation: unmatched ')'")
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100440 }
Marcel van Lohuizen369e4232019-02-15 10:59:29 +0400441 s = l.Value[prefixLen:]
442 x := parseString(v.ctx(), l, info, s)
443 lit.parts = append(lit.parts, x)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100444 if i+1 < len(n.Elts) {
Marcel van Lohuizen369e4232019-02-15 10:59:29 +0400445 lit.parts = append(lit.parts, v.walk(n.Elts[i+1]))
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100446 }
447 prefix = ")"
Marcel van Lohuizen369e4232019-02-15 10:59:29 +0400448 prefixLen = 1
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100449 }
450
451 case *ast.ListLit:
Marcel van Lohuizen9ee652d2019-04-25 17:16:01 +0200452 arcs := []arc{}
453 for i, e := range n.Elts {
454 arcs = append(arcs, arc{feature: label(i), v: v.walk(e)})
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100455 }
Marcel van Lohuizen9ee652d2019-04-25 17:16:01 +0200456 s := &structLit{baseValue: newExpr(n), arcs: arcs}
457 list := &list{baseValue: newExpr(n), elem: s}
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100458 list.initLit()
459 if n.Ellipsis != token.NoPos || n.Type != nil {
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200460 list.len = newBound(list.baseValue, opGeq, intKind, list.len)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100461 if n.Type != nil {
462 list.typ = v.walk(n.Type)
463 }
464 }
465 value = list
466
467 case *ast.ParenExpr:
468 value = v.walk(n.X)
469
470 case *ast.SelectorExpr:
471 v.inSelector++
472 value = &selectorExpr{
473 newExpr(n),
474 v.walk(n.X),
475 v.label(n.Sel.Name, true),
476 }
477 v.inSelector--
478
479 case *ast.IndexExpr:
480 value = &indexExpr{newExpr(n), v.walk(n.X), v.walk(n.Index)}
481
482 case *ast.SliceExpr:
483 slice := &sliceExpr{baseValue: newExpr(n), x: v.walk(n.X)}
484 if n.Low != nil {
485 slice.lo = v.walk(n.Low)
486 }
487 if n.High != nil {
488 slice.hi = v.walk(n.High)
489 }
490 value = slice
491
492 case *ast.CallExpr:
493 call := &callExpr{baseValue: newExpr(n), x: v.walk(n.Fun)}
494 for _, a := range n.Args {
495 call.args = append(call.args, v.walk(a))
496 }
497 value = call
498
499 case *ast.UnaryExpr:
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +0100500 switch n.Op {
501 case token.NOT, token.ADD, token.SUB:
502 value = &unaryExpr{
503 newExpr(n),
504 tokenMap[n.Op],
505 v.walk(n.X),
506 }
Marcel van Lohuizen706e69c2019-02-11 18:21:14 +0100507 case token.GEQ, token.GTR, token.LSS, token.LEQ,
508 token.NEQ, token.MAT, token.NMAT:
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200509 value = newBound(
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +0100510 newExpr(n),
511 tokenMap[n.Op],
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200512 topKind|nonGround,
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +0100513 v.walk(n.X),
Marcel van Lohuizen4a360992019-05-11 18:18:31 +0200514 )
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +0100515
516 case token.MUL:
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +0100517 return v.error(n, "preference mark not allowed at this position")
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +0100518 default:
519 return v.error(n, "unsupported unary operator %q", n.Op)
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100520 }
521
522 case *ast.BinaryExpr:
523 switch n.Op {
Marcel van Lohuizenbedcf0c2019-02-22 18:00:00 +0100524 case token.OR:
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +0100525 d := &disjunction{baseValue: newExpr(n)}
526 v.addDisjunctionElem(d, n.X, false)
527 v.addDisjunctionElem(d, n.Y, false)
528 value = d
Marcel van Lohuizen7d0797b2019-02-07 18:35:28 +0100529
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100530 default:
531 value = &binaryExpr{
532 newExpr(n),
533 tokenMap[n.Op], // op
534 v.walk(n.X), // left
535 v.walk(n.Y), // right
536 }
537 }
538
Marcel van Lohuizen5b49d762019-05-13 10:59:45 +0200539 case *ast.CommentGroup:
540 // Nothing to do for a free-floating comment group.
541
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100542 // nothing to do
543 // case *syntax.EmitDecl:
544 default:
545 // TODO: unhandled node.
546 // value = ctx.mkErr(n, "unknown node type %T", n)
547 panic(fmt.Sprintf("unimplemented %T", n))
548
549 }
550 return value
551}
552
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +0100553func (v *astVisitor) addDisjunctionElem(d *disjunction, n ast.Node, mark bool) {
554 switch x := n.(type) {
555 case *ast.BinaryExpr:
Marcel van Lohuizenbedcf0c2019-02-22 18:00:00 +0100556 if x.Op == token.OR {
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +0100557 v.addDisjunctionElem(d, x.X, mark)
558 v.addDisjunctionElem(d, x.Y, mark)
559 return
560 }
561 case *ast.UnaryExpr:
562 if x.Op == token.MUL {
563 mark = true
564 n = x.X
565 }
Marcel van Lohuizen94d845d2019-05-10 00:28:03 +0200566 d.hasDefaults = true
Marcel van Lohuizenc9b3cb22019-01-30 11:32:41 +0100567 }
568 d.values = append(d.values, dValue{v.walk(n), mark})
569}
570
Marcel van Lohuizen17157ea2018-12-11 10:41:10 +0100571func wrapClauses(v *astVisitor, y yielder, clauses []ast.Clause) yielder {
572 for _, c := range clauses {
573 if n, ok := c.(*ast.ForClause); ok {
574 params := &params{}
575 fn := &lambdaExpr{newExpr(n.Source), params, nil}
576 v.setScope(n, fn)
577 }
578 }
579 for i := len(clauses) - 1; i >= 0; i-- {
580 switch n := clauses[i].(type) {
581 case *ast.ForClause:
582 fn := v.mapScope(n).(*lambdaExpr)
583 fn.value = y
584
585 key := "_"
586 if n.Key != nil {
587 key = n.Key.Name
588 }
589 f := v.label(key, true)
590 fn.add(f, &basicType{newExpr(n.Key), stringKind | intKind})
591
592 f = v.label(n.Value.Name, true)
593 fn.add(f, &top{})
594
595 y = &feed{newExpr(n.Source), v.walk(n.Source), fn}
596
597 case *ast.IfClause:
598 y = &guard{newExpr(n.Condition), v.walk(n.Condition), y}
599 }
600 }
601 return y
602}