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 mkparser "android/soong/androidmk/parser" 22*333d2b36SAndroid Build Coastguard Worker) 23*333d2b36SAndroid Build Coastguard Worker 24*333d2b36SAndroid Build Coastguard Worker// A parsed node for which starlark code will be generated 25*333d2b36SAndroid Build Coastguard Worker// by calling emit(). 26*333d2b36SAndroid Build Coastguard Workertype starlarkNode interface { 27*333d2b36SAndroid Build Coastguard Worker emit(ctx *generationContext) 28*333d2b36SAndroid Build Coastguard Worker} 29*333d2b36SAndroid Build Coastguard Worker 30*333d2b36SAndroid Build Coastguard Worker// Types used to keep processed makefile data: 31*333d2b36SAndroid Build Coastguard Workertype commentNode struct { 32*333d2b36SAndroid Build Coastguard Worker text string 33*333d2b36SAndroid Build Coastguard Worker} 34*333d2b36SAndroid Build Coastguard Worker 35*333d2b36SAndroid Build Coastguard Workerfunc (c *commentNode) emit(gctx *generationContext) { 36*333d2b36SAndroid Build Coastguard Worker chunks := strings.Split(c.text, "\\\n") 37*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 38*333d2b36SAndroid Build Coastguard Worker gctx.write(chunks[0]) // It has '#' at the beginning already. 39*333d2b36SAndroid Build Coastguard Worker for _, chunk := range chunks[1:] { 40*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 41*333d2b36SAndroid Build Coastguard Worker gctx.write("#", chunk) 42*333d2b36SAndroid Build Coastguard Worker } 43*333d2b36SAndroid Build Coastguard Worker} 44*333d2b36SAndroid Build Coastguard Worker 45*333d2b36SAndroid Build Coastguard Workertype moduleInfo struct { 46*333d2b36SAndroid Build Coastguard Worker path string // Converted Starlark file path 47*333d2b36SAndroid Build Coastguard Worker originalPath string // Makefile file path 48*333d2b36SAndroid Build Coastguard Worker moduleLocalName string 49*333d2b36SAndroid Build Coastguard Worker optional bool 50*333d2b36SAndroid Build Coastguard Worker missing bool // a module may not exist if a module that depends on it is loaded dynamically 51*333d2b36SAndroid Build Coastguard Worker} 52*333d2b36SAndroid Build Coastguard Worker 53*333d2b36SAndroid Build Coastguard Workerfunc (im moduleInfo) entryName() string { 54*333d2b36SAndroid Build Coastguard Worker return im.moduleLocalName + "_init" 55*333d2b36SAndroid Build Coastguard Worker} 56*333d2b36SAndroid Build Coastguard Worker 57*333d2b36SAndroid Build Coastguard Workerfunc (mi moduleInfo) name() string { 58*333d2b36SAndroid Build Coastguard Worker return fmt.Sprintf("%q", MakePath2ModuleName(mi.originalPath)) 59*333d2b36SAndroid Build Coastguard Worker} 60*333d2b36SAndroid Build Coastguard Worker 61*333d2b36SAndroid Build Coastguard Workertype inheritedModule interface { 62*333d2b36SAndroid Build Coastguard Worker name() string 63*333d2b36SAndroid Build Coastguard Worker entryName() string 64*333d2b36SAndroid Build Coastguard Worker emitSelect(gctx *generationContext) 65*333d2b36SAndroid Build Coastguard Worker pathExpr() starlarkExpr 66*333d2b36SAndroid Build Coastguard Worker needsLoadCheck() bool 67*333d2b36SAndroid Build Coastguard Worker} 68*333d2b36SAndroid Build Coastguard Worker 69*333d2b36SAndroid Build Coastguard Workertype inheritedStaticModule struct { 70*333d2b36SAndroid Build Coastguard Worker *moduleInfo 71*333d2b36SAndroid Build Coastguard Worker loadAlways bool 72*333d2b36SAndroid Build Coastguard Worker} 73*333d2b36SAndroid Build Coastguard Worker 74*333d2b36SAndroid Build Coastguard Workerfunc (im inheritedStaticModule) emitSelect(_ *generationContext) { 75*333d2b36SAndroid Build Coastguard Worker} 76*333d2b36SAndroid Build Coastguard Worker 77*333d2b36SAndroid Build Coastguard Workerfunc (im inheritedStaticModule) pathExpr() starlarkExpr { 78*333d2b36SAndroid Build Coastguard Worker return &stringLiteralExpr{im.path} 79*333d2b36SAndroid Build Coastguard Worker} 80*333d2b36SAndroid Build Coastguard Worker 81*333d2b36SAndroid Build Coastguard Workerfunc (im inheritedStaticModule) needsLoadCheck() bool { 82*333d2b36SAndroid Build Coastguard Worker return im.missing 83*333d2b36SAndroid Build Coastguard Worker} 84*333d2b36SAndroid Build Coastguard Worker 85*333d2b36SAndroid Build Coastguard Workertype inheritedDynamicModule struct { 86*333d2b36SAndroid Build Coastguard Worker path starlarkExpr 87*333d2b36SAndroid Build Coastguard Worker candidateModules []*moduleInfo 88*333d2b36SAndroid Build Coastguard Worker loadAlways bool 89*333d2b36SAndroid Build Coastguard Worker location ErrorLocation 90*333d2b36SAndroid Build Coastguard Worker needsWarning bool 91*333d2b36SAndroid Build Coastguard Worker} 92*333d2b36SAndroid Build Coastguard Worker 93*333d2b36SAndroid Build Coastguard Workerfunc (i inheritedDynamicModule) name() string { 94*333d2b36SAndroid Build Coastguard Worker return "_varmod" 95*333d2b36SAndroid Build Coastguard Worker} 96*333d2b36SAndroid Build Coastguard Worker 97*333d2b36SAndroid Build Coastguard Workerfunc (i inheritedDynamicModule) entryName() string { 98*333d2b36SAndroid Build Coastguard Worker return i.name() + "_init" 99*333d2b36SAndroid Build Coastguard Worker} 100*333d2b36SAndroid Build Coastguard Worker 101*333d2b36SAndroid Build Coastguard Workerfunc (i inheritedDynamicModule) emitSelect(gctx *generationContext) { 102*333d2b36SAndroid Build Coastguard Worker if i.needsWarning { 103*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 104*333d2b36SAndroid Build Coastguard Worker gctx.writef("%s.mkwarning(%q, %q)", baseName, i.location, "Please avoid starting an include path with a variable. See https://source.android.com/setup/build/bazel/product_config/issues/includes for details.") 105*333d2b36SAndroid Build Coastguard Worker } 106*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 107*333d2b36SAndroid Build Coastguard Worker gctx.writef("_entry = {") 108*333d2b36SAndroid Build Coastguard Worker gctx.indentLevel++ 109*333d2b36SAndroid Build Coastguard Worker for _, mi := range i.candidateModules { 110*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 111*333d2b36SAndroid Build Coastguard Worker gctx.writef(`"%s": (%s, %s),`, mi.originalPath, mi.name(), mi.entryName()) 112*333d2b36SAndroid Build Coastguard Worker } 113*333d2b36SAndroid Build Coastguard Worker gctx.indentLevel-- 114*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 115*333d2b36SAndroid Build Coastguard Worker gctx.write("}.get(") 116*333d2b36SAndroid Build Coastguard Worker i.path.emit(gctx) 117*333d2b36SAndroid Build Coastguard Worker gctx.write(")") 118*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 119*333d2b36SAndroid Build Coastguard Worker gctx.writef("(%s, %s) = _entry if _entry else (None, None)", i.name(), i.entryName()) 120*333d2b36SAndroid Build Coastguard Worker} 121*333d2b36SAndroid Build Coastguard Worker 122*333d2b36SAndroid Build Coastguard Workerfunc (i inheritedDynamicModule) pathExpr() starlarkExpr { 123*333d2b36SAndroid Build Coastguard Worker return i.path 124*333d2b36SAndroid Build Coastguard Worker} 125*333d2b36SAndroid Build Coastguard Worker 126*333d2b36SAndroid Build Coastguard Workerfunc (i inheritedDynamicModule) needsLoadCheck() bool { 127*333d2b36SAndroid Build Coastguard Worker return true 128*333d2b36SAndroid Build Coastguard Worker} 129*333d2b36SAndroid Build Coastguard Worker 130*333d2b36SAndroid Build Coastguard Workertype inheritNode struct { 131*333d2b36SAndroid Build Coastguard Worker module inheritedModule 132*333d2b36SAndroid Build Coastguard Worker loadAlways bool 133*333d2b36SAndroid Build Coastguard Worker} 134*333d2b36SAndroid Build Coastguard Worker 135*333d2b36SAndroid Build Coastguard Workerfunc (inn *inheritNode) emit(gctx *generationContext) { 136*333d2b36SAndroid Build Coastguard Worker // Unconditional case: 137*333d2b36SAndroid Build Coastguard Worker // maybe check that loaded 138*333d2b36SAndroid Build Coastguard Worker // rblf.inherit(handle, <module>, module_init) 139*333d2b36SAndroid Build Coastguard Worker // Conditional case: 140*333d2b36SAndroid Build Coastguard Worker // if <module>_init != None: 141*333d2b36SAndroid Build Coastguard Worker // same as above 142*333d2b36SAndroid Build Coastguard Worker inn.module.emitSelect(gctx) 143*333d2b36SAndroid Build Coastguard Worker name := inn.module.name() 144*333d2b36SAndroid Build Coastguard Worker entry := inn.module.entryName() 145*333d2b36SAndroid Build Coastguard Worker if inn.loadAlways { 146*333d2b36SAndroid Build Coastguard Worker gctx.emitLoadCheck(inn.module) 147*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 148*333d2b36SAndroid Build Coastguard Worker gctx.writef("%s(handle, %s, %s)", cfnInherit, name, entry) 149*333d2b36SAndroid Build Coastguard Worker return 150*333d2b36SAndroid Build Coastguard Worker } 151*333d2b36SAndroid Build Coastguard Worker 152*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 153*333d2b36SAndroid Build Coastguard Worker gctx.writef("if %s:", entry) 154*333d2b36SAndroid Build Coastguard Worker gctx.indentLevel++ 155*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 156*333d2b36SAndroid Build Coastguard Worker gctx.writef("%s(handle, %s, %s)", cfnInherit, name, entry) 157*333d2b36SAndroid Build Coastguard Worker gctx.indentLevel-- 158*333d2b36SAndroid Build Coastguard Worker} 159*333d2b36SAndroid Build Coastguard Worker 160*333d2b36SAndroid Build Coastguard Workertype includeNode struct { 161*333d2b36SAndroid Build Coastguard Worker module inheritedModule 162*333d2b36SAndroid Build Coastguard Worker loadAlways bool 163*333d2b36SAndroid Build Coastguard Worker} 164*333d2b36SAndroid Build Coastguard Worker 165*333d2b36SAndroid Build Coastguard Workerfunc (inn *includeNode) emit(gctx *generationContext) { 166*333d2b36SAndroid Build Coastguard Worker inn.module.emitSelect(gctx) 167*333d2b36SAndroid Build Coastguard Worker entry := inn.module.entryName() 168*333d2b36SAndroid Build Coastguard Worker if inn.loadAlways { 169*333d2b36SAndroid Build Coastguard Worker gctx.emitLoadCheck(inn.module) 170*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 171*333d2b36SAndroid Build Coastguard Worker gctx.writef("%s(g, handle)", entry) 172*333d2b36SAndroid Build Coastguard Worker return 173*333d2b36SAndroid Build Coastguard Worker } 174*333d2b36SAndroid Build Coastguard Worker 175*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 176*333d2b36SAndroid Build Coastguard Worker gctx.writef("if %s != None:", entry) 177*333d2b36SAndroid Build Coastguard Worker gctx.indentLevel++ 178*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 179*333d2b36SAndroid Build Coastguard Worker gctx.writef("%s(g, handle)", entry) 180*333d2b36SAndroid Build Coastguard Worker gctx.indentLevel-- 181*333d2b36SAndroid Build Coastguard Worker} 182*333d2b36SAndroid Build Coastguard Worker 183*333d2b36SAndroid Build Coastguard Workertype assignmentFlavor int 184*333d2b36SAndroid Build Coastguard Worker 185*333d2b36SAndroid Build Coastguard Workerconst ( 186*333d2b36SAndroid Build Coastguard Worker // Assignment flavors 187*333d2b36SAndroid Build Coastguard Worker asgnSet assignmentFlavor = iota // := or = 188*333d2b36SAndroid Build Coastguard Worker asgnMaybeSet assignmentFlavor = iota // ?= 189*333d2b36SAndroid Build Coastguard Worker asgnAppend assignmentFlavor = iota // += 190*333d2b36SAndroid Build Coastguard Worker) 191*333d2b36SAndroid Build Coastguard Worker 192*333d2b36SAndroid Build Coastguard Workertype assignmentNode struct { 193*333d2b36SAndroid Build Coastguard Worker lhs variable 194*333d2b36SAndroid Build Coastguard Worker value starlarkExpr 195*333d2b36SAndroid Build Coastguard Worker mkValue *mkparser.MakeString 196*333d2b36SAndroid Build Coastguard Worker flavor assignmentFlavor 197*333d2b36SAndroid Build Coastguard Worker location ErrorLocation 198*333d2b36SAndroid Build Coastguard Worker isTraced bool 199*333d2b36SAndroid Build Coastguard Worker} 200*333d2b36SAndroid Build Coastguard Worker 201*333d2b36SAndroid Build Coastguard Workerfunc (asgn *assignmentNode) emit(gctx *generationContext) { 202*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 203*333d2b36SAndroid Build Coastguard Worker gctx.inAssignment = true 204*333d2b36SAndroid Build Coastguard Worker asgn.lhs.emitSet(gctx, asgn) 205*333d2b36SAndroid Build Coastguard Worker gctx.inAssignment = false 206*333d2b36SAndroid Build Coastguard Worker 207*333d2b36SAndroid Build Coastguard Worker if asgn.isTraced { 208*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 209*333d2b36SAndroid Build Coastguard Worker gctx.tracedCount++ 210*333d2b36SAndroid Build Coastguard Worker gctx.writef(`print("%s.%d: %s := ", `, gctx.starScript.mkFile, gctx.tracedCount, asgn.lhs.name()) 211*333d2b36SAndroid Build Coastguard Worker asgn.lhs.emitGet(gctx) 212*333d2b36SAndroid Build Coastguard Worker gctx.writef(")") 213*333d2b36SAndroid Build Coastguard Worker } 214*333d2b36SAndroid Build Coastguard Worker} 215*333d2b36SAndroid Build Coastguard Worker 216*333d2b36SAndroid Build Coastguard Workerfunc (asgn *assignmentNode) isSelfReferential() bool { 217*333d2b36SAndroid Build Coastguard Worker if asgn.flavor == asgnAppend { 218*333d2b36SAndroid Build Coastguard Worker return true 219*333d2b36SAndroid Build Coastguard Worker } 220*333d2b36SAndroid Build Coastguard Worker isSelfReferential := false 221*333d2b36SAndroid Build Coastguard Worker asgn.value.transform(func(expr starlarkExpr) starlarkExpr { 222*333d2b36SAndroid Build Coastguard Worker if ref, ok := expr.(*variableRefExpr); ok && ref.ref.name() == asgn.lhs.name() { 223*333d2b36SAndroid Build Coastguard Worker isSelfReferential = true 224*333d2b36SAndroid Build Coastguard Worker } 225*333d2b36SAndroid Build Coastguard Worker return nil 226*333d2b36SAndroid Build Coastguard Worker }) 227*333d2b36SAndroid Build Coastguard Worker return isSelfReferential 228*333d2b36SAndroid Build Coastguard Worker} 229*333d2b36SAndroid Build Coastguard Worker 230*333d2b36SAndroid Build Coastguard Workertype exprNode struct { 231*333d2b36SAndroid Build Coastguard Worker expr starlarkExpr 232*333d2b36SAndroid Build Coastguard Worker} 233*333d2b36SAndroid Build Coastguard Worker 234*333d2b36SAndroid Build Coastguard Workerfunc (exn *exprNode) emit(gctx *generationContext) { 235*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 236*333d2b36SAndroid Build Coastguard Worker exn.expr.emit(gctx) 237*333d2b36SAndroid Build Coastguard Worker} 238*333d2b36SAndroid Build Coastguard Worker 239*333d2b36SAndroid Build Coastguard Workertype ifNode struct { 240*333d2b36SAndroid Build Coastguard Worker isElif bool // true if this is 'elif' statement 241*333d2b36SAndroid Build Coastguard Worker expr starlarkExpr 242*333d2b36SAndroid Build Coastguard Worker} 243*333d2b36SAndroid Build Coastguard Worker 244*333d2b36SAndroid Build Coastguard Workerfunc (in *ifNode) emit(gctx *generationContext) { 245*333d2b36SAndroid Build Coastguard Worker ifElif := "if " 246*333d2b36SAndroid Build Coastguard Worker if in.isElif { 247*333d2b36SAndroid Build Coastguard Worker ifElif = "elif " 248*333d2b36SAndroid Build Coastguard Worker } 249*333d2b36SAndroid Build Coastguard Worker 250*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 251*333d2b36SAndroid Build Coastguard Worker gctx.write(ifElif) 252*333d2b36SAndroid Build Coastguard Worker in.expr.emit(gctx) 253*333d2b36SAndroid Build Coastguard Worker gctx.write(":") 254*333d2b36SAndroid Build Coastguard Worker} 255*333d2b36SAndroid Build Coastguard Worker 256*333d2b36SAndroid Build Coastguard Workertype elseNode struct{} 257*333d2b36SAndroid Build Coastguard Worker 258*333d2b36SAndroid Build Coastguard Workerfunc (br *elseNode) emit(gctx *generationContext) { 259*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 260*333d2b36SAndroid Build Coastguard Worker gctx.write("else:") 261*333d2b36SAndroid Build Coastguard Worker} 262*333d2b36SAndroid Build Coastguard Worker 263*333d2b36SAndroid Build Coastguard Worker// switchCase represents as single if/elseif/else branch. All the necessary 264*333d2b36SAndroid Build Coastguard Worker// info about flavor (if/elseif/else) is supposed to be kept in `gate`. 265*333d2b36SAndroid Build Coastguard Workertype switchCase struct { 266*333d2b36SAndroid Build Coastguard Worker gate starlarkNode 267*333d2b36SAndroid Build Coastguard Worker nodes []starlarkNode 268*333d2b36SAndroid Build Coastguard Worker} 269*333d2b36SAndroid Build Coastguard Worker 270*333d2b36SAndroid Build Coastguard Workerfunc (cb *switchCase) emit(gctx *generationContext) { 271*333d2b36SAndroid Build Coastguard Worker cb.gate.emit(gctx) 272*333d2b36SAndroid Build Coastguard Worker gctx.indentLevel++ 273*333d2b36SAndroid Build Coastguard Worker gctx.pushVariableAssignments() 274*333d2b36SAndroid Build Coastguard Worker hasStatements := false 275*333d2b36SAndroid Build Coastguard Worker for _, node := range cb.nodes { 276*333d2b36SAndroid Build Coastguard Worker if _, ok := node.(*commentNode); !ok { 277*333d2b36SAndroid Build Coastguard Worker hasStatements = true 278*333d2b36SAndroid Build Coastguard Worker } 279*333d2b36SAndroid Build Coastguard Worker node.emit(gctx) 280*333d2b36SAndroid Build Coastguard Worker } 281*333d2b36SAndroid Build Coastguard Worker if !hasStatements { 282*333d2b36SAndroid Build Coastguard Worker gctx.emitPass() 283*333d2b36SAndroid Build Coastguard Worker } 284*333d2b36SAndroid Build Coastguard Worker gctx.indentLevel-- 285*333d2b36SAndroid Build Coastguard Worker gctx.popVariableAssignments() 286*333d2b36SAndroid Build Coastguard Worker} 287*333d2b36SAndroid Build Coastguard Worker 288*333d2b36SAndroid Build Coastguard Worker// A single complete if ... elseif ... else ... endif sequences 289*333d2b36SAndroid Build Coastguard Workertype switchNode struct { 290*333d2b36SAndroid Build Coastguard Worker ssCases []*switchCase 291*333d2b36SAndroid Build Coastguard Worker} 292*333d2b36SAndroid Build Coastguard Worker 293*333d2b36SAndroid Build Coastguard Workerfunc (ssw *switchNode) emit(gctx *generationContext) { 294*333d2b36SAndroid Build Coastguard Worker for _, ssCase := range ssw.ssCases { 295*333d2b36SAndroid Build Coastguard Worker ssCase.emit(gctx) 296*333d2b36SAndroid Build Coastguard Worker } 297*333d2b36SAndroid Build Coastguard Worker} 298*333d2b36SAndroid Build Coastguard Worker 299*333d2b36SAndroid Build Coastguard Workertype foreachNode struct { 300*333d2b36SAndroid Build Coastguard Worker varName string 301*333d2b36SAndroid Build Coastguard Worker list starlarkExpr 302*333d2b36SAndroid Build Coastguard Worker actions []starlarkNode 303*333d2b36SAndroid Build Coastguard Worker} 304*333d2b36SAndroid Build Coastguard Worker 305*333d2b36SAndroid Build Coastguard Workerfunc (f *foreachNode) emit(gctx *generationContext) { 306*333d2b36SAndroid Build Coastguard Worker gctx.pushVariableAssignments() 307*333d2b36SAndroid Build Coastguard Worker gctx.newLine() 308*333d2b36SAndroid Build Coastguard Worker gctx.writef("for %s in ", f.varName) 309*333d2b36SAndroid Build Coastguard Worker f.list.emit(gctx) 310*333d2b36SAndroid Build Coastguard Worker gctx.write(":") 311*333d2b36SAndroid Build Coastguard Worker gctx.indentLevel++ 312*333d2b36SAndroid Build Coastguard Worker hasStatements := false 313*333d2b36SAndroid Build Coastguard Worker for _, a := range f.actions { 314*333d2b36SAndroid Build Coastguard Worker if _, ok := a.(*commentNode); !ok { 315*333d2b36SAndroid Build Coastguard Worker hasStatements = true 316*333d2b36SAndroid Build Coastguard Worker } 317*333d2b36SAndroid Build Coastguard Worker a.emit(gctx) 318*333d2b36SAndroid Build Coastguard Worker } 319*333d2b36SAndroid Build Coastguard Worker if !hasStatements { 320*333d2b36SAndroid Build Coastguard Worker gctx.emitPass() 321*333d2b36SAndroid Build Coastguard Worker } 322*333d2b36SAndroid Build Coastguard Worker gctx.indentLevel-- 323*333d2b36SAndroid Build Coastguard Worker gctx.popVariableAssignments() 324*333d2b36SAndroid Build Coastguard Worker} 325