blob: 333a8da17072cccd497557f4e39bcc08a2ea8bdb [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 Smundak6609ba72021-07-22 18:32:56 -070057type inheritedModule interface {
58 name() string
59 entryName() string
60 emitSelect(gctx *generationContext)
Sasha Smundak6bc132a2022-01-10 17:02:16 -080061 pathExpr() starlarkExpr
62 needsLoadCheck() bool
Sasha Smundak6609ba72021-07-22 18:32:56 -070063}
64
65type inheritedStaticModule struct {
66 *moduleInfo
67 loadAlways bool
68}
69
70func (im inheritedStaticModule) name() string {
71 return fmt.Sprintf("%q", MakePath2ModuleName(im.originalPath))
72}
73
74func (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
89}
90
91func (i inheritedDynamicModule) name() string {
92 return "_varmod"
93}
94
95func (i inheritedDynamicModule) entryName() string {
96 return i.name() + "_init"
97}
98
99func (i inheritedDynamicModule) emitSelect(gctx *generationContext) {
100 gctx.newLine()
101 gctx.writef("_entry = {")
102 gctx.indentLevel++
103 for _, mi := range i.candidateModules {
104 gctx.newLine()
105 gctx.writef(`"%s": (%q, %s),`, mi.originalPath, mi.moduleLocalName, mi.entryName())
106 }
107 gctx.indentLevel--
108 gctx.newLine()
109 gctx.write("}.get(")
110 i.path.emit(gctx)
111 gctx.write(")")
112 gctx.newLine()
113 gctx.writef("(%s, %s) = _entry if _entry else (None, None)", i.name(), i.entryName())
Sasha Smundak6609ba72021-07-22 18:32:56 -0700114}
115
Sasha Smundak6bc132a2022-01-10 17:02:16 -0800116func (i inheritedDynamicModule) pathExpr() starlarkExpr {
117 return &i.path
118}
119
120func (i inheritedDynamicModule) needsLoadCheck() bool {
121 return true
Sasha Smundak6609ba72021-07-22 18:32:56 -0700122}
123
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800124type inheritNode struct {
Sasha Smundak868c5e32021-09-23 16:20:58 -0700125 module inheritedModule
126 loadAlways bool
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800127}
128
129func (inn *inheritNode) emit(gctx *generationContext) {
130 // Unconditional case:
Sasha Smundak6bc132a2022-01-10 17:02:16 -0800131 // maybe check that loaded
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800132 // rblf.inherit(handle, <module>, module_init)
133 // Conditional case:
134 // if <module>_init != None:
135 // same as above
Sasha Smundak6609ba72021-07-22 18:32:56 -0700136 inn.module.emitSelect(gctx)
Sasha Smundak6609ba72021-07-22 18:32:56 -0700137 name := inn.module.name()
138 entry := inn.module.entryName()
Sasha Smundak868c5e32021-09-23 16:20:58 -0700139 if inn.loadAlways {
Sasha Smundak6bc132a2022-01-10 17:02:16 -0800140 gctx.emitLoadCheck(inn.module)
141 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700142 gctx.writef("%s(handle, %s, %s)", cfnInherit, name, entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800143 return
144 }
Sasha Smundak6609ba72021-07-22 18:32:56 -0700145
Sasha Smundak6bc132a2022-01-10 17:02:16 -0800146 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700147 gctx.writef("if %s:", entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800148 gctx.indentLevel++
149 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700150 gctx.writef("%s(handle, %s, %s)", cfnInherit, name, entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800151 gctx.indentLevel--
152}
153
154type includeNode struct {
Sasha Smundak868c5e32021-09-23 16:20:58 -0700155 module inheritedModule
156 loadAlways bool
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800157}
158
159func (inn *includeNode) emit(gctx *generationContext) {
Sasha Smundak6609ba72021-07-22 18:32:56 -0700160 inn.module.emitSelect(gctx)
161 entry := inn.module.entryName()
Sasha Smundak868c5e32021-09-23 16:20:58 -0700162 if inn.loadAlways {
Sasha Smundak6bc132a2022-01-10 17:02:16 -0800163 gctx.emitLoadCheck(inn.module)
164 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700165 gctx.writef("%s(g, handle)", entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800166 return
167 }
Sasha Smundak6609ba72021-07-22 18:32:56 -0700168
Sasha Smundak6bc132a2022-01-10 17:02:16 -0800169 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700170 gctx.writef("if %s != None:", entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800171 gctx.indentLevel++
172 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700173 gctx.writef("%s(g, handle)", entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800174 gctx.indentLevel--
175}
176
177type assignmentFlavor int
178
179const (
180 // Assignment flavors
181 asgnSet assignmentFlavor = iota // := or =
182 asgnMaybeSet assignmentFlavor = iota // ?= and variable may be unset
183 asgnAppend assignmentFlavor = iota // += and variable has been set before
184 asgnMaybeAppend assignmentFlavor = iota // += and variable may be unset
185)
186
187type assignmentNode struct {
188 lhs variable
189 value starlarkExpr
190 mkValue *mkparser.MakeString
191 flavor assignmentFlavor
Sasha Smundak422b6142021-11-11 18:31:59 -0800192 location ErrorLocation
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800193 isTraced bool
194 previous *assignmentNode
195}
196
197func (asgn *assignmentNode) emit(gctx *generationContext) {
198 gctx.newLine()
199 gctx.inAssignment = true
200 asgn.lhs.emitSet(gctx, asgn)
201 gctx.inAssignment = false
202
203 if asgn.isTraced {
204 gctx.newLine()
205 gctx.tracedCount++
206 gctx.writef(`print("%s.%d: %s := ", `, gctx.starScript.mkFile, gctx.tracedCount, asgn.lhs.name())
207 asgn.lhs.emitGet(gctx, true)
208 gctx.writef(")")
209 }
210}
211
212type exprNode struct {
213 expr starlarkExpr
214}
215
216func (exn *exprNode) emit(gctx *generationContext) {
217 gctx.newLine()
218 exn.expr.emit(gctx)
219}
220
221type ifNode struct {
222 isElif bool // true if this is 'elif' statement
223 expr starlarkExpr
224}
225
226func (in *ifNode) emit(gctx *generationContext) {
227 ifElif := "if "
228 if in.isElif {
229 ifElif = "elif "
230 }
231
232 gctx.newLine()
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800233 gctx.write(ifElif)
234 in.expr.emit(gctx)
235 gctx.write(":")
236}
237
238type elseNode struct{}
239
240func (br *elseNode) emit(gctx *generationContext) {
241 gctx.newLine()
242 gctx.write("else:")
243}
244
245// switchCase represents as single if/elseif/else branch. All the necessary
246// info about flavor (if/elseif/else) is supposed to be kept in `gate`.
247type switchCase struct {
248 gate starlarkNode
249 nodes []starlarkNode
250}
251
252func (cb *switchCase) newNode(node starlarkNode) {
253 cb.nodes = append(cb.nodes, node)
254}
255
256func (cb *switchCase) emit(gctx *generationContext) {
257 cb.gate.emit(gctx)
258 gctx.indentLevel++
259 hasStatements := false
260 emitNode := func(node starlarkNode) {
261 if _, ok := node.(*commentNode); !ok {
262 hasStatements = true
263 }
264 node.emit(gctx)
265 }
266 if len(cb.nodes) > 0 {
267 emitNode(cb.nodes[0])
268 for _, node := range cb.nodes[1:] {
269 emitNode(node)
270 }
271 if !hasStatements {
272 gctx.emitPass()
273 }
274 } else {
275 gctx.emitPass()
276 }
277 gctx.indentLevel--
278}
279
280// A single complete if ... elseif ... else ... endif sequences
281type switchNode struct {
282 ssCases []*switchCase
283}
284
285func (ssw *switchNode) newNode(node starlarkNode) {
286 switch br := node.(type) {
287 case *switchCase:
288 ssw.ssCases = append(ssw.ssCases, br)
289 default:
290 panic(fmt.Errorf("expected switchCase node, got %t", br))
291 }
292}
293
294func (ssw *switchNode) emit(gctx *generationContext) {
295 if len(ssw.ssCases) == 0 {
296 gctx.emitPass()
297 } else {
298 ssw.ssCases[0].emit(gctx)
299 for _, ssCase := range ssw.ssCases[1:] {
300 ssCase.emit(gctx)
301 }
302 }
303}