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 ¬Expr{expr: expr} 794*333d2b36SAndroid Build Coastguard Worker } 795*333d2b36SAndroid Build Coastguard Worker default: 796*333d2b36SAndroid Build Coastguard Worker return ¬Expr{expr: expr} 797*333d2b36SAndroid Build Coastguard Worker } 798*333d2b36SAndroid Build Coastguard Worker} 799