blob: a01abd8ace825ecf275375952ba039573cc743aa [file] [log] [blame]
Sasha Smundakb051c4e2020-11-05 20:45:07 -08001// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package mk2rbc
16
17import (
18 "fmt"
19 "strings"
20
21 mkparser "android/soong/androidmk/parser"
22)
23
24// A parsed node for which starlark code will be generated
25// by calling emit().
26type starlarkNode interface {
27 emit(ctx *generationContext)
28}
29
30// Types used to keep processed makefile data:
31type commentNode struct {
32 text string
33}
34
35func (c *commentNode) emit(gctx *generationContext) {
36 chunks := strings.Split(c.text, "\\\n")
37 gctx.newLine()
38 gctx.write(chunks[0]) // It has '#' at the beginning already.
39 for _, chunk := range chunks[1:] {
40 gctx.newLine()
41 gctx.write("#", chunk)
42 }
43}
44
Sasha Smundak6609ba72021-07-22 18:32:56 -070045type moduleInfo struct {
Sasha Smundakb051c4e2020-11-05 20:45:07 -080046 path string // Converted Starlark file path
47 originalPath string // Makefile file path
Sasha Smundakb051c4e2020-11-05 20:45:07 -080048 moduleLocalName string
Sasha Smundak6609ba72021-07-22 18:32:56 -070049 optional bool
Sasha Smundak6bc132a2022-01-10 17:02:16 -080050 missing bool // a module may not exist if a module that depends on it is loaded dynamically
Sasha Smundakb051c4e2020-11-05 20:45:07 -080051}
52
Sasha Smundak6609ba72021-07-22 18:32:56 -070053func (im moduleInfo) entryName() string {
Sasha Smundakb051c4e2020-11-05 20:45:07 -080054 return im.moduleLocalName + "_init"
55}
56
Sasha Smundak845cb292022-01-18 10:31:14 -080057func (mi moduleInfo) name() string {
58 return fmt.Sprintf("%q", MakePath2ModuleName(mi.originalPath))
59}
60
Sasha Smundak6609ba72021-07-22 18:32:56 -070061type inheritedModule interface {
62 name() string
63 entryName() string
64 emitSelect(gctx *generationContext)
Sasha Smundak6bc132a2022-01-10 17:02:16 -080065 pathExpr() starlarkExpr
66 needsLoadCheck() bool
Sasha Smundak6609ba72021-07-22 18:32:56 -070067}
68
69type inheritedStaticModule struct {
70 *moduleInfo
71 loadAlways bool
72}
73
Sasha Smundak6609ba72021-07-22 18:32:56 -070074func (im inheritedStaticModule) emitSelect(_ *generationContext) {
75}
76
Sasha Smundak6bc132a2022-01-10 17:02:16 -080077func (im inheritedStaticModule) pathExpr() starlarkExpr {
78 return &stringLiteralExpr{im.path}
79}
80
81func (im inheritedStaticModule) needsLoadCheck() bool {
82 return im.missing
Sasha Smundak6609ba72021-07-22 18:32:56 -070083}
84
85type inheritedDynamicModule struct {
Cole Faust9df1d732022-04-26 16:27:22 -070086 path starlarkExpr
Sasha Smundak6609ba72021-07-22 18:32:56 -070087 candidateModules []*moduleInfo
88 loadAlways bool
Cole Faust069aba62022-01-26 17:47:33 -080089 location ErrorLocation
90 needsWarning bool
Sasha Smundak6609ba72021-07-22 18:32:56 -070091}
92
93func (i inheritedDynamicModule) name() string {
94 return "_varmod"
95}
96
97func (i inheritedDynamicModule) entryName() string {
98 return i.name() + "_init"
99}
100
101func (i inheritedDynamicModule) emitSelect(gctx *generationContext) {
Cole Faust069aba62022-01-26 17:47:33 -0800102 if i.needsWarning {
103 gctx.newLine()
Cole Faustf4e72cf2022-02-08 12:49:37 -0800104 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.")
Cole Faust069aba62022-01-26 17:47:33 -0800105 }
Sasha Smundak6609ba72021-07-22 18:32:56 -0700106 gctx.newLine()
107 gctx.writef("_entry = {")
108 gctx.indentLevel++
109 for _, mi := range i.candidateModules {
110 gctx.newLine()
Sasha Smundak845cb292022-01-18 10:31:14 -0800111 gctx.writef(`"%s": (%s, %s),`, mi.originalPath, mi.name(), mi.entryName())
Sasha Smundak6609ba72021-07-22 18:32:56 -0700112 }
113 gctx.indentLevel--
114 gctx.newLine()
115 gctx.write("}.get(")
116 i.path.emit(gctx)
117 gctx.write(")")
118 gctx.newLine()
119 gctx.writef("(%s, %s) = _entry if _entry else (None, None)", i.name(), i.entryName())
Sasha Smundak6609ba72021-07-22 18:32:56 -0700120}
121
Sasha Smundak6bc132a2022-01-10 17:02:16 -0800122func (i inheritedDynamicModule) pathExpr() starlarkExpr {
Cole Faust9df1d732022-04-26 16:27:22 -0700123 return i.path
Sasha Smundak6bc132a2022-01-10 17:02:16 -0800124}
125
126func (i inheritedDynamicModule) needsLoadCheck() bool {
127 return true
Sasha Smundak6609ba72021-07-22 18:32:56 -0700128}
129
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800130type inheritNode struct {
Sasha Smundak868c5e32021-09-23 16:20:58 -0700131 module inheritedModule
132 loadAlways bool
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800133}
134
135func (inn *inheritNode) emit(gctx *generationContext) {
136 // Unconditional case:
Sasha Smundak6bc132a2022-01-10 17:02:16 -0800137 // maybe check that loaded
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800138 // rblf.inherit(handle, <module>, module_init)
139 // Conditional case:
140 // if <module>_init != None:
141 // same as above
Sasha Smundak6609ba72021-07-22 18:32:56 -0700142 inn.module.emitSelect(gctx)
Sasha Smundak6609ba72021-07-22 18:32:56 -0700143 name := inn.module.name()
144 entry := inn.module.entryName()
Sasha Smundak868c5e32021-09-23 16:20:58 -0700145 if inn.loadAlways {
Sasha Smundak6bc132a2022-01-10 17:02:16 -0800146 gctx.emitLoadCheck(inn.module)
147 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700148 gctx.writef("%s(handle, %s, %s)", cfnInherit, name, entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800149 return
150 }
Sasha Smundak6609ba72021-07-22 18:32:56 -0700151
Sasha Smundak6bc132a2022-01-10 17:02:16 -0800152 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700153 gctx.writef("if %s:", entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800154 gctx.indentLevel++
155 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700156 gctx.writef("%s(handle, %s, %s)", cfnInherit, name, entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800157 gctx.indentLevel--
158}
159
160type includeNode struct {
Sasha Smundak868c5e32021-09-23 16:20:58 -0700161 module inheritedModule
162 loadAlways bool
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800163}
164
165func (inn *includeNode) emit(gctx *generationContext) {
Sasha Smundak6609ba72021-07-22 18:32:56 -0700166 inn.module.emitSelect(gctx)
167 entry := inn.module.entryName()
Sasha Smundak868c5e32021-09-23 16:20:58 -0700168 if inn.loadAlways {
Sasha Smundak6bc132a2022-01-10 17:02:16 -0800169 gctx.emitLoadCheck(inn.module)
170 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700171 gctx.writef("%s(g, handle)", entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800172 return
173 }
Sasha Smundak6609ba72021-07-22 18:32:56 -0700174
Sasha Smundak6bc132a2022-01-10 17:02:16 -0800175 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700176 gctx.writef("if %s != None:", entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800177 gctx.indentLevel++
178 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700179 gctx.writef("%s(g, handle)", entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800180 gctx.indentLevel--
181}
182
183type assignmentFlavor int
184
185const (
186 // Assignment flavors
Cole Fauste2a37982022-03-09 16:00:17 -0800187 asgnSet assignmentFlavor = iota // := or =
188 asgnMaybeSet assignmentFlavor = iota // ?=
189 asgnAppend assignmentFlavor = iota // +=
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800190)
191
192type assignmentNode struct {
193 lhs variable
194 value starlarkExpr
195 mkValue *mkparser.MakeString
196 flavor assignmentFlavor
Sasha Smundak422b6142021-11-11 18:31:59 -0800197 location ErrorLocation
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800198 isTraced bool
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800199}
200
201func (asgn *assignmentNode) emit(gctx *generationContext) {
202 gctx.newLine()
203 gctx.inAssignment = true
204 asgn.lhs.emitSet(gctx, asgn)
205 gctx.inAssignment = false
206
207 if asgn.isTraced {
208 gctx.newLine()
209 gctx.tracedCount++
210 gctx.writef(`print("%s.%d: %s := ", `, gctx.starScript.mkFile, gctx.tracedCount, asgn.lhs.name())
Cole Faustf0632662022-04-07 13:59:24 -0700211 asgn.lhs.emitGet(gctx)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800212 gctx.writef(")")
213 }
214}
215
Cole Fauste2a37982022-03-09 16:00:17 -0800216func (asgn *assignmentNode) isSelfReferential() bool {
217 if asgn.flavor == asgnAppend {
218 return true
219 }
220 isSelfReferential := false
221 asgn.value.transform(func(expr starlarkExpr) starlarkExpr {
222 if ref, ok := expr.(*variableRefExpr); ok && ref.ref.name() == asgn.lhs.name() {
223 isSelfReferential = true
224 }
225 return nil
226 })
227 return isSelfReferential
228}
229
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800230type exprNode struct {
231 expr starlarkExpr
232}
233
234func (exn *exprNode) emit(gctx *generationContext) {
235 gctx.newLine()
236 exn.expr.emit(gctx)
237}
238
239type ifNode struct {
240 isElif bool // true if this is 'elif' statement
241 expr starlarkExpr
242}
243
244func (in *ifNode) emit(gctx *generationContext) {
245 ifElif := "if "
246 if in.isElif {
247 ifElif = "elif "
248 }
249
250 gctx.newLine()
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800251 gctx.write(ifElif)
252 in.expr.emit(gctx)
253 gctx.write(":")
254}
255
256type elseNode struct{}
257
258func (br *elseNode) emit(gctx *generationContext) {
259 gctx.newLine()
260 gctx.write("else:")
261}
262
263// switchCase represents as single if/elseif/else branch. All the necessary
264// info about flavor (if/elseif/else) is supposed to be kept in `gate`.
265type switchCase struct {
266 gate starlarkNode
267 nodes []starlarkNode
268}
269
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800270func (cb *switchCase) emit(gctx *generationContext) {
271 cb.gate.emit(gctx)
272 gctx.indentLevel++
Cole Faustf0632662022-04-07 13:59:24 -0700273 gctx.pushVariableAssignments()
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800274 hasStatements := false
Cole Faustdd569ae2022-01-31 15:48:29 -0800275 for _, node := range cb.nodes {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800276 if _, ok := node.(*commentNode); !ok {
277 hasStatements = true
278 }
279 node.emit(gctx)
280 }
Cole Faustdd569ae2022-01-31 15:48:29 -0800281 if !hasStatements {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800282 gctx.emitPass()
283 }
284 gctx.indentLevel--
Cole Faustf0632662022-04-07 13:59:24 -0700285 gctx.popVariableAssignments()
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800286}
287
288// A single complete if ... elseif ... else ... endif sequences
289type switchNode struct {
290 ssCases []*switchCase
291}
292
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800293func (ssw *switchNode) emit(gctx *generationContext) {
Cole Faustdd569ae2022-01-31 15:48:29 -0800294 for _, ssCase := range ssw.ssCases {
295 ssCase.emit(gctx)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800296 }
297}
Cole Faustf035d402022-03-28 14:02:50 -0700298
299type foreachNode struct {
300 varName string
301 list starlarkExpr
302 actions []starlarkNode
303}
304
305func (f *foreachNode) emit(gctx *generationContext) {
Cole Faustf0632662022-04-07 13:59:24 -0700306 gctx.pushVariableAssignments()
Cole Faustf035d402022-03-28 14:02:50 -0700307 gctx.newLine()
308 gctx.writef("for %s in ", f.varName)
309 f.list.emit(gctx)
310 gctx.write(":")
311 gctx.indentLevel++
312 hasStatements := false
313 for _, a := range f.actions {
314 if _, ok := a.(*commentNode); !ok {
315 hasStatements = true
316 }
317 a.emit(gctx)
318 }
319 if !hasStatements {
320 gctx.emitPass()
321 }
322 gctx.indentLevel--
Cole Faustf0632662022-04-07 13:59:24 -0700323 gctx.popVariableAssignments()
Cole Faustf035d402022-03-28 14:02:50 -0700324}