xref: /aosp_15_r20/build/soong/mk2rbc/expr.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2021 Google LLC
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//      http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage mk2rbc
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"fmt"
19*333d2b36SAndroid Build Coastguard Worker	"strings"
20*333d2b36SAndroid Build Coastguard Worker)
21*333d2b36SAndroid Build Coastguard Worker
22*333d2b36SAndroid Build Coastguard Worker// Represents an expression in the Starlark code. An expression has a type.
23*333d2b36SAndroid Build Coastguard Workertype starlarkExpr interface {
24*333d2b36SAndroid Build Coastguard Worker	starlarkNode
25*333d2b36SAndroid Build Coastguard Worker	typ() starlarkType
26*333d2b36SAndroid Build Coastguard Worker	// Emit the code to copy the expression, otherwise we will end up
27*333d2b36SAndroid Build Coastguard Worker	// with source and target pointing to the same list.
28*333d2b36SAndroid Build Coastguard Worker	emitListVarCopy(gctx *generationContext)
29*333d2b36SAndroid Build Coastguard Worker	// Return the expression, calling the transformer func for
30*333d2b36SAndroid Build Coastguard Worker	// every expression in the tree. If the transformer func returns non-nil,
31*333d2b36SAndroid Build Coastguard Worker	// its result is used in place of the expression it was called with in the
32*333d2b36SAndroid Build Coastguard Worker	// resulting expression. The resulting starlarkExpr will contain as many
33*333d2b36SAndroid Build Coastguard Worker	// of the same objects from the original expression as possible.
34*333d2b36SAndroid Build Coastguard Worker	transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr
35*333d2b36SAndroid Build Coastguard Worker}
36*333d2b36SAndroid Build Coastguard Worker
37*333d2b36SAndroid Build Coastguard Workerfunc maybeString(expr starlarkExpr) (string, bool) {
38*333d2b36SAndroid Build Coastguard Worker	if x, ok := expr.(*stringLiteralExpr); ok {
39*333d2b36SAndroid Build Coastguard Worker		return x.literal, true
40*333d2b36SAndroid Build Coastguard Worker	}
41*333d2b36SAndroid Build Coastguard Worker	return "", false
42*333d2b36SAndroid Build Coastguard Worker}
43*333d2b36SAndroid Build Coastguard Worker
44*333d2b36SAndroid Build Coastguard Workertype stringLiteralExpr struct {
45*333d2b36SAndroid Build Coastguard Worker	literal string
46*333d2b36SAndroid Build Coastguard Worker}
47*333d2b36SAndroid Build Coastguard Worker
48*333d2b36SAndroid Build Coastguard Workerfunc (s *stringLiteralExpr) emit(gctx *generationContext) {
49*333d2b36SAndroid Build Coastguard Worker	gctx.writef("%q", s.literal)
50*333d2b36SAndroid Build Coastguard Worker}
51*333d2b36SAndroid Build Coastguard Worker
52*333d2b36SAndroid Build Coastguard Workerfunc (_ *stringLiteralExpr) typ() starlarkType {
53*333d2b36SAndroid Build Coastguard Worker	return starlarkTypeString
54*333d2b36SAndroid Build Coastguard Worker}
55*333d2b36SAndroid Build Coastguard Worker
56*333d2b36SAndroid Build Coastguard Workerfunc (s *stringLiteralExpr) emitListVarCopy(gctx *generationContext) {
57*333d2b36SAndroid Build Coastguard Worker	s.emit(gctx)
58*333d2b36SAndroid Build Coastguard Worker}
59*333d2b36SAndroid Build Coastguard Worker
60*333d2b36SAndroid Build Coastguard Workerfunc (s *stringLiteralExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
61*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(s); replacement != nil {
62*333d2b36SAndroid Build Coastguard Worker		return replacement
63*333d2b36SAndroid Build Coastguard Worker	} else {
64*333d2b36SAndroid Build Coastguard Worker		return s
65*333d2b36SAndroid Build Coastguard Worker	}
66*333d2b36SAndroid Build Coastguard Worker}
67*333d2b36SAndroid Build Coastguard Worker
68*333d2b36SAndroid Build Coastguard Worker// Integer literal
69*333d2b36SAndroid Build Coastguard Workertype intLiteralExpr struct {
70*333d2b36SAndroid Build Coastguard Worker	literal int
71*333d2b36SAndroid Build Coastguard Worker}
72*333d2b36SAndroid Build Coastguard Worker
73*333d2b36SAndroid Build Coastguard Workerfunc (s *intLiteralExpr) emit(gctx *generationContext) {
74*333d2b36SAndroid Build Coastguard Worker	gctx.writef("%d", s.literal)
75*333d2b36SAndroid Build Coastguard Worker}
76*333d2b36SAndroid Build Coastguard Worker
77*333d2b36SAndroid Build Coastguard Workerfunc (_ *intLiteralExpr) typ() starlarkType {
78*333d2b36SAndroid Build Coastguard Worker	return starlarkTypeInt
79*333d2b36SAndroid Build Coastguard Worker}
80*333d2b36SAndroid Build Coastguard Worker
81*333d2b36SAndroid Build Coastguard Workerfunc (s *intLiteralExpr) emitListVarCopy(gctx *generationContext) {
82*333d2b36SAndroid Build Coastguard Worker	s.emit(gctx)
83*333d2b36SAndroid Build Coastguard Worker}
84*333d2b36SAndroid Build Coastguard Worker
85*333d2b36SAndroid Build Coastguard Workerfunc (s *intLiteralExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
86*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(s); replacement != nil {
87*333d2b36SAndroid Build Coastguard Worker		return replacement
88*333d2b36SAndroid Build Coastguard Worker	} else {
89*333d2b36SAndroid Build Coastguard Worker		return s
90*333d2b36SAndroid Build Coastguard Worker	}
91*333d2b36SAndroid Build Coastguard Worker}
92*333d2b36SAndroid Build Coastguard Worker
93*333d2b36SAndroid Build Coastguard Worker// Boolean literal
94*333d2b36SAndroid Build Coastguard Workertype boolLiteralExpr struct {
95*333d2b36SAndroid Build Coastguard Worker	literal bool
96*333d2b36SAndroid Build Coastguard Worker}
97*333d2b36SAndroid Build Coastguard Worker
98*333d2b36SAndroid Build Coastguard Workerfunc (b *boolLiteralExpr) emit(gctx *generationContext) {
99*333d2b36SAndroid Build Coastguard Worker	if b.literal {
100*333d2b36SAndroid Build Coastguard Worker		gctx.write("True")
101*333d2b36SAndroid Build Coastguard Worker	} else {
102*333d2b36SAndroid Build Coastguard Worker		gctx.write("False")
103*333d2b36SAndroid Build Coastguard Worker	}
104*333d2b36SAndroid Build Coastguard Worker}
105*333d2b36SAndroid Build Coastguard Worker
106*333d2b36SAndroid Build Coastguard Workerfunc (_ *boolLiteralExpr) typ() starlarkType {
107*333d2b36SAndroid Build Coastguard Worker	return starlarkTypeBool
108*333d2b36SAndroid Build Coastguard Worker}
109*333d2b36SAndroid Build Coastguard Worker
110*333d2b36SAndroid Build Coastguard Workerfunc (b *boolLiteralExpr) emitListVarCopy(gctx *generationContext) {
111*333d2b36SAndroid Build Coastguard Worker	b.emit(gctx)
112*333d2b36SAndroid Build Coastguard Worker}
113*333d2b36SAndroid Build Coastguard Worker
114*333d2b36SAndroid Build Coastguard Workerfunc (b *boolLiteralExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
115*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(b); replacement != nil {
116*333d2b36SAndroid Build Coastguard Worker		return replacement
117*333d2b36SAndroid Build Coastguard Worker	} else {
118*333d2b36SAndroid Build Coastguard Worker		return b
119*333d2b36SAndroid Build Coastguard Worker	}
120*333d2b36SAndroid Build Coastguard Worker}
121*333d2b36SAndroid Build Coastguard Worker
122*333d2b36SAndroid Build Coastguard Workertype globalsExpr struct {
123*333d2b36SAndroid Build Coastguard Worker}
124*333d2b36SAndroid Build Coastguard Worker
125*333d2b36SAndroid Build Coastguard Workerfunc (g *globalsExpr) emit(gctx *generationContext) {
126*333d2b36SAndroid Build Coastguard Worker	gctx.write("g")
127*333d2b36SAndroid Build Coastguard Worker}
128*333d2b36SAndroid Build Coastguard Worker
129*333d2b36SAndroid Build Coastguard Workerfunc (g *globalsExpr) typ() starlarkType {
130*333d2b36SAndroid Build Coastguard Worker	return starlarkTypeUnknown
131*333d2b36SAndroid Build Coastguard Worker}
132*333d2b36SAndroid Build Coastguard Worker
133*333d2b36SAndroid Build Coastguard Workerfunc (g *globalsExpr) emitListVarCopy(gctx *generationContext) {
134*333d2b36SAndroid Build Coastguard Worker	g.emit(gctx)
135*333d2b36SAndroid Build Coastguard Worker}
136*333d2b36SAndroid Build Coastguard Worker
137*333d2b36SAndroid Build Coastguard Workerfunc (g *globalsExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
138*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(g); replacement != nil {
139*333d2b36SAndroid Build Coastguard Worker		return replacement
140*333d2b36SAndroid Build Coastguard Worker	} else {
141*333d2b36SAndroid Build Coastguard Worker		return g
142*333d2b36SAndroid Build Coastguard Worker	}
143*333d2b36SAndroid Build Coastguard Worker}
144*333d2b36SAndroid Build Coastguard Worker
145*333d2b36SAndroid Build Coastguard Worker// interpolateExpr represents Starlark's interpolation operator <string> % list
146*333d2b36SAndroid Build Coastguard Worker// we break <string> into a list of chunks, i.e., "first%second%third" % (X, Y)
147*333d2b36SAndroid Build Coastguard Worker// will have chunks = ["first", "second", "third"] and args = [X, Y]
148*333d2b36SAndroid Build Coastguard Workertype interpolateExpr struct {
149*333d2b36SAndroid Build Coastguard Worker	chunks []string // string chunks, separated by '%'
150*333d2b36SAndroid Build Coastguard Worker	args   []starlarkExpr
151*333d2b36SAndroid Build Coastguard Worker}
152*333d2b36SAndroid Build Coastguard Worker
153*333d2b36SAndroid Build Coastguard Workerfunc NewInterpolateExpr(parts []starlarkExpr) starlarkExpr {
154*333d2b36SAndroid Build Coastguard Worker	result := &interpolateExpr{}
155*333d2b36SAndroid Build Coastguard Worker	needString := true
156*333d2b36SAndroid Build Coastguard Worker	for _, part := range parts {
157*333d2b36SAndroid Build Coastguard Worker		if needString {
158*333d2b36SAndroid Build Coastguard Worker			if strLit, ok := part.(*stringLiteralExpr); ok {
159*333d2b36SAndroid Build Coastguard Worker				result.chunks = append(result.chunks, strLit.literal)
160*333d2b36SAndroid Build Coastguard Worker			} else {
161*333d2b36SAndroid Build Coastguard Worker				result.chunks = append(result.chunks, "")
162*333d2b36SAndroid Build Coastguard Worker			}
163*333d2b36SAndroid Build Coastguard Worker			needString = false
164*333d2b36SAndroid Build Coastguard Worker		} else {
165*333d2b36SAndroid Build Coastguard Worker			if strLit, ok := part.(*stringLiteralExpr); ok {
166*333d2b36SAndroid Build Coastguard Worker				result.chunks[len(result.chunks)-1] += strLit.literal
167*333d2b36SAndroid Build Coastguard Worker			} else {
168*333d2b36SAndroid Build Coastguard Worker				result.args = append(result.args, part)
169*333d2b36SAndroid Build Coastguard Worker				needString = true
170*333d2b36SAndroid Build Coastguard Worker			}
171*333d2b36SAndroid Build Coastguard Worker		}
172*333d2b36SAndroid Build Coastguard Worker	}
173*333d2b36SAndroid Build Coastguard Worker	if len(result.chunks) == len(result.args) {
174*333d2b36SAndroid Build Coastguard Worker		result.chunks = append(result.chunks, "")
175*333d2b36SAndroid Build Coastguard Worker	}
176*333d2b36SAndroid Build Coastguard Worker	if len(result.args) == 0 {
177*333d2b36SAndroid Build Coastguard Worker		return &stringLiteralExpr{literal: strings.Join(result.chunks, "")}
178*333d2b36SAndroid Build Coastguard Worker	}
179*333d2b36SAndroid Build Coastguard Worker	return result
180*333d2b36SAndroid Build Coastguard Worker}
181*333d2b36SAndroid Build Coastguard Worker
182*333d2b36SAndroid Build Coastguard Workerfunc (xi *interpolateExpr) emit(gctx *generationContext) {
183*333d2b36SAndroid Build Coastguard Worker	if len(xi.chunks) != len(xi.args)+1 {
184*333d2b36SAndroid Build Coastguard Worker		panic(fmt.Errorf("malformed interpolateExpr: #chunks(%d) != #args(%d)+1",
185*333d2b36SAndroid Build Coastguard Worker			len(xi.chunks), len(xi.args)))
186*333d2b36SAndroid Build Coastguard Worker	}
187*333d2b36SAndroid Build Coastguard Worker	// Generate format as join of chunks, but first escape '%' in them
188*333d2b36SAndroid Build Coastguard Worker	format := strings.ReplaceAll(xi.chunks[0], "%", "%%")
189*333d2b36SAndroid Build Coastguard Worker	for _, chunk := range xi.chunks[1:] {
190*333d2b36SAndroid Build Coastguard Worker		format += "%s" + strings.ReplaceAll(chunk, "%", "%%")
191*333d2b36SAndroid Build Coastguard Worker	}
192*333d2b36SAndroid Build Coastguard Worker	gctx.writef("%q %% ", format)
193*333d2b36SAndroid Build Coastguard Worker	emitArg := func(arg starlarkExpr) {
194*333d2b36SAndroid Build Coastguard Worker		if arg.typ() == starlarkTypeList {
195*333d2b36SAndroid Build Coastguard Worker			gctx.write(`" ".join(`)
196*333d2b36SAndroid Build Coastguard Worker			arg.emit(gctx)
197*333d2b36SAndroid Build Coastguard Worker			gctx.write(`)`)
198*333d2b36SAndroid Build Coastguard Worker		} else {
199*333d2b36SAndroid Build Coastguard Worker			arg.emit(gctx)
200*333d2b36SAndroid Build Coastguard Worker		}
201*333d2b36SAndroid Build Coastguard Worker	}
202*333d2b36SAndroid Build Coastguard Worker	if len(xi.args) == 1 {
203*333d2b36SAndroid Build Coastguard Worker		emitArg(xi.args[0])
204*333d2b36SAndroid Build Coastguard Worker	} else {
205*333d2b36SAndroid Build Coastguard Worker		sep := "("
206*333d2b36SAndroid Build Coastguard Worker		for _, arg := range xi.args {
207*333d2b36SAndroid Build Coastguard Worker			gctx.write(sep)
208*333d2b36SAndroid Build Coastguard Worker			emitArg(arg)
209*333d2b36SAndroid Build Coastguard Worker			sep = ", "
210*333d2b36SAndroid Build Coastguard Worker		}
211*333d2b36SAndroid Build Coastguard Worker		gctx.write(")")
212*333d2b36SAndroid Build Coastguard Worker	}
213*333d2b36SAndroid Build Coastguard Worker}
214*333d2b36SAndroid Build Coastguard Worker
215*333d2b36SAndroid Build Coastguard Workerfunc (_ *interpolateExpr) typ() starlarkType {
216*333d2b36SAndroid Build Coastguard Worker	return starlarkTypeString
217*333d2b36SAndroid Build Coastguard Worker}
218*333d2b36SAndroid Build Coastguard Worker
219*333d2b36SAndroid Build Coastguard Workerfunc (xi *interpolateExpr) emitListVarCopy(gctx *generationContext) {
220*333d2b36SAndroid Build Coastguard Worker	xi.emit(gctx)
221*333d2b36SAndroid Build Coastguard Worker}
222*333d2b36SAndroid Build Coastguard Worker
223*333d2b36SAndroid Build Coastguard Workerfunc (xi *interpolateExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
224*333d2b36SAndroid Build Coastguard Worker	for i := range xi.args {
225*333d2b36SAndroid Build Coastguard Worker		xi.args[i] = xi.args[i].transform(transformer)
226*333d2b36SAndroid Build Coastguard Worker	}
227*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(xi); replacement != nil {
228*333d2b36SAndroid Build Coastguard Worker		return replacement
229*333d2b36SAndroid Build Coastguard Worker	} else {
230*333d2b36SAndroid Build Coastguard Worker		return xi
231*333d2b36SAndroid Build Coastguard Worker	}
232*333d2b36SAndroid Build Coastguard Worker}
233*333d2b36SAndroid Build Coastguard Worker
234*333d2b36SAndroid Build Coastguard Workertype variableRefExpr struct {
235*333d2b36SAndroid Build Coastguard Worker	ref variable
236*333d2b36SAndroid Build Coastguard Worker}
237*333d2b36SAndroid Build Coastguard Worker
238*333d2b36SAndroid Build Coastguard Workerfunc NewVariableRefExpr(ref variable) starlarkExpr {
239*333d2b36SAndroid Build Coastguard Worker	if predefined, ok := ref.(*predefinedVariable); ok {
240*333d2b36SAndroid Build Coastguard Worker		return predefined.value
241*333d2b36SAndroid Build Coastguard Worker	}
242*333d2b36SAndroid Build Coastguard Worker	return &variableRefExpr{ref}
243*333d2b36SAndroid Build Coastguard Worker}
244*333d2b36SAndroid Build Coastguard Worker
245*333d2b36SAndroid Build Coastguard Workerfunc (v *variableRefExpr) emit(gctx *generationContext) {
246*333d2b36SAndroid Build Coastguard Worker	v.ref.emitGet(gctx)
247*333d2b36SAndroid Build Coastguard Worker}
248*333d2b36SAndroid Build Coastguard Worker
249*333d2b36SAndroid Build Coastguard Workerfunc (v *variableRefExpr) typ() starlarkType {
250*333d2b36SAndroid Build Coastguard Worker	return v.ref.valueType()
251*333d2b36SAndroid Build Coastguard Worker}
252*333d2b36SAndroid Build Coastguard Worker
253*333d2b36SAndroid Build Coastguard Workerfunc (v *variableRefExpr) emitListVarCopy(gctx *generationContext) {
254*333d2b36SAndroid Build Coastguard Worker	v.emit(gctx)
255*333d2b36SAndroid Build Coastguard Worker	if v.typ() == starlarkTypeList {
256*333d2b36SAndroid Build Coastguard Worker		gctx.write("[:]") // this will copy the list
257*333d2b36SAndroid Build Coastguard Worker	}
258*333d2b36SAndroid Build Coastguard Worker}
259*333d2b36SAndroid Build Coastguard Worker
260*333d2b36SAndroid Build Coastguard Workerfunc (v *variableRefExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
261*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(v); replacement != nil {
262*333d2b36SAndroid Build Coastguard Worker		return replacement
263*333d2b36SAndroid Build Coastguard Worker	} else {
264*333d2b36SAndroid Build Coastguard Worker		return v
265*333d2b36SAndroid Build Coastguard Worker	}
266*333d2b36SAndroid Build Coastguard Worker}
267*333d2b36SAndroid Build Coastguard Worker
268*333d2b36SAndroid Build Coastguard Workertype toStringExpr struct {
269*333d2b36SAndroid Build Coastguard Worker	expr starlarkExpr
270*333d2b36SAndroid Build Coastguard Worker}
271*333d2b36SAndroid Build Coastguard Worker
272*333d2b36SAndroid Build Coastguard Workerfunc (s *toStringExpr) emit(ctx *generationContext) {
273*333d2b36SAndroid Build Coastguard Worker	switch s.expr.typ() {
274*333d2b36SAndroid Build Coastguard Worker	case starlarkTypeString, starlarkTypeUnknown:
275*333d2b36SAndroid Build Coastguard Worker		// Assume unknown types are strings already.
276*333d2b36SAndroid Build Coastguard Worker		s.expr.emit(ctx)
277*333d2b36SAndroid Build Coastguard Worker	case starlarkTypeList:
278*333d2b36SAndroid Build Coastguard Worker		ctx.write(`" ".join(`)
279*333d2b36SAndroid Build Coastguard Worker		s.expr.emit(ctx)
280*333d2b36SAndroid Build Coastguard Worker		ctx.write(")")
281*333d2b36SAndroid Build Coastguard Worker	case starlarkTypeInt:
282*333d2b36SAndroid Build Coastguard Worker		ctx.write(`("%d" % (`)
283*333d2b36SAndroid Build Coastguard Worker		s.expr.emit(ctx)
284*333d2b36SAndroid Build Coastguard Worker		ctx.write("))")
285*333d2b36SAndroid Build Coastguard Worker	case starlarkTypeBool:
286*333d2b36SAndroid Build Coastguard Worker		ctx.write(`("true" if (`)
287*333d2b36SAndroid Build Coastguard Worker		s.expr.emit(ctx)
288*333d2b36SAndroid Build Coastguard Worker		ctx.write(`) else "")`)
289*333d2b36SAndroid Build Coastguard Worker	case starlarkTypeVoid:
290*333d2b36SAndroid Build Coastguard Worker		ctx.write(`""`)
291*333d2b36SAndroid Build Coastguard Worker	default:
292*333d2b36SAndroid Build Coastguard Worker		panic("Unknown starlark type!")
293*333d2b36SAndroid Build Coastguard Worker	}
294*333d2b36SAndroid Build Coastguard Worker}
295*333d2b36SAndroid Build Coastguard Worker
296*333d2b36SAndroid Build Coastguard Workerfunc (s *toStringExpr) typ() starlarkType {
297*333d2b36SAndroid Build Coastguard Worker	return starlarkTypeString
298*333d2b36SAndroid Build Coastguard Worker}
299*333d2b36SAndroid Build Coastguard Worker
300*333d2b36SAndroid Build Coastguard Workerfunc (s *toStringExpr) emitListVarCopy(gctx *generationContext) {
301*333d2b36SAndroid Build Coastguard Worker	s.emit(gctx)
302*333d2b36SAndroid Build Coastguard Worker}
303*333d2b36SAndroid Build Coastguard Worker
304*333d2b36SAndroid Build Coastguard Workerfunc (s *toStringExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
305*333d2b36SAndroid Build Coastguard Worker	s.expr = s.expr.transform(transformer)
306*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(s); replacement != nil {
307*333d2b36SAndroid Build Coastguard Worker		return replacement
308*333d2b36SAndroid Build Coastguard Worker	} else {
309*333d2b36SAndroid Build Coastguard Worker		return s
310*333d2b36SAndroid Build Coastguard Worker	}
311*333d2b36SAndroid Build Coastguard Worker}
312*333d2b36SAndroid Build Coastguard Worker
313*333d2b36SAndroid Build Coastguard Workertype notExpr struct {
314*333d2b36SAndroid Build Coastguard Worker	expr starlarkExpr
315*333d2b36SAndroid Build Coastguard Worker}
316*333d2b36SAndroid Build Coastguard Worker
317*333d2b36SAndroid Build Coastguard Workerfunc (n *notExpr) emit(ctx *generationContext) {
318*333d2b36SAndroid Build Coastguard Worker	ctx.write("not ")
319*333d2b36SAndroid Build Coastguard Worker	n.expr.emit(ctx)
320*333d2b36SAndroid Build Coastguard Worker}
321*333d2b36SAndroid Build Coastguard Worker
322*333d2b36SAndroid Build Coastguard Workerfunc (_ *notExpr) typ() starlarkType {
323*333d2b36SAndroid Build Coastguard Worker	return starlarkTypeBool
324*333d2b36SAndroid Build Coastguard Worker}
325*333d2b36SAndroid Build Coastguard Worker
326*333d2b36SAndroid Build Coastguard Workerfunc (n *notExpr) emitListVarCopy(gctx *generationContext) {
327*333d2b36SAndroid Build Coastguard Worker	n.emit(gctx)
328*333d2b36SAndroid Build Coastguard Worker}
329*333d2b36SAndroid Build Coastguard Worker
330*333d2b36SAndroid Build Coastguard Workerfunc (n *notExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
331*333d2b36SAndroid Build Coastguard Worker	n.expr = n.expr.transform(transformer)
332*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(n); replacement != nil {
333*333d2b36SAndroid Build Coastguard Worker		return replacement
334*333d2b36SAndroid Build Coastguard Worker	} else {
335*333d2b36SAndroid Build Coastguard Worker		return n
336*333d2b36SAndroid Build Coastguard Worker	}
337*333d2b36SAndroid Build Coastguard Worker}
338*333d2b36SAndroid Build Coastguard Worker
339*333d2b36SAndroid Build Coastguard Workertype eqExpr struct {
340*333d2b36SAndroid Build Coastguard Worker	left, right starlarkExpr
341*333d2b36SAndroid Build Coastguard Worker	isEq        bool // if false, it's !=
342*333d2b36SAndroid Build Coastguard Worker}
343*333d2b36SAndroid Build Coastguard Worker
344*333d2b36SAndroid Build Coastguard Workerfunc (eq *eqExpr) emit(gctx *generationContext) {
345*333d2b36SAndroid Build Coastguard Worker	if eq.left.typ() != eq.right.typ() {
346*333d2b36SAndroid Build Coastguard Worker		eq.left = &toStringExpr{expr: eq.left}
347*333d2b36SAndroid Build Coastguard Worker		eq.right = &toStringExpr{expr: eq.right}
348*333d2b36SAndroid Build Coastguard Worker	}
349*333d2b36SAndroid Build Coastguard Worker
350*333d2b36SAndroid Build Coastguard Worker	// General case
351*333d2b36SAndroid Build Coastguard Worker	eq.left.emit(gctx)
352*333d2b36SAndroid Build Coastguard Worker	if eq.isEq {
353*333d2b36SAndroid Build Coastguard Worker		gctx.write(" == ")
354*333d2b36SAndroid Build Coastguard Worker	} else {
355*333d2b36SAndroid Build Coastguard Worker		gctx.write(" != ")
356*333d2b36SAndroid Build Coastguard Worker	}
357*333d2b36SAndroid Build Coastguard Worker	eq.right.emit(gctx)
358*333d2b36SAndroid Build Coastguard Worker}
359*333d2b36SAndroid Build Coastguard Worker
360*333d2b36SAndroid Build Coastguard Workerfunc (_ *eqExpr) typ() starlarkType {
361*333d2b36SAndroid Build Coastguard Worker	return starlarkTypeBool
362*333d2b36SAndroid Build Coastguard Worker}
363*333d2b36SAndroid Build Coastguard Worker
364*333d2b36SAndroid Build Coastguard Workerfunc (eq *eqExpr) emitListVarCopy(gctx *generationContext) {
365*333d2b36SAndroid Build Coastguard Worker	eq.emit(gctx)
366*333d2b36SAndroid Build Coastguard Worker}
367*333d2b36SAndroid Build Coastguard Worker
368*333d2b36SAndroid Build Coastguard Workerfunc (eq *eqExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
369*333d2b36SAndroid Build Coastguard Worker	eq.left = eq.left.transform(transformer)
370*333d2b36SAndroid Build Coastguard Worker	eq.right = eq.right.transform(transformer)
371*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(eq); replacement != nil {
372*333d2b36SAndroid Build Coastguard Worker		return replacement
373*333d2b36SAndroid Build Coastguard Worker	} else {
374*333d2b36SAndroid Build Coastguard Worker		return eq
375*333d2b36SAndroid Build Coastguard Worker	}
376*333d2b36SAndroid Build Coastguard Worker}
377*333d2b36SAndroid Build Coastguard Worker
378*333d2b36SAndroid Build Coastguard Workertype listExpr struct {
379*333d2b36SAndroid Build Coastguard Worker	items []starlarkExpr
380*333d2b36SAndroid Build Coastguard Worker}
381*333d2b36SAndroid Build Coastguard Worker
382*333d2b36SAndroid Build Coastguard Workerfunc (l *listExpr) emit(gctx *generationContext) {
383*333d2b36SAndroid Build Coastguard Worker	if !gctx.inAssignment || len(l.items) < 2 {
384*333d2b36SAndroid Build Coastguard Worker		gctx.write("[")
385*333d2b36SAndroid Build Coastguard Worker		sep := ""
386*333d2b36SAndroid Build Coastguard Worker		for _, item := range l.items {
387*333d2b36SAndroid Build Coastguard Worker			gctx.write(sep)
388*333d2b36SAndroid Build Coastguard Worker			item.emit(gctx)
389*333d2b36SAndroid Build Coastguard Worker			sep = ", "
390*333d2b36SAndroid Build Coastguard Worker		}
391*333d2b36SAndroid Build Coastguard Worker		gctx.write("]")
392*333d2b36SAndroid Build Coastguard Worker		return
393*333d2b36SAndroid Build Coastguard Worker	}
394*333d2b36SAndroid Build Coastguard Worker
395*333d2b36SAndroid Build Coastguard Worker	gctx.write("[")
396*333d2b36SAndroid Build Coastguard Worker	gctx.indentLevel += 2
397*333d2b36SAndroid Build Coastguard Worker
398*333d2b36SAndroid Build Coastguard Worker	for _, item := range l.items {
399*333d2b36SAndroid Build Coastguard Worker		gctx.newLine()
400*333d2b36SAndroid Build Coastguard Worker		item.emit(gctx)
401*333d2b36SAndroid Build Coastguard Worker		gctx.write(",")
402*333d2b36SAndroid Build Coastguard Worker	}
403*333d2b36SAndroid Build Coastguard Worker	gctx.indentLevel -= 2
404*333d2b36SAndroid Build Coastguard Worker	gctx.newLine()
405*333d2b36SAndroid Build Coastguard Worker	gctx.write("]")
406*333d2b36SAndroid Build Coastguard Worker}
407*333d2b36SAndroid Build Coastguard Worker
408*333d2b36SAndroid Build Coastguard Workerfunc (_ *listExpr) typ() starlarkType {
409*333d2b36SAndroid Build Coastguard Worker	return starlarkTypeList
410*333d2b36SAndroid Build Coastguard Worker}
411*333d2b36SAndroid Build Coastguard Worker
412*333d2b36SAndroid Build Coastguard Workerfunc (l *listExpr) emitListVarCopy(gctx *generationContext) {
413*333d2b36SAndroid Build Coastguard Worker	l.emit(gctx)
414*333d2b36SAndroid Build Coastguard Worker}
415*333d2b36SAndroid Build Coastguard Worker
416*333d2b36SAndroid Build Coastguard Workerfunc (l *listExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
417*333d2b36SAndroid Build Coastguard Worker	itemsCopy := make([]starlarkExpr, len(l.items))
418*333d2b36SAndroid Build Coastguard Worker	for i, item := range l.items {
419*333d2b36SAndroid Build Coastguard Worker		itemsCopy[i] = item.transform(transformer)
420*333d2b36SAndroid Build Coastguard Worker	}
421*333d2b36SAndroid Build Coastguard Worker	l.items = itemsCopy
422*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(l); replacement != nil {
423*333d2b36SAndroid Build Coastguard Worker		return replacement
424*333d2b36SAndroid Build Coastguard Worker	} else {
425*333d2b36SAndroid Build Coastguard Worker		return l
426*333d2b36SAndroid Build Coastguard Worker	}
427*333d2b36SAndroid Build Coastguard Worker}
428*333d2b36SAndroid Build Coastguard Worker
429*333d2b36SAndroid Build Coastguard Workerfunc newStringListExpr(items []string) *listExpr {
430*333d2b36SAndroid Build Coastguard Worker	v := listExpr{}
431*333d2b36SAndroid Build Coastguard Worker	for _, item := range items {
432*333d2b36SAndroid Build Coastguard Worker		v.items = append(v.items, &stringLiteralExpr{item})
433*333d2b36SAndroid Build Coastguard Worker	}
434*333d2b36SAndroid Build Coastguard Worker	return &v
435*333d2b36SAndroid Build Coastguard Worker}
436*333d2b36SAndroid Build Coastguard Worker
437*333d2b36SAndroid Build Coastguard Worker// concatExpr generates expr1 + expr2 + ... + exprN in Starlark.
438*333d2b36SAndroid Build Coastguard Workertype concatExpr struct {
439*333d2b36SAndroid Build Coastguard Worker	items []starlarkExpr
440*333d2b36SAndroid Build Coastguard Worker}
441*333d2b36SAndroid Build Coastguard Worker
442*333d2b36SAndroid Build Coastguard Workerfunc (c *concatExpr) emit(gctx *generationContext) {
443*333d2b36SAndroid Build Coastguard Worker	if len(c.items) == 1 {
444*333d2b36SAndroid Build Coastguard Worker		c.items[0].emit(gctx)
445*333d2b36SAndroid Build Coastguard Worker		return
446*333d2b36SAndroid Build Coastguard Worker	}
447*333d2b36SAndroid Build Coastguard Worker
448*333d2b36SAndroid Build Coastguard Worker	if !gctx.inAssignment {
449*333d2b36SAndroid Build Coastguard Worker		c.items[0].emit(gctx)
450*333d2b36SAndroid Build Coastguard Worker		for _, item := range c.items[1:] {
451*333d2b36SAndroid Build Coastguard Worker			gctx.write(" + ")
452*333d2b36SAndroid Build Coastguard Worker			item.emit(gctx)
453*333d2b36SAndroid Build Coastguard Worker		}
454*333d2b36SAndroid Build Coastguard Worker		return
455*333d2b36SAndroid Build Coastguard Worker	}
456*333d2b36SAndroid Build Coastguard Worker	gctx.write("(")
457*333d2b36SAndroid Build Coastguard Worker	c.items[0].emit(gctx)
458*333d2b36SAndroid Build Coastguard Worker	gctx.indentLevel += 2
459*333d2b36SAndroid Build Coastguard Worker	for _, item := range c.items[1:] {
460*333d2b36SAndroid Build Coastguard Worker		gctx.write(" +")
461*333d2b36SAndroid Build Coastguard Worker		gctx.newLine()
462*333d2b36SAndroid Build Coastguard Worker		item.emit(gctx)
463*333d2b36SAndroid Build Coastguard Worker	}
464*333d2b36SAndroid Build Coastguard Worker	gctx.write(")")
465*333d2b36SAndroid Build Coastguard Worker	gctx.indentLevel -= 2
466*333d2b36SAndroid Build Coastguard Worker}
467*333d2b36SAndroid Build Coastguard Worker
468*333d2b36SAndroid Build Coastguard Workerfunc (_ *concatExpr) typ() starlarkType {
469*333d2b36SAndroid Build Coastguard Worker	return starlarkTypeList
470*333d2b36SAndroid Build Coastguard Worker}
471*333d2b36SAndroid Build Coastguard Worker
472*333d2b36SAndroid Build Coastguard Workerfunc (c *concatExpr) emitListVarCopy(gctx *generationContext) {
473*333d2b36SAndroid Build Coastguard Worker	c.emit(gctx)
474*333d2b36SAndroid Build Coastguard Worker}
475*333d2b36SAndroid Build Coastguard Worker
476*333d2b36SAndroid Build Coastguard Workerfunc (c *concatExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
477*333d2b36SAndroid Build Coastguard Worker	itemsCopy := make([]starlarkExpr, len(c.items))
478*333d2b36SAndroid Build Coastguard Worker	for i, item := range c.items {
479*333d2b36SAndroid Build Coastguard Worker		itemsCopy[i] = item.transform(transformer)
480*333d2b36SAndroid Build Coastguard Worker	}
481*333d2b36SAndroid Build Coastguard Worker	c.items = itemsCopy
482*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(c); replacement != nil {
483*333d2b36SAndroid Build Coastguard Worker		return replacement
484*333d2b36SAndroid Build Coastguard Worker	} else {
485*333d2b36SAndroid Build Coastguard Worker		return c
486*333d2b36SAndroid Build Coastguard Worker	}
487*333d2b36SAndroid Build Coastguard Worker}
488*333d2b36SAndroid Build Coastguard Worker
489*333d2b36SAndroid Build Coastguard Worker// inExpr generates <expr> [not] in <list>
490*333d2b36SAndroid Build Coastguard Workertype inExpr struct {
491*333d2b36SAndroid Build Coastguard Worker	expr  starlarkExpr
492*333d2b36SAndroid Build Coastguard Worker	list  starlarkExpr
493*333d2b36SAndroid Build Coastguard Worker	isNot bool
494*333d2b36SAndroid Build Coastguard Worker}
495*333d2b36SAndroid Build Coastguard Worker
496*333d2b36SAndroid Build Coastguard Workerfunc (i *inExpr) emit(gctx *generationContext) {
497*333d2b36SAndroid Build Coastguard Worker	i.expr.emit(gctx)
498*333d2b36SAndroid Build Coastguard Worker	if i.isNot {
499*333d2b36SAndroid Build Coastguard Worker		gctx.write(" not in ")
500*333d2b36SAndroid Build Coastguard Worker	} else {
501*333d2b36SAndroid Build Coastguard Worker		gctx.write(" in ")
502*333d2b36SAndroid Build Coastguard Worker	}
503*333d2b36SAndroid Build Coastguard Worker	i.list.emit(gctx)
504*333d2b36SAndroid Build Coastguard Worker}
505*333d2b36SAndroid Build Coastguard Worker
506*333d2b36SAndroid Build Coastguard Workerfunc (_ *inExpr) typ() starlarkType {
507*333d2b36SAndroid Build Coastguard Worker	return starlarkTypeBool
508*333d2b36SAndroid Build Coastguard Worker}
509*333d2b36SAndroid Build Coastguard Worker
510*333d2b36SAndroid Build Coastguard Workerfunc (i *inExpr) emitListVarCopy(gctx *generationContext) {
511*333d2b36SAndroid Build Coastguard Worker	i.emit(gctx)
512*333d2b36SAndroid Build Coastguard Worker}
513*333d2b36SAndroid Build Coastguard Worker
514*333d2b36SAndroid Build Coastguard Workerfunc (i *inExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
515*333d2b36SAndroid Build Coastguard Worker	i.expr = i.expr.transform(transformer)
516*333d2b36SAndroid Build Coastguard Worker	i.list = i.list.transform(transformer)
517*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(i); replacement != nil {
518*333d2b36SAndroid Build Coastguard Worker		return replacement
519*333d2b36SAndroid Build Coastguard Worker	} else {
520*333d2b36SAndroid Build Coastguard Worker		return i
521*333d2b36SAndroid Build Coastguard Worker	}
522*333d2b36SAndroid Build Coastguard Worker}
523*333d2b36SAndroid Build Coastguard Worker
524*333d2b36SAndroid Build Coastguard Workertype indexExpr struct {
525*333d2b36SAndroid Build Coastguard Worker	array starlarkExpr
526*333d2b36SAndroid Build Coastguard Worker	index starlarkExpr
527*333d2b36SAndroid Build Coastguard Worker}
528*333d2b36SAndroid Build Coastguard Worker
529*333d2b36SAndroid Build Coastguard Workerfunc (ix *indexExpr) emit(gctx *generationContext) {
530*333d2b36SAndroid Build Coastguard Worker	ix.array.emit(gctx)
531*333d2b36SAndroid Build Coastguard Worker	gctx.write("[")
532*333d2b36SAndroid Build Coastguard Worker	ix.index.emit(gctx)
533*333d2b36SAndroid Build Coastguard Worker	gctx.write("]")
534*333d2b36SAndroid Build Coastguard Worker}
535*333d2b36SAndroid Build Coastguard Worker
536*333d2b36SAndroid Build Coastguard Workerfunc (ix *indexExpr) typ() starlarkType {
537*333d2b36SAndroid Build Coastguard Worker	return starlarkTypeString
538*333d2b36SAndroid Build Coastguard Worker}
539*333d2b36SAndroid Build Coastguard Worker
540*333d2b36SAndroid Build Coastguard Workerfunc (ix *indexExpr) emitListVarCopy(gctx *generationContext) {
541*333d2b36SAndroid Build Coastguard Worker	ix.emit(gctx)
542*333d2b36SAndroid Build Coastguard Worker}
543*333d2b36SAndroid Build Coastguard Worker
544*333d2b36SAndroid Build Coastguard Workerfunc (ix *indexExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
545*333d2b36SAndroid Build Coastguard Worker	ix.array = ix.array.transform(transformer)
546*333d2b36SAndroid Build Coastguard Worker	ix.index = ix.index.transform(transformer)
547*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(ix); replacement != nil {
548*333d2b36SAndroid Build Coastguard Worker		return replacement
549*333d2b36SAndroid Build Coastguard Worker	} else {
550*333d2b36SAndroid Build Coastguard Worker		return ix
551*333d2b36SAndroid Build Coastguard Worker	}
552*333d2b36SAndroid Build Coastguard Worker}
553*333d2b36SAndroid Build Coastguard Worker
554*333d2b36SAndroid Build Coastguard Workertype callExpr struct {
555*333d2b36SAndroid Build Coastguard Worker	object     starlarkExpr // nil if static call
556*333d2b36SAndroid Build Coastguard Worker	name       string
557*333d2b36SAndroid Build Coastguard Worker	args       []starlarkExpr
558*333d2b36SAndroid Build Coastguard Worker	returnType starlarkType
559*333d2b36SAndroid Build Coastguard Worker}
560*333d2b36SAndroid Build Coastguard Worker
561*333d2b36SAndroid Build Coastguard Workerfunc (cx *callExpr) emit(gctx *generationContext) {
562*333d2b36SAndroid Build Coastguard Worker	if cx.object != nil {
563*333d2b36SAndroid Build Coastguard Worker		gctx.write("(")
564*333d2b36SAndroid Build Coastguard Worker		cx.object.emit(gctx)
565*333d2b36SAndroid Build Coastguard Worker		gctx.write(")")
566*333d2b36SAndroid Build Coastguard Worker		gctx.write(".", cx.name, "(")
567*333d2b36SAndroid Build Coastguard Worker	} else {
568*333d2b36SAndroid Build Coastguard Worker		gctx.write(cx.name, "(")
569*333d2b36SAndroid Build Coastguard Worker	}
570*333d2b36SAndroid Build Coastguard Worker	sep := ""
571*333d2b36SAndroid Build Coastguard Worker	for _, arg := range cx.args {
572*333d2b36SAndroid Build Coastguard Worker		gctx.write(sep)
573*333d2b36SAndroid Build Coastguard Worker		arg.emit(gctx)
574*333d2b36SAndroid Build Coastguard Worker		sep = ", "
575*333d2b36SAndroid Build Coastguard Worker	}
576*333d2b36SAndroid Build Coastguard Worker	gctx.write(")")
577*333d2b36SAndroid Build Coastguard Worker}
578*333d2b36SAndroid Build Coastguard Worker
579*333d2b36SAndroid Build Coastguard Workerfunc (cx *callExpr) typ() starlarkType {
580*333d2b36SAndroid Build Coastguard Worker	return cx.returnType
581*333d2b36SAndroid Build Coastguard Worker}
582*333d2b36SAndroid Build Coastguard Worker
583*333d2b36SAndroid Build Coastguard Workerfunc (cx *callExpr) emitListVarCopy(gctx *generationContext) {
584*333d2b36SAndroid Build Coastguard Worker	cx.emit(gctx)
585*333d2b36SAndroid Build Coastguard Worker}
586*333d2b36SAndroid Build Coastguard Worker
587*333d2b36SAndroid Build Coastguard Workerfunc (cx *callExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
588*333d2b36SAndroid Build Coastguard Worker	if cx.object != nil {
589*333d2b36SAndroid Build Coastguard Worker		cx.object = cx.object.transform(transformer)
590*333d2b36SAndroid Build Coastguard Worker	}
591*333d2b36SAndroid Build Coastguard Worker	for i := range cx.args {
592*333d2b36SAndroid Build Coastguard Worker		cx.args[i] = cx.args[i].transform(transformer)
593*333d2b36SAndroid Build Coastguard Worker	}
594*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(cx); replacement != nil {
595*333d2b36SAndroid Build Coastguard Worker		return replacement
596*333d2b36SAndroid Build Coastguard Worker	} else {
597*333d2b36SAndroid Build Coastguard Worker		return cx
598*333d2b36SAndroid Build Coastguard Worker	}
599*333d2b36SAndroid Build Coastguard Worker}
600*333d2b36SAndroid Build Coastguard Worker
601*333d2b36SAndroid Build Coastguard Workertype ifExpr struct {
602*333d2b36SAndroid Build Coastguard Worker	condition starlarkExpr
603*333d2b36SAndroid Build Coastguard Worker	ifTrue    starlarkExpr
604*333d2b36SAndroid Build Coastguard Worker	ifFalse   starlarkExpr
605*333d2b36SAndroid Build Coastguard Worker}
606*333d2b36SAndroid Build Coastguard Worker
607*333d2b36SAndroid Build Coastguard Workerfunc (i *ifExpr) emit(gctx *generationContext) {
608*333d2b36SAndroid Build Coastguard Worker	gctx.write("(")
609*333d2b36SAndroid Build Coastguard Worker	i.ifTrue.emit(gctx)
610*333d2b36SAndroid Build Coastguard Worker	gctx.write(" if ")
611*333d2b36SAndroid Build Coastguard Worker	i.condition.emit(gctx)
612*333d2b36SAndroid Build Coastguard Worker	gctx.write(" else ")
613*333d2b36SAndroid Build Coastguard Worker	i.ifFalse.emit(gctx)
614*333d2b36SAndroid Build Coastguard Worker	gctx.write(")")
615*333d2b36SAndroid Build Coastguard Worker}
616*333d2b36SAndroid Build Coastguard Worker
617*333d2b36SAndroid Build Coastguard Workerfunc (i *ifExpr) typ() starlarkType {
618*333d2b36SAndroid Build Coastguard Worker	tType := i.ifTrue.typ()
619*333d2b36SAndroid Build Coastguard Worker	fType := i.ifFalse.typ()
620*333d2b36SAndroid Build Coastguard Worker	if tType != fType && tType != starlarkTypeUnknown && fType != starlarkTypeUnknown {
621*333d2b36SAndroid Build Coastguard Worker		panic("Conflicting types in if expression")
622*333d2b36SAndroid Build Coastguard Worker	}
623*333d2b36SAndroid Build Coastguard Worker	if tType != starlarkTypeUnknown {
624*333d2b36SAndroid Build Coastguard Worker		return tType
625*333d2b36SAndroid Build Coastguard Worker	} else {
626*333d2b36SAndroid Build Coastguard Worker		return fType
627*333d2b36SAndroid Build Coastguard Worker	}
628*333d2b36SAndroid Build Coastguard Worker}
629*333d2b36SAndroid Build Coastguard Worker
630*333d2b36SAndroid Build Coastguard Workerfunc (i *ifExpr) emitListVarCopy(gctx *generationContext) {
631*333d2b36SAndroid Build Coastguard Worker	i.emit(gctx)
632*333d2b36SAndroid Build Coastguard Worker}
633*333d2b36SAndroid Build Coastguard Worker
634*333d2b36SAndroid Build Coastguard Workerfunc (i *ifExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
635*333d2b36SAndroid Build Coastguard Worker	i.condition = i.condition.transform(transformer)
636*333d2b36SAndroid Build Coastguard Worker	i.ifTrue = i.ifTrue.transform(transformer)
637*333d2b36SAndroid Build Coastguard Worker	i.ifFalse = i.ifFalse.transform(transformer)
638*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(i); replacement != nil {
639*333d2b36SAndroid Build Coastguard Worker		return replacement
640*333d2b36SAndroid Build Coastguard Worker	} else {
641*333d2b36SAndroid Build Coastguard Worker		return i
642*333d2b36SAndroid Build Coastguard Worker	}
643*333d2b36SAndroid Build Coastguard Worker}
644*333d2b36SAndroid Build Coastguard Worker
645*333d2b36SAndroid Build Coastguard Workertype identifierExpr struct {
646*333d2b36SAndroid Build Coastguard Worker	name string
647*333d2b36SAndroid Build Coastguard Worker}
648*333d2b36SAndroid Build Coastguard Worker
649*333d2b36SAndroid Build Coastguard Workerfunc (i *identifierExpr) emit(gctx *generationContext) {
650*333d2b36SAndroid Build Coastguard Worker	gctx.write(i.name)
651*333d2b36SAndroid Build Coastguard Worker}
652*333d2b36SAndroid Build Coastguard Worker
653*333d2b36SAndroid Build Coastguard Workerfunc (i *identifierExpr) typ() starlarkType {
654*333d2b36SAndroid Build Coastguard Worker	return starlarkTypeUnknown
655*333d2b36SAndroid Build Coastguard Worker}
656*333d2b36SAndroid Build Coastguard Worker
657*333d2b36SAndroid Build Coastguard Workerfunc (i *identifierExpr) emitListVarCopy(gctx *generationContext) {
658*333d2b36SAndroid Build Coastguard Worker	i.emit(gctx)
659*333d2b36SAndroid Build Coastguard Worker}
660*333d2b36SAndroid Build Coastguard Worker
661*333d2b36SAndroid Build Coastguard Workerfunc (i *identifierExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
662*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(i); replacement != nil {
663*333d2b36SAndroid Build Coastguard Worker		return replacement
664*333d2b36SAndroid Build Coastguard Worker	} else {
665*333d2b36SAndroid Build Coastguard Worker		return i
666*333d2b36SAndroid Build Coastguard Worker	}
667*333d2b36SAndroid Build Coastguard Worker}
668*333d2b36SAndroid Build Coastguard Worker
669*333d2b36SAndroid Build Coastguard Workertype foreachExpr struct {
670*333d2b36SAndroid Build Coastguard Worker	varName string
671*333d2b36SAndroid Build Coastguard Worker	list    starlarkExpr
672*333d2b36SAndroid Build Coastguard Worker	action  starlarkExpr
673*333d2b36SAndroid Build Coastguard Worker}
674*333d2b36SAndroid Build Coastguard Worker
675*333d2b36SAndroid Build Coastguard Workerfunc (f *foreachExpr) emit(gctx *generationContext) {
676*333d2b36SAndroid Build Coastguard Worker	gctx.write("[")
677*333d2b36SAndroid Build Coastguard Worker	f.action.emit(gctx)
678*333d2b36SAndroid Build Coastguard Worker	gctx.write(" for " + f.varName + " in ")
679*333d2b36SAndroid Build Coastguard Worker	f.list.emit(gctx)
680*333d2b36SAndroid Build Coastguard Worker	gctx.write("]")
681*333d2b36SAndroid Build Coastguard Worker}
682*333d2b36SAndroid Build Coastguard Worker
683*333d2b36SAndroid Build Coastguard Workerfunc (f *foreachExpr) typ() starlarkType {
684*333d2b36SAndroid Build Coastguard Worker	return starlarkTypeList
685*333d2b36SAndroid Build Coastguard Worker}
686*333d2b36SAndroid Build Coastguard Worker
687*333d2b36SAndroid Build Coastguard Workerfunc (f *foreachExpr) emitListVarCopy(gctx *generationContext) {
688*333d2b36SAndroid Build Coastguard Worker	f.emit(gctx)
689*333d2b36SAndroid Build Coastguard Worker}
690*333d2b36SAndroid Build Coastguard Worker
691*333d2b36SAndroid Build Coastguard Workerfunc (f *foreachExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
692*333d2b36SAndroid Build Coastguard Worker	f.list = f.list.transform(transformer)
693*333d2b36SAndroid Build Coastguard Worker	f.action = f.action.transform(transformer)
694*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(f); replacement != nil {
695*333d2b36SAndroid Build Coastguard Worker		return replacement
696*333d2b36SAndroid Build Coastguard Worker	} else {
697*333d2b36SAndroid Build Coastguard Worker		return f
698*333d2b36SAndroid Build Coastguard Worker	}
699*333d2b36SAndroid Build Coastguard Worker}
700*333d2b36SAndroid Build Coastguard Worker
701*333d2b36SAndroid Build Coastguard Workertype binaryOpExpr struct {
702*333d2b36SAndroid Build Coastguard Worker	left, right starlarkExpr
703*333d2b36SAndroid Build Coastguard Worker	op          string
704*333d2b36SAndroid Build Coastguard Worker	returnType  starlarkType
705*333d2b36SAndroid Build Coastguard Worker}
706*333d2b36SAndroid Build Coastguard Worker
707*333d2b36SAndroid Build Coastguard Workerfunc (b *binaryOpExpr) emit(gctx *generationContext) {
708*333d2b36SAndroid Build Coastguard Worker	b.left.emit(gctx)
709*333d2b36SAndroid Build Coastguard Worker	gctx.write(" " + b.op + " ")
710*333d2b36SAndroid Build Coastguard Worker	b.right.emit(gctx)
711*333d2b36SAndroid Build Coastguard Worker}
712*333d2b36SAndroid Build Coastguard Worker
713*333d2b36SAndroid Build Coastguard Workerfunc (b *binaryOpExpr) typ() starlarkType {
714*333d2b36SAndroid Build Coastguard Worker	return b.returnType
715*333d2b36SAndroid Build Coastguard Worker}
716*333d2b36SAndroid Build Coastguard Worker
717*333d2b36SAndroid Build Coastguard Workerfunc (b *binaryOpExpr) emitListVarCopy(gctx *generationContext) {
718*333d2b36SAndroid Build Coastguard Worker	b.emit(gctx)
719*333d2b36SAndroid Build Coastguard Worker}
720*333d2b36SAndroid Build Coastguard Worker
721*333d2b36SAndroid Build Coastguard Workerfunc (b *binaryOpExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
722*333d2b36SAndroid Build Coastguard Worker	b.left = b.left.transform(transformer)
723*333d2b36SAndroid Build Coastguard Worker	b.right = b.right.transform(transformer)
724*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(b); replacement != nil {
725*333d2b36SAndroid Build Coastguard Worker		return replacement
726*333d2b36SAndroid Build Coastguard Worker	} else {
727*333d2b36SAndroid Build Coastguard Worker		return b
728*333d2b36SAndroid Build Coastguard Worker	}
729*333d2b36SAndroid Build Coastguard Worker}
730*333d2b36SAndroid Build Coastguard Worker
731*333d2b36SAndroid Build Coastguard Workertype badExpr struct {
732*333d2b36SAndroid Build Coastguard Worker	errorLocation ErrorLocation
733*333d2b36SAndroid Build Coastguard Worker	message       string
734*333d2b36SAndroid Build Coastguard Worker}
735*333d2b36SAndroid Build Coastguard Worker
736*333d2b36SAndroid Build Coastguard Workerfunc (b *badExpr) emit(gctx *generationContext) {
737*333d2b36SAndroid Build Coastguard Worker	gctx.emitConversionError(b.errorLocation, b.message)
738*333d2b36SAndroid Build Coastguard Worker}
739*333d2b36SAndroid Build Coastguard Worker
740*333d2b36SAndroid Build Coastguard Workerfunc (_ *badExpr) typ() starlarkType {
741*333d2b36SAndroid Build Coastguard Worker	return starlarkTypeUnknown
742*333d2b36SAndroid Build Coastguard Worker}
743*333d2b36SAndroid Build Coastguard Worker
744*333d2b36SAndroid Build Coastguard Workerfunc (b *badExpr) emitListVarCopy(gctx *generationContext) {
745*333d2b36SAndroid Build Coastguard Worker	b.emit(gctx)
746*333d2b36SAndroid Build Coastguard Worker}
747*333d2b36SAndroid Build Coastguard Worker
748*333d2b36SAndroid Build Coastguard Workerfunc (b *badExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
749*333d2b36SAndroid Build Coastguard Worker	if replacement := transformer(b); replacement != nil {
750*333d2b36SAndroid Build Coastguard Worker		return replacement
751*333d2b36SAndroid Build Coastguard Worker	} else {
752*333d2b36SAndroid Build Coastguard Worker		return b
753*333d2b36SAndroid Build Coastguard Worker	}
754*333d2b36SAndroid Build Coastguard Worker}
755*333d2b36SAndroid Build Coastguard Worker
756*333d2b36SAndroid Build Coastguard Workerfunc maybeConvertToStringList(expr starlarkExpr) starlarkExpr {
757*333d2b36SAndroid Build Coastguard Worker	if xString, ok := expr.(*stringLiteralExpr); ok {
758*333d2b36SAndroid Build Coastguard Worker		return newStringListExpr(strings.Fields(xString.literal))
759*333d2b36SAndroid Build Coastguard Worker	}
760*333d2b36SAndroid Build Coastguard Worker	return expr
761*333d2b36SAndroid Build Coastguard Worker}
762*333d2b36SAndroid Build Coastguard Worker
763*333d2b36SAndroid Build Coastguard Workerfunc isEmptyString(expr starlarkExpr) bool {
764*333d2b36SAndroid Build Coastguard Worker	x, ok := expr.(*stringLiteralExpr)
765*333d2b36SAndroid Build Coastguard Worker	return ok && x.literal == ""
766*333d2b36SAndroid Build Coastguard Worker}
767*333d2b36SAndroid Build Coastguard Worker
768*333d2b36SAndroid Build Coastguard Workerfunc negateExpr(expr starlarkExpr) starlarkExpr {
769*333d2b36SAndroid Build Coastguard Worker	switch typedExpr := expr.(type) {
770*333d2b36SAndroid Build Coastguard Worker	case *notExpr:
771*333d2b36SAndroid Build Coastguard Worker		return typedExpr.expr
772*333d2b36SAndroid Build Coastguard Worker	case *inExpr:
773*333d2b36SAndroid Build Coastguard Worker		typedExpr.isNot = !typedExpr.isNot
774*333d2b36SAndroid Build Coastguard Worker		return typedExpr
775*333d2b36SAndroid Build Coastguard Worker	case *eqExpr:
776*333d2b36SAndroid Build Coastguard Worker		typedExpr.isEq = !typedExpr.isEq
777*333d2b36SAndroid Build Coastguard Worker		return typedExpr
778*333d2b36SAndroid Build Coastguard Worker	case *binaryOpExpr:
779*333d2b36SAndroid Build Coastguard Worker		switch typedExpr.op {
780*333d2b36SAndroid Build Coastguard Worker		case ">":
781*333d2b36SAndroid Build Coastguard Worker			typedExpr.op = "<="
782*333d2b36SAndroid Build Coastguard Worker			return typedExpr
783*333d2b36SAndroid Build Coastguard Worker		case "<":
784*333d2b36SAndroid Build Coastguard Worker			typedExpr.op = ">="
785*333d2b36SAndroid Build Coastguard Worker			return typedExpr
786*333d2b36SAndroid Build Coastguard Worker		case ">=":
787*333d2b36SAndroid Build Coastguard Worker			typedExpr.op = "<"
788*333d2b36SAndroid Build Coastguard Worker			return typedExpr
789*333d2b36SAndroid Build Coastguard Worker		case "<=":
790*333d2b36SAndroid Build Coastguard Worker			typedExpr.op = ">"
791*333d2b36SAndroid Build Coastguard Worker			return typedExpr
792*333d2b36SAndroid Build Coastguard Worker		default:
793*333d2b36SAndroid Build Coastguard Worker			return &notExpr{expr: expr}
794*333d2b36SAndroid Build Coastguard Worker		}
795*333d2b36SAndroid Build Coastguard Worker	default:
796*333d2b36SAndroid Build Coastguard Worker		return &notExpr{expr: expr}
797*333d2b36SAndroid Build Coastguard Worker	}
798*333d2b36SAndroid Build Coastguard Worker}
799