blob: 915f69efc4b6cbf7b490888f1735142777b92a31 [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"
21
22 mkparser "android/soong/androidmk/parser"
23)
24
25// Represents an expression in the Starlark code. An expression has
26// a type, and it can be evaluated.
27type starlarkExpr interface {
28 starlarkNode
29 typ() starlarkType
30 // Try to substitute variable values. Return substitution result
31 // and whether it is the same as the original expression.
32 eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool)
33 // Emit the code to copy the expression, otherwise we will end up
34 // with source and target pointing to the same list.
35 emitListVarCopy(gctx *generationContext)
36}
37
38func maybeString(expr starlarkExpr) (string, bool) {
39 if x, ok := expr.(*stringLiteralExpr); ok {
40 return x.literal, true
41 }
42 return "", false
43}
44
45type stringLiteralExpr struct {
46 literal string
47}
48
49func (s *stringLiteralExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
50 res = s
51 same = true
52 return
53}
54
55func (s *stringLiteralExpr) emit(gctx *generationContext) {
56 gctx.writef("%q", s.literal)
57}
58
59func (_ *stringLiteralExpr) typ() starlarkType {
60 return starlarkTypeString
61}
62
63func (s *stringLiteralExpr) emitListVarCopy(gctx *generationContext) {
64 s.emit(gctx)
65}
66
67// Integer literal
68type intLiteralExpr struct {
69 literal int
70}
71
72func (s *intLiteralExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
73 res = s
74 same = true
75 return
76}
77
78func (s *intLiteralExpr) emit(gctx *generationContext) {
79 gctx.writef("%d", s.literal)
80}
81
82func (_ *intLiteralExpr) typ() starlarkType {
83 return starlarkTypeInt
84}
85
86func (s *intLiteralExpr) emitListVarCopy(gctx *generationContext) {
87 s.emit(gctx)
88}
89
90// interpolateExpr represents Starlark's interpolation operator <string> % list
91// we break <string> into a list of chunks, i.e., "first%second%third" % (X, Y)
92// will have chunks = ["first", "second", "third"] and args = [X, Y]
93type interpolateExpr struct {
94 chunks []string // string chunks, separated by '%'
95 args []starlarkExpr
96}
97
98func (xi *interpolateExpr) emit(gctx *generationContext) {
99 if len(xi.chunks) != len(xi.args)+1 {
100 panic(fmt.Errorf("malformed interpolateExpr: #chunks(%d) != #args(%d)+1",
101 len(xi.chunks), len(xi.args)))
102 }
103 // Generate format as join of chunks, but first escape '%' in them
104 format := strings.ReplaceAll(xi.chunks[0], "%", "%%")
105 for _, chunk := range xi.chunks[1:] {
106 format += "%s" + strings.ReplaceAll(chunk, "%", "%%")
107 }
108 gctx.writef("%q %% ", format)
109 emitarg := func(arg starlarkExpr) {
110 if arg.typ() == starlarkTypeList {
111 gctx.write(`" ".join(`)
112 arg.emit(gctx)
113 gctx.write(`)`)
114 } else {
115 arg.emit(gctx)
116 }
117 }
118 if len(xi.args) == 1 {
119 emitarg(xi.args[0])
120 } else {
121 sep := "("
122 for _, arg := range xi.args {
123 gctx.write(sep)
124 emitarg(arg)
125 sep = ", "
126 }
127 gctx.write(")")
128 }
129}
130
131func (xi *interpolateExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
132 same = true
133 newChunks := []string{xi.chunks[0]}
134 var newArgs []starlarkExpr
135 for i, arg := range xi.args {
136 newArg, sameArg := arg.eval(valueMap)
137 same = same && sameArg
138 switch x := newArg.(type) {
139 case *stringLiteralExpr:
140 newChunks[len(newChunks)-1] += x.literal + xi.chunks[i+1]
141 same = false
142 continue
143 case *intLiteralExpr:
144 newChunks[len(newChunks)-1] += strconv.Itoa(x.literal) + xi.chunks[i+1]
145 same = false
146 continue
147 default:
148 newChunks = append(newChunks, xi.chunks[i+1])
149 newArgs = append(newArgs, newArg)
150 }
151 }
152 if same {
153 res = xi
154 } else if len(newChunks) == 1 {
155 res = &stringLiteralExpr{newChunks[0]}
156 } else {
157 res = &interpolateExpr{chunks: newChunks, args: newArgs}
158 }
159 return
160}
161
162func (_ *interpolateExpr) typ() starlarkType {
163 return starlarkTypeString
164}
165
166func (xi *interpolateExpr) emitListVarCopy(gctx *generationContext) {
167 xi.emit(gctx)
168}
169
170type variableRefExpr struct {
171 ref variable
172 isDefined bool
173}
174
175func (v *variableRefExpr) eval(map[string]starlarkExpr) (res starlarkExpr, same bool) {
176 predefined, ok := v.ref.(*predefinedVariable)
177 if same = !ok; same {
178 res = v
179 } else {
180 res = predefined.value
181 }
182 return
183}
184
185func (v *variableRefExpr) emit(gctx *generationContext) {
186 v.ref.emitGet(gctx, v.isDefined)
187}
188
189func (v *variableRefExpr) typ() starlarkType {
190 return v.ref.valueType()
191}
192
193func (v *variableRefExpr) emitListVarCopy(gctx *generationContext) {
194 v.emit(gctx)
195 if v.typ() == starlarkTypeList {
196 gctx.write("[:]") // this will copy the list
197 }
198}
199
200type notExpr struct {
201 expr starlarkExpr
202}
203
204func (n *notExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
205 if x, same := n.expr.eval(valueMap); same {
206 res = n
207 } else {
208 res = &notExpr{expr: x}
209 }
210 return
211}
212
213func (n *notExpr) emit(ctx *generationContext) {
214 ctx.write("not ")
215 n.expr.emit(ctx)
216}
217
218func (_ *notExpr) typ() starlarkType {
219 return starlarkTypeBool
220}
221
222func (n *notExpr) emitListVarCopy(gctx *generationContext) {
223 n.emit(gctx)
224}
225
226type eqExpr struct {
227 left, right starlarkExpr
228 isEq bool // if false, it's !=
229}
230
231func (eq *eqExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
232 xLeft, sameLeft := eq.left.eval(valueMap)
233 xRight, sameRight := eq.right.eval(valueMap)
234 if same = sameLeft && sameRight; same {
235 res = eq
236 } else {
237 res = &eqExpr{left: xLeft, right: xRight, isEq: eq.isEq}
238 }
239 return
240}
241
242func (eq *eqExpr) emit(gctx *generationContext) {
Sasha Smundak0554d762021-07-08 18:26:12 -0700243 emitSimple := func(expr starlarkExpr) {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800244 if eq.isEq {
245 gctx.write("not ")
246 }
Sasha Smundak0554d762021-07-08 18:26:12 -0700247 expr.emit(gctx)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800248 }
Sasha Smundak0554d762021-07-08 18:26:12 -0700249 // Are we checking that a variable is empty?
250 if isEmptyString(eq.left) {
251 emitSimple(eq.right)
252 return
253 } else if isEmptyString(eq.right) {
254 emitSimple(eq.left)
255 return
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800256
Sasha Smundak0554d762021-07-08 18:26:12 -0700257 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800258 // General case
259 eq.left.emit(gctx)
260 if eq.isEq {
261 gctx.write(" == ")
262 } else {
263 gctx.write(" != ")
264 }
265 eq.right.emit(gctx)
266}
267
268func (_ *eqExpr) typ() starlarkType {
269 return starlarkTypeBool
270}
271
272func (eq *eqExpr) emitListVarCopy(gctx *generationContext) {
273 eq.emit(gctx)
274}
275
276// variableDefinedExpr corresponds to Make's ifdef VAR
277type variableDefinedExpr struct {
278 v variable
279}
280
281func (v *variableDefinedExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
282 res = v
283 same = true
284 return
285
286}
287
288func (v *variableDefinedExpr) emit(gctx *generationContext) {
289 if v.v != nil {
290 v.v.emitDefined(gctx)
291 return
292 }
293 gctx.writef("%s(%q)", cfnWarning, "TODO(VAR)")
294}
295
296func (_ *variableDefinedExpr) typ() starlarkType {
297 return starlarkTypeBool
298}
299
300func (v *variableDefinedExpr) emitListVarCopy(gctx *generationContext) {
301 v.emit(gctx)
302}
303
304type listExpr struct {
305 items []starlarkExpr
306}
307
308func (l *listExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
309 newItems := make([]starlarkExpr, len(l.items))
310 same = true
311 for i, item := range l.items {
312 var sameItem bool
313 newItems[i], sameItem = item.eval(valueMap)
314 same = same && sameItem
315 }
316 if same {
317 res = l
318 } else {
319 res = &listExpr{newItems}
320 }
321 return
322}
323
324func (l *listExpr) emit(gctx *generationContext) {
325 if !gctx.inAssignment || len(l.items) < 2 {
326 gctx.write("[")
327 sep := ""
328 for _, item := range l.items {
329 gctx.write(sep)
330 item.emit(gctx)
331 sep = ", "
332 }
333 gctx.write("]")
334 return
335 }
336
337 gctx.write("[")
338 gctx.indentLevel += 2
339
340 for _, item := range l.items {
341 gctx.newLine()
342 item.emit(gctx)
343 gctx.write(",")
344 }
345 gctx.indentLevel -= 2
346 gctx.newLine()
347 gctx.write("]")
348}
349
350func (_ *listExpr) typ() starlarkType {
351 return starlarkTypeList
352}
353
354func (l *listExpr) emitListVarCopy(gctx *generationContext) {
355 l.emit(gctx)
356}
357
358func newStringListExpr(items []string) *listExpr {
359 v := listExpr{}
360 for _, item := range items {
361 v.items = append(v.items, &stringLiteralExpr{item})
362 }
363 return &v
364}
365
366// concatExpr generates epxr1 + expr2 + ... + exprN in Starlark.
367type concatExpr struct {
368 items []starlarkExpr
369}
370
371func (c *concatExpr) emit(gctx *generationContext) {
372 if len(c.items) == 1 {
373 c.items[0].emit(gctx)
374 return
375 }
376
377 if !gctx.inAssignment {
378 c.items[0].emit(gctx)
379 for _, item := range c.items[1:] {
380 gctx.write(" + ")
381 item.emit(gctx)
382 }
383 return
384 }
385 gctx.write("(")
386 c.items[0].emit(gctx)
387 gctx.indentLevel += 2
388 for _, item := range c.items[1:] {
389 gctx.write(" +")
390 gctx.newLine()
391 item.emit(gctx)
392 }
393 gctx.write(")")
394 gctx.indentLevel -= 2
395}
396
397func (c *concatExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
398 same = true
399 xConcat := &concatExpr{items: make([]starlarkExpr, len(c.items))}
400 for i, item := range c.items {
401 var sameItem bool
402 xConcat.items[i], sameItem = item.eval(valueMap)
403 same = same && sameItem
404 }
405 if same {
406 res = c
407 } else {
408 res = xConcat
409 }
410 return
411}
412
413func (_ *concatExpr) typ() starlarkType {
414 return starlarkTypeList
415}
416
417func (c *concatExpr) emitListVarCopy(gctx *generationContext) {
418 c.emit(gctx)
419}
420
421// inExpr generates <expr> [not] in <list>
422type inExpr struct {
423 expr starlarkExpr
424 list starlarkExpr
425 isNot bool
426}
427
428func (i *inExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
429 x := &inExpr{isNot: i.isNot}
430 var sameExpr, sameList bool
431 x.expr, sameExpr = i.expr.eval(valueMap)
432 x.list, sameList = i.list.eval(valueMap)
433 if same = sameExpr && sameList; same {
434 res = i
435 } else {
436 res = x
437 }
438 return
439}
440
441func (i *inExpr) emit(gctx *generationContext) {
442 i.expr.emit(gctx)
443 if i.isNot {
444 gctx.write(" not in ")
445 } else {
446 gctx.write(" in ")
447 }
448 i.list.emit(gctx)
449}
450
451func (_ *inExpr) typ() starlarkType {
452 return starlarkTypeBool
453}
454
455func (i *inExpr) emitListVarCopy(gctx *generationContext) {
456 i.emit(gctx)
457}
458
459type indexExpr struct {
460 array starlarkExpr
461 index starlarkExpr
462}
463
464func (ix indexExpr) emit(gctx *generationContext) {
465 ix.array.emit(gctx)
466 gctx.write("[")
467 ix.index.emit(gctx)
468 gctx.write("]")
469}
470
471func (ix indexExpr) typ() starlarkType {
472 return starlarkTypeString
473}
474
475func (ix indexExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
476 newArray, isSameArray := ix.array.eval(valueMap)
477 newIndex, isSameIndex := ix.index.eval(valueMap)
478 if same = isSameArray && isSameIndex; same {
479 res = ix
480 } else {
481 res = &indexExpr{newArray, newIndex}
482 }
483 return
484}
485
486func (ix indexExpr) emitListVarCopy(gctx *generationContext) {
487 ix.emit(gctx)
488}
489
490type callExpr struct {
491 object starlarkExpr // nil if static call
492 name string
493 args []starlarkExpr
494 returnType starlarkType
495}
496
497func (cx *callExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
498 newCallExpr := &callExpr{name: cx.name, args: make([]starlarkExpr, len(cx.args)),
499 returnType: cx.returnType}
500 if cx.object != nil {
501 newCallExpr.object, same = cx.object.eval(valueMap)
502 } else {
503 same = true
504 }
505 for i, args := range cx.args {
506 var s bool
507 newCallExpr.args[i], s = args.eval(valueMap)
508 same = same && s
509 }
510 if same {
511 res = cx
512 } else {
513 res = newCallExpr
514 }
515 return
516}
517
518func (cx *callExpr) emit(gctx *generationContext) {
519 if cx.object != nil {
520 gctx.write("(")
521 cx.object.emit(gctx)
522 gctx.write(")")
523 gctx.write(".", cx.name, "(")
524 } else {
525 kf, found := knownFunctions[cx.name]
526 if !found {
527 panic(fmt.Errorf("callExpr with unknown function %q", cx.name))
528 }
529 if kf.runtimeName[0] == '!' {
530 panic(fmt.Errorf("callExpr for %q should not be there", cx.name))
531 }
532 gctx.write(kf.runtimeName, "(")
533 }
534 sep := ""
535 for _, arg := range cx.args {
536 gctx.write(sep)
537 arg.emit(gctx)
538 sep = ", "
539 }
540 gctx.write(")")
541}
542
543func (cx *callExpr) typ() starlarkType {
544 return cx.returnType
545}
546
547func (cx *callExpr) emitListVarCopy(gctx *generationContext) {
548 cx.emit(gctx)
549}
550
551type badExpr struct {
552 node mkparser.Node
553 message string
554}
555
556func (b *badExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
557 res = b
558 same = true
559 return
560}
561
562func (b *badExpr) emit(_ *generationContext) {
563 panic("implement me")
564}
565
566func (_ *badExpr) typ() starlarkType {
567 return starlarkTypeUnknown
568}
569
570func (b *badExpr) emitListVarCopy(gctx *generationContext) {
571 panic("implement me")
572}
573
574func maybeConvertToStringList(expr starlarkExpr) starlarkExpr {
575 if xString, ok := expr.(*stringLiteralExpr); ok {
576 return newStringListExpr(strings.Fields(xString.literal))
577 }
578 return expr
579}
Sasha Smundak0554d762021-07-08 18:26:12 -0700580
581func isEmptyString(expr starlarkExpr) bool {
582 x, ok := expr.(*stringLiteralExpr)
583 return ok && x.literal == ""
584}