blob: ca48bd98206423276196e145f69e1db19b78aa2d [file] [log] [blame]
Sasha Smundakb051c4e2020-11-05 20:45:07 -08001// Copyright 2021 Google LLC
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 mk2rbc
16
17import (
18 "fmt"
19 "strconv"
20 "strings"
Sasha Smundakb051c4e2020-11-05 20:45:07 -080021)
22
23// Represents an expression in the Starlark code. An expression has
24// a type, and it can be evaluated.
25type starlarkExpr interface {
26 starlarkNode
27 typ() starlarkType
28 // Try to substitute variable values. Return substitution result
29 // and whether it is the same as the original expression.
30 eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool)
31 // Emit the code to copy the expression, otherwise we will end up
32 // with source and target pointing to the same list.
33 emitListVarCopy(gctx *generationContext)
Cole Faustb0d32ab2021-12-09 14:00:59 -080034 // Return the expression, calling the transformer func for
35 // every expression in the tree. If the transformer func returns non-nil,
36 // its result is used in place of the expression it was called with in the
37 // resulting expression. The resulting starlarkExpr will contain as many
38 // of the same objects from the original expression as possible.
39 transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr
Sasha Smundakb051c4e2020-11-05 20:45:07 -080040}
41
42func maybeString(expr starlarkExpr) (string, bool) {
43 if x, ok := expr.(*stringLiteralExpr); ok {
44 return x.literal, true
45 }
46 return "", false
47}
48
49type stringLiteralExpr struct {
50 literal string
51}
52
53func (s *stringLiteralExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
54 res = s
55 same = true
56 return
57}
58
59func (s *stringLiteralExpr) emit(gctx *generationContext) {
60 gctx.writef("%q", s.literal)
61}
62
63func (_ *stringLiteralExpr) typ() starlarkType {
64 return starlarkTypeString
65}
66
67func (s *stringLiteralExpr) emitListVarCopy(gctx *generationContext) {
68 s.emit(gctx)
69}
70
Cole Faustb0d32ab2021-12-09 14:00:59 -080071func (s *stringLiteralExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
72 if replacement := transformer(s); replacement != nil {
73 return replacement
74 } else {
75 return s
76 }
77}
78
Sasha Smundakb051c4e2020-11-05 20:45:07 -080079// Integer literal
80type intLiteralExpr struct {
81 literal int
82}
83
84func (s *intLiteralExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
85 res = s
86 same = true
87 return
88}
89
90func (s *intLiteralExpr) emit(gctx *generationContext) {
91 gctx.writef("%d", s.literal)
92}
93
94func (_ *intLiteralExpr) typ() starlarkType {
95 return starlarkTypeInt
96}
97
98func (s *intLiteralExpr) emitListVarCopy(gctx *generationContext) {
99 s.emit(gctx)
100}
101
Cole Faustb0d32ab2021-12-09 14:00:59 -0800102func (s *intLiteralExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
103 if replacement := transformer(s); replacement != nil {
104 return replacement
105 } else {
106 return s
107 }
108}
109
Cole Faust4eadba72021-12-07 11:54:52 -0800110// Boolean literal
111type boolLiteralExpr struct {
112 literal bool
113}
114
115func (b *boolLiteralExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
116 return b, true
117}
118
119func (b *boolLiteralExpr) emit(gctx *generationContext) {
120 if b.literal {
121 gctx.write("True")
122 } else {
123 gctx.write("False")
124 }
125}
126
127func (_ *boolLiteralExpr) typ() starlarkType {
128 return starlarkTypeBool
129}
130
131func (b *boolLiteralExpr) emitListVarCopy(gctx *generationContext) {
132 b.emit(gctx)
133}
134
Cole Faustb0d32ab2021-12-09 14:00:59 -0800135func (b *boolLiteralExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
136 if replacement := transformer(b); replacement != nil {
137 return replacement
138 } else {
139 return b
140 }
141}
142
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800143// interpolateExpr represents Starlark's interpolation operator <string> % list
144// we break <string> into a list of chunks, i.e., "first%second%third" % (X, Y)
145// will have chunks = ["first", "second", "third"] and args = [X, Y]
146type interpolateExpr struct {
147 chunks []string // string chunks, separated by '%'
148 args []starlarkExpr
149}
150
151func (xi *interpolateExpr) emit(gctx *generationContext) {
152 if len(xi.chunks) != len(xi.args)+1 {
153 panic(fmt.Errorf("malformed interpolateExpr: #chunks(%d) != #args(%d)+1",
154 len(xi.chunks), len(xi.args)))
155 }
156 // Generate format as join of chunks, but first escape '%' in them
157 format := strings.ReplaceAll(xi.chunks[0], "%", "%%")
158 for _, chunk := range xi.chunks[1:] {
159 format += "%s" + strings.ReplaceAll(chunk, "%", "%%")
160 }
161 gctx.writef("%q %% ", format)
Sasha Smundak422b6142021-11-11 18:31:59 -0800162 emitArg := func(arg starlarkExpr) {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800163 if arg.typ() == starlarkTypeList {
164 gctx.write(`" ".join(`)
165 arg.emit(gctx)
166 gctx.write(`)`)
167 } else {
168 arg.emit(gctx)
169 }
170 }
171 if len(xi.args) == 1 {
Sasha Smundak422b6142021-11-11 18:31:59 -0800172 emitArg(xi.args[0])
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800173 } else {
174 sep := "("
175 for _, arg := range xi.args {
176 gctx.write(sep)
Sasha Smundak422b6142021-11-11 18:31:59 -0800177 emitArg(arg)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800178 sep = ", "
179 }
180 gctx.write(")")
181 }
182}
183
184func (xi *interpolateExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
185 same = true
186 newChunks := []string{xi.chunks[0]}
187 var newArgs []starlarkExpr
188 for i, arg := range xi.args {
189 newArg, sameArg := arg.eval(valueMap)
190 same = same && sameArg
191 switch x := newArg.(type) {
192 case *stringLiteralExpr:
193 newChunks[len(newChunks)-1] += x.literal + xi.chunks[i+1]
194 same = false
195 continue
196 case *intLiteralExpr:
197 newChunks[len(newChunks)-1] += strconv.Itoa(x.literal) + xi.chunks[i+1]
198 same = false
199 continue
200 default:
201 newChunks = append(newChunks, xi.chunks[i+1])
202 newArgs = append(newArgs, newArg)
203 }
204 }
205 if same {
206 res = xi
207 } else if len(newChunks) == 1 {
208 res = &stringLiteralExpr{newChunks[0]}
209 } else {
210 res = &interpolateExpr{chunks: newChunks, args: newArgs}
211 }
212 return
213}
214
215func (_ *interpolateExpr) typ() starlarkType {
216 return starlarkTypeString
217}
218
219func (xi *interpolateExpr) emitListVarCopy(gctx *generationContext) {
220 xi.emit(gctx)
221}
222
Cole Faustb0d32ab2021-12-09 14:00:59 -0800223func (xi *interpolateExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
224 argsCopy := make([]starlarkExpr, len(xi.args))
225 for i, arg := range xi.args {
226 argsCopy[i] = arg.transform(transformer)
227 }
228 xi.args = argsCopy
229 if replacement := transformer(xi); replacement != nil {
230 return replacement
231 } else {
232 return xi
233 }
234}
235
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800236type variableRefExpr struct {
237 ref variable
238 isDefined bool
239}
240
241func (v *variableRefExpr) eval(map[string]starlarkExpr) (res starlarkExpr, same bool) {
242 predefined, ok := v.ref.(*predefinedVariable)
243 if same = !ok; same {
244 res = v
245 } else {
246 res = predefined.value
247 }
248 return
249}
250
251func (v *variableRefExpr) emit(gctx *generationContext) {
252 v.ref.emitGet(gctx, v.isDefined)
253}
254
255func (v *variableRefExpr) typ() starlarkType {
256 return v.ref.valueType()
257}
258
259func (v *variableRefExpr) emitListVarCopy(gctx *generationContext) {
260 v.emit(gctx)
261 if v.typ() == starlarkTypeList {
262 gctx.write("[:]") // this will copy the list
263 }
264}
265
Cole Faustb0d32ab2021-12-09 14:00:59 -0800266func (v *variableRefExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
267 if replacement := transformer(v); replacement != nil {
268 return replacement
269 } else {
270 return v
271 }
272}
273
Cole Faustf8320212021-11-10 15:05:07 -0800274type toStringExpr struct {
275 expr starlarkExpr
276}
277
278func (s *toStringExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
279 if x, same := s.expr.eval(valueMap); same {
280 res = s
281 } else {
282 res = &toStringExpr{expr: x}
283 }
284 return
285}
286
287func (s *toStringExpr) emit(ctx *generationContext) {
288 switch s.expr.typ() {
289 case starlarkTypeString, starlarkTypeUnknown:
290 // Assume unknown types are strings already.
291 s.expr.emit(ctx)
292 case starlarkTypeList:
293 ctx.write(`" ".join(`)
294 s.expr.emit(ctx)
295 ctx.write(")")
296 case starlarkTypeInt:
297 ctx.write(`("%d" % (`)
298 s.expr.emit(ctx)
299 ctx.write("))")
300 case starlarkTypeBool:
Cole Faustf1f44d32021-11-16 14:52:12 -0800301 ctx.write(`("true" if (`)
Cole Faustf8320212021-11-10 15:05:07 -0800302 s.expr.emit(ctx)
Cole Faustf1f44d32021-11-16 14:52:12 -0800303 ctx.write(`) else "")`)
Cole Faustf8320212021-11-10 15:05:07 -0800304 case starlarkTypeVoid:
305 ctx.write(`""`)
306 default:
307 panic("Unknown starlark type!")
308 }
309}
310
311func (s *toStringExpr) typ() starlarkType {
312 return starlarkTypeString
313}
314
315func (s *toStringExpr) emitListVarCopy(gctx *generationContext) {
316 s.emit(gctx)
317}
318
Cole Faustb0d32ab2021-12-09 14:00:59 -0800319func (s *toStringExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
320 s.expr = s.expr.transform(transformer)
321 if replacement := transformer(s); replacement != nil {
322 return replacement
323 } else {
324 return s
325 }
326}
327
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800328type notExpr struct {
329 expr starlarkExpr
330}
331
332func (n *notExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
333 if x, same := n.expr.eval(valueMap); same {
334 res = n
335 } else {
336 res = &notExpr{expr: x}
337 }
338 return
339}
340
341func (n *notExpr) emit(ctx *generationContext) {
342 ctx.write("not ")
343 n.expr.emit(ctx)
344}
345
346func (_ *notExpr) typ() starlarkType {
347 return starlarkTypeBool
348}
349
350func (n *notExpr) emitListVarCopy(gctx *generationContext) {
351 n.emit(gctx)
352}
353
Cole Faustb0d32ab2021-12-09 14:00:59 -0800354func (n *notExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
355 n.expr = n.expr.transform(transformer)
356 if replacement := transformer(n); replacement != nil {
357 return replacement
358 } else {
359 return n
360 }
361}
362
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800363type eqExpr struct {
364 left, right starlarkExpr
365 isEq bool // if false, it's !=
366}
367
368func (eq *eqExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
369 xLeft, sameLeft := eq.left.eval(valueMap)
370 xRight, sameRight := eq.right.eval(valueMap)
371 if same = sameLeft && sameRight; same {
372 res = eq
373 } else {
374 res = &eqExpr{left: xLeft, right: xRight, isEq: eq.isEq}
375 }
376 return
377}
378
379func (eq *eqExpr) emit(gctx *generationContext) {
Cole Faustf1f44d32021-11-16 14:52:12 -0800380 var stringOperand string
381 var otherOperand starlarkExpr
382 if s, ok := maybeString(eq.left); ok {
383 stringOperand = s
384 otherOperand = eq.right
385 } else if s, ok := maybeString(eq.right); ok {
386 stringOperand = s
387 otherOperand = eq.left
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800388 }
389
Cole Faustf1f44d32021-11-16 14:52:12 -0800390 // If we've identified one of the operands as being a string literal, check
391 // for some special cases we can do to simplify the resulting expression.
392 if otherOperand != nil {
393 if stringOperand == "" {
394 if eq.isEq {
395 gctx.write("not ")
396 }
397 otherOperand.emit(gctx)
398 return
399 }
400 if stringOperand == "true" && otherOperand.typ() == starlarkTypeBool {
401 if !eq.isEq {
402 gctx.write("not ")
403 }
404 otherOperand.emit(gctx)
405 return
406 }
Sasha Smundak0554d762021-07-08 18:26:12 -0700407 }
Cole Faustf8320212021-11-10 15:05:07 -0800408
409 if eq.left.typ() != eq.right.typ() {
410 eq.left = &toStringExpr{expr: eq.left}
411 eq.right = &toStringExpr{expr: eq.right}
412 }
413
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800414 // General case
415 eq.left.emit(gctx)
416 if eq.isEq {
417 gctx.write(" == ")
418 } else {
419 gctx.write(" != ")
420 }
421 eq.right.emit(gctx)
422}
423
424func (_ *eqExpr) typ() starlarkType {
425 return starlarkTypeBool
426}
427
428func (eq *eqExpr) emitListVarCopy(gctx *generationContext) {
429 eq.emit(gctx)
430}
431
Cole Faustb0d32ab2021-12-09 14:00:59 -0800432func (eq *eqExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
433 eq.left = eq.left.transform(transformer)
434 eq.right = eq.right.transform(transformer)
435 if replacement := transformer(eq); replacement != nil {
436 return replacement
437 } else {
438 return eq
439 }
440}
441
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800442// variableDefinedExpr corresponds to Make's ifdef VAR
443type variableDefinedExpr struct {
444 v variable
445}
446
447func (v *variableDefinedExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
448 res = v
449 same = true
450 return
451
452}
453
454func (v *variableDefinedExpr) emit(gctx *generationContext) {
455 if v.v != nil {
456 v.v.emitDefined(gctx)
457 return
458 }
459 gctx.writef("%s(%q)", cfnWarning, "TODO(VAR)")
460}
461
462func (_ *variableDefinedExpr) typ() starlarkType {
463 return starlarkTypeBool
464}
465
466func (v *variableDefinedExpr) emitListVarCopy(gctx *generationContext) {
467 v.emit(gctx)
468}
469
Cole Faustb0d32ab2021-12-09 14:00:59 -0800470func (v *variableDefinedExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
471 // TODO: VariableDefinedExpr isn't really an expression?
472 return v
473}
474
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800475type listExpr struct {
476 items []starlarkExpr
477}
478
479func (l *listExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
480 newItems := make([]starlarkExpr, len(l.items))
481 same = true
482 for i, item := range l.items {
483 var sameItem bool
484 newItems[i], sameItem = item.eval(valueMap)
485 same = same && sameItem
486 }
487 if same {
488 res = l
489 } else {
490 res = &listExpr{newItems}
491 }
492 return
493}
494
495func (l *listExpr) emit(gctx *generationContext) {
496 if !gctx.inAssignment || len(l.items) < 2 {
497 gctx.write("[")
498 sep := ""
499 for _, item := range l.items {
500 gctx.write(sep)
501 item.emit(gctx)
502 sep = ", "
503 }
504 gctx.write("]")
505 return
506 }
507
508 gctx.write("[")
509 gctx.indentLevel += 2
510
511 for _, item := range l.items {
512 gctx.newLine()
513 item.emit(gctx)
514 gctx.write(",")
515 }
516 gctx.indentLevel -= 2
517 gctx.newLine()
518 gctx.write("]")
519}
520
521func (_ *listExpr) typ() starlarkType {
522 return starlarkTypeList
523}
524
525func (l *listExpr) emitListVarCopy(gctx *generationContext) {
526 l.emit(gctx)
527}
528
Cole Faustb0d32ab2021-12-09 14:00:59 -0800529func (l *listExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
530 itemsCopy := make([]starlarkExpr, len(l.items))
531 for i, item := range l.items {
532 itemsCopy[i] = item.transform(transformer)
533 }
534 l.items = itemsCopy
535 if replacement := transformer(l); replacement != nil {
536 return replacement
537 } else {
538 return l
539 }
540}
541
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800542func newStringListExpr(items []string) *listExpr {
543 v := listExpr{}
544 for _, item := range items {
545 v.items = append(v.items, &stringLiteralExpr{item})
546 }
547 return &v
548}
549
Sasha Smundak422b6142021-11-11 18:31:59 -0800550// concatExpr generates expr1 + expr2 + ... + exprN in Starlark.
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800551type concatExpr struct {
552 items []starlarkExpr
553}
554
555func (c *concatExpr) emit(gctx *generationContext) {
556 if len(c.items) == 1 {
557 c.items[0].emit(gctx)
558 return
559 }
560
561 if !gctx.inAssignment {
562 c.items[0].emit(gctx)
563 for _, item := range c.items[1:] {
564 gctx.write(" + ")
565 item.emit(gctx)
566 }
567 return
568 }
569 gctx.write("(")
570 c.items[0].emit(gctx)
571 gctx.indentLevel += 2
572 for _, item := range c.items[1:] {
573 gctx.write(" +")
574 gctx.newLine()
575 item.emit(gctx)
576 }
577 gctx.write(")")
578 gctx.indentLevel -= 2
579}
580
581func (c *concatExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
582 same = true
583 xConcat := &concatExpr{items: make([]starlarkExpr, len(c.items))}
584 for i, item := range c.items {
585 var sameItem bool
586 xConcat.items[i], sameItem = item.eval(valueMap)
587 same = same && sameItem
588 }
589 if same {
590 res = c
591 } else {
592 res = xConcat
593 }
594 return
595}
596
597func (_ *concatExpr) typ() starlarkType {
598 return starlarkTypeList
599}
600
601func (c *concatExpr) emitListVarCopy(gctx *generationContext) {
602 c.emit(gctx)
603}
604
Cole Faustb0d32ab2021-12-09 14:00:59 -0800605func (c *concatExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
606 itemsCopy := make([]starlarkExpr, len(c.items))
607 for i, item := range c.items {
608 itemsCopy[i] = item.transform(transformer)
609 }
610 c.items = itemsCopy
611 if replacement := transformer(c); replacement != nil {
612 return replacement
613 } else {
614 return c
615 }
616}
617
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800618// inExpr generates <expr> [not] in <list>
619type inExpr struct {
620 expr starlarkExpr
621 list starlarkExpr
622 isNot bool
623}
624
625func (i *inExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
626 x := &inExpr{isNot: i.isNot}
627 var sameExpr, sameList bool
628 x.expr, sameExpr = i.expr.eval(valueMap)
629 x.list, sameList = i.list.eval(valueMap)
630 if same = sameExpr && sameList; same {
631 res = i
632 } else {
633 res = x
634 }
635 return
636}
637
638func (i *inExpr) emit(gctx *generationContext) {
639 i.expr.emit(gctx)
640 if i.isNot {
641 gctx.write(" not in ")
642 } else {
643 gctx.write(" in ")
644 }
645 i.list.emit(gctx)
646}
647
648func (_ *inExpr) typ() starlarkType {
649 return starlarkTypeBool
650}
651
652func (i *inExpr) emitListVarCopy(gctx *generationContext) {
653 i.emit(gctx)
654}
655
Cole Faustb0d32ab2021-12-09 14:00:59 -0800656func (i *inExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
657 i.expr = i.expr.transform(transformer)
658 i.list = i.list.transform(transformer)
659 if replacement := transformer(i); replacement != nil {
660 return replacement
661 } else {
662 return i
663 }
664}
665
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800666type indexExpr struct {
667 array starlarkExpr
668 index starlarkExpr
669}
670
Cole Faustb0d32ab2021-12-09 14:00:59 -0800671func (ix *indexExpr) emit(gctx *generationContext) {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800672 ix.array.emit(gctx)
673 gctx.write("[")
674 ix.index.emit(gctx)
675 gctx.write("]")
676}
677
Cole Faustb0d32ab2021-12-09 14:00:59 -0800678func (ix *indexExpr) typ() starlarkType {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800679 return starlarkTypeString
680}
681
Cole Faustb0d32ab2021-12-09 14:00:59 -0800682func (ix *indexExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800683 newArray, isSameArray := ix.array.eval(valueMap)
684 newIndex, isSameIndex := ix.index.eval(valueMap)
685 if same = isSameArray && isSameIndex; same {
686 res = ix
687 } else {
688 res = &indexExpr{newArray, newIndex}
689 }
690 return
691}
692
Cole Faustb0d32ab2021-12-09 14:00:59 -0800693func (ix *indexExpr) emitListVarCopy(gctx *generationContext) {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800694 ix.emit(gctx)
695}
696
Cole Faustb0d32ab2021-12-09 14:00:59 -0800697func (ix *indexExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
698 ix.array = ix.array.transform(transformer)
699 ix.index = ix.index.transform(transformer)
700 if replacement := transformer(ix); replacement != nil {
701 return replacement
702 } else {
703 return ix
704 }
705}
706
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800707type callExpr struct {
708 object starlarkExpr // nil if static call
709 name string
710 args []starlarkExpr
711 returnType starlarkType
712}
713
714func (cx *callExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
715 newCallExpr := &callExpr{name: cx.name, args: make([]starlarkExpr, len(cx.args)),
716 returnType: cx.returnType}
717 if cx.object != nil {
718 newCallExpr.object, same = cx.object.eval(valueMap)
719 } else {
720 same = true
721 }
722 for i, args := range cx.args {
723 var s bool
724 newCallExpr.args[i], s = args.eval(valueMap)
725 same = same && s
726 }
727 if same {
728 res = cx
729 } else {
730 res = newCallExpr
731 }
732 return
733}
734
735func (cx *callExpr) emit(gctx *generationContext) {
Sasha Smundak3deb9682021-07-26 18:42:25 -0700736 sep := ""
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800737 if cx.object != nil {
738 gctx.write("(")
739 cx.object.emit(gctx)
740 gctx.write(")")
741 gctx.write(".", cx.name, "(")
742 } else {
743 kf, found := knownFunctions[cx.name]
744 if !found {
745 panic(fmt.Errorf("callExpr with unknown function %q", cx.name))
746 }
747 if kf.runtimeName[0] == '!' {
748 panic(fmt.Errorf("callExpr for %q should not be there", cx.name))
749 }
750 gctx.write(kf.runtimeName, "(")
Sasha Smundak3deb9682021-07-26 18:42:25 -0700751 if kf.hiddenArg == hiddenArgGlobal {
752 gctx.write("g")
753 sep = ", "
754 } else if kf.hiddenArg == hiddenArgConfig {
755 gctx.write("cfg")
756 sep = ", "
757 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800758 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800759 for _, arg := range cx.args {
760 gctx.write(sep)
761 arg.emit(gctx)
762 sep = ", "
763 }
764 gctx.write(")")
765}
766
767func (cx *callExpr) typ() starlarkType {
768 return cx.returnType
769}
770
771func (cx *callExpr) emitListVarCopy(gctx *generationContext) {
772 cx.emit(gctx)
773}
774
Cole Faustb0d32ab2021-12-09 14:00:59 -0800775func (cx *callExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
776 if cx.object != nil {
777 cx.object = cx.object.transform(transformer)
778 }
779 argsCopy := make([]starlarkExpr, len(cx.args))
780 for i, arg := range cx.args {
781 argsCopy[i] = arg.transform(transformer)
782 }
783 if replacement := transformer(cx); replacement != nil {
784 return replacement
785 } else {
786 return cx
787 }
788}
789
Cole Faust4eadba72021-12-07 11:54:52 -0800790type ifExpr struct {
791 condition starlarkExpr
792 ifTrue starlarkExpr
793 ifFalse starlarkExpr
794}
795
796func (i *ifExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
797 cond, condSame := i.condition.eval(valueMap)
798 t, tSame := i.ifTrue.eval(valueMap)
799 f, fSame := i.ifFalse.eval(valueMap)
800 same = condSame && tSame && fSame
801 if same {
802 return i, same
803 } else {
804 return &ifExpr{
805 condition: cond,
806 ifTrue: t,
807 ifFalse: f,
808 }, same
809 }
810}
811
812func (i *ifExpr) emit(gctx *generationContext) {
813 gctx.write("(")
814 i.ifTrue.emit(gctx)
815 gctx.write(" if ")
816 i.condition.emit(gctx)
817 gctx.write(" else ")
818 i.ifFalse.emit(gctx)
819 gctx.write(")")
820}
821
822func (i *ifExpr) typ() starlarkType {
823 tType := i.ifTrue.typ()
824 fType := i.ifFalse.typ()
825 if tType != fType && tType != starlarkTypeUnknown && fType != starlarkTypeUnknown {
826 panic("Conflicting types in if expression")
827 }
828 if tType != starlarkTypeUnknown {
829 return tType
830 } else {
831 return fType
832 }
833}
834
835func (i *ifExpr) emitListVarCopy(gctx *generationContext) {
836 i.emit(gctx)
837}
838
Cole Faustb0d32ab2021-12-09 14:00:59 -0800839func (i *ifExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
840 i.condition = i.condition.transform(transformer)
841 i.ifTrue = i.ifTrue.transform(transformer)
842 i.ifFalse = i.ifFalse.transform(transformer)
843 if replacement := transformer(i); replacement != nil {
844 return replacement
845 } else {
846 return i
847 }
848}
849
850type identifierExpr struct {
851 name string
852}
853
854func (i *identifierExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
855 return i, true
856}
857
858func (i *identifierExpr) emit(gctx *generationContext) {
859 gctx.write(i.name)
860}
861
862func (i *identifierExpr) typ() starlarkType {
863 return starlarkTypeUnknown
864}
865
866func (i *identifierExpr) emitListVarCopy(gctx *generationContext) {
867 i.emit(gctx)
868}
869
870func (i *identifierExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
871 if replacement := transformer(i); replacement != nil {
872 return replacement
873 } else {
874 return i
875 }
876}
877
878type foreachExpr struct {
879 varName string
880 list starlarkExpr
881 action starlarkExpr
882}
883
884func (f *foreachExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
885 list, listSame := f.list.eval(valueMap)
886 action, actionSame := f.action.eval(valueMap)
887 same = listSame && actionSame
888 if same {
889 return f, same
890 } else {
891 return &foreachExpr{
892 varName: f.varName,
893 list: list,
894 action: action,
895 }, same
896 }
897}
898
899func (f *foreachExpr) emit(gctx *generationContext) {
900 gctx.write("[")
901 f.action.emit(gctx)
902 gctx.write(" for " + f.varName + " in ")
903 f.list.emit(gctx)
904 gctx.write("]")
905}
906
907func (f *foreachExpr) typ() starlarkType {
908 return starlarkTypeList
909}
910
911func (f *foreachExpr) emitListVarCopy(gctx *generationContext) {
912 f.emit(gctx)
913}
914
915func (f *foreachExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
916 f.list = f.list.transform(transformer)
917 f.action = f.action.transform(transformer)
918 if replacement := transformer(f); replacement != nil {
919 return replacement
920 } else {
921 return f
922 }
923}
924
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800925type badExpr struct {
Sasha Smundak422b6142021-11-11 18:31:59 -0800926 errorLocation ErrorLocation
927 message string
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800928}
929
930func (b *badExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
931 res = b
932 same = true
933 return
934}
935
Sasha Smundak422b6142021-11-11 18:31:59 -0800936func (b *badExpr) emit(gctx *generationContext) {
937 gctx.emitConversionError(b.errorLocation, b.message)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800938}
939
940func (_ *badExpr) typ() starlarkType {
941 return starlarkTypeUnknown
942}
943
Sasha Smundak422b6142021-11-11 18:31:59 -0800944func (_ *badExpr) emitListVarCopy(_ *generationContext) {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800945 panic("implement me")
946}
947
Cole Faustb0d32ab2021-12-09 14:00:59 -0800948func (b *badExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
949 if replacement := transformer(b); replacement != nil {
950 return replacement
951 } else {
952 return b
953 }
954}
955
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800956func maybeConvertToStringList(expr starlarkExpr) starlarkExpr {
957 if xString, ok := expr.(*stringLiteralExpr); ok {
958 return newStringListExpr(strings.Fields(xString.literal))
959 }
960 return expr
961}
Sasha Smundak0554d762021-07-08 18:26:12 -0700962
963func isEmptyString(expr starlarkExpr) bool {
964 x, ok := expr.(*stringLiteralExpr)
965 return ok && x.literal == ""
966}