blob: dea4dc84bb3f0cddde2383afe061013bccacd922 [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 {
86 path interpolateExpr
87 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()
104 gctx.writef("%s.mkwarning(%q, %q)", baseName, i.location, "Including a path with a non-constant prefix, please convert this to a simple literal to generate cleaner starlark.")
105 }
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 {
123 return &i.path
124}
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
187 asgnSet assignmentFlavor = iota // := or =
188 asgnMaybeSet assignmentFlavor = iota // ?= and variable may be unset
189 asgnAppend assignmentFlavor = iota // += and variable has been set before
190 asgnMaybeAppend assignmentFlavor = iota // += and variable may be unset
191)
192
193type assignmentNode struct {
194 lhs variable
195 value starlarkExpr
196 mkValue *mkparser.MakeString
197 flavor assignmentFlavor
Sasha Smundak422b6142021-11-11 18:31:59 -0800198 location ErrorLocation
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800199 isTraced bool
200 previous *assignmentNode
201}
202
203func (asgn *assignmentNode) emit(gctx *generationContext) {
204 gctx.newLine()
205 gctx.inAssignment = true
206 asgn.lhs.emitSet(gctx, asgn)
207 gctx.inAssignment = false
208
209 if asgn.isTraced {
210 gctx.newLine()
211 gctx.tracedCount++
212 gctx.writef(`print("%s.%d: %s := ", `, gctx.starScript.mkFile, gctx.tracedCount, asgn.lhs.name())
213 asgn.lhs.emitGet(gctx, true)
214 gctx.writef(")")
215 }
216}
217
218type exprNode struct {
219 expr starlarkExpr
220}
221
222func (exn *exprNode) emit(gctx *generationContext) {
223 gctx.newLine()
224 exn.expr.emit(gctx)
225}
226
227type ifNode struct {
228 isElif bool // true if this is 'elif' statement
229 expr starlarkExpr
230}
231
232func (in *ifNode) emit(gctx *generationContext) {
233 ifElif := "if "
234 if in.isElif {
235 ifElif = "elif "
236 }
237
238 gctx.newLine()
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800239 gctx.write(ifElif)
240 in.expr.emit(gctx)
241 gctx.write(":")
242}
243
244type elseNode struct{}
245
246func (br *elseNode) emit(gctx *generationContext) {
247 gctx.newLine()
248 gctx.write("else:")
249}
250
251// switchCase represents as single if/elseif/else branch. All the necessary
252// info about flavor (if/elseif/else) is supposed to be kept in `gate`.
253type switchCase struct {
254 gate starlarkNode
255 nodes []starlarkNode
256}
257
258func (cb *switchCase) newNode(node starlarkNode) {
259 cb.nodes = append(cb.nodes, node)
260}
261
262func (cb *switchCase) emit(gctx *generationContext) {
263 cb.gate.emit(gctx)
264 gctx.indentLevel++
265 hasStatements := false
266 emitNode := func(node starlarkNode) {
267 if _, ok := node.(*commentNode); !ok {
268 hasStatements = true
269 }
270 node.emit(gctx)
271 }
272 if len(cb.nodes) > 0 {
273 emitNode(cb.nodes[0])
274 for _, node := range cb.nodes[1:] {
275 emitNode(node)
276 }
277 if !hasStatements {
278 gctx.emitPass()
279 }
280 } else {
281 gctx.emitPass()
282 }
283 gctx.indentLevel--
284}
285
286// A single complete if ... elseif ... else ... endif sequences
287type switchNode struct {
288 ssCases []*switchCase
289}
290
291func (ssw *switchNode) newNode(node starlarkNode) {
292 switch br := node.(type) {
293 case *switchCase:
294 ssw.ssCases = append(ssw.ssCases, br)
295 default:
296 panic(fmt.Errorf("expected switchCase node, got %t", br))
297 }
298}
299
300func (ssw *switchNode) emit(gctx *generationContext) {
301 if len(ssw.ssCases) == 0 {
302 gctx.emitPass()
303 } else {
304 ssw.ssCases[0].emit(gctx)
305 for _, ssCase := range ssw.ssCases[1:] {
306 ssCase.emit(gctx)
307 }
308 }
309}