blob: 3fe1a17e639235501411dca70aef3b8065da0a17 [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 Smundakb051c4e2020-11-05 20:45:07 -080050}
51
Sasha Smundak6609ba72021-07-22 18:32:56 -070052func (im moduleInfo) entryName() string {
Sasha Smundakb051c4e2020-11-05 20:45:07 -080053 return im.moduleLocalName + "_init"
54}
55
Sasha Smundak6609ba72021-07-22 18:32:56 -070056type inheritedModule interface {
57 name() string
58 entryName() string
59 emitSelect(gctx *generationContext)
Sasha Smundak868c5e32021-09-23 16:20:58 -070060 shouldExist() bool
Sasha Smundak6609ba72021-07-22 18:32:56 -070061}
62
63type inheritedStaticModule struct {
64 *moduleInfo
65 loadAlways bool
66}
67
68func (im inheritedStaticModule) name() string {
69 return fmt.Sprintf("%q", MakePath2ModuleName(im.originalPath))
70}
71
72func (im inheritedStaticModule) emitSelect(_ *generationContext) {
73}
74
Sasha Smundak868c5e32021-09-23 16:20:58 -070075func (im inheritedStaticModule) shouldExist() bool {
Sasha Smundak6609ba72021-07-22 18:32:56 -070076 return im.loadAlways
77}
78
79type inheritedDynamicModule struct {
80 path interpolateExpr
81 candidateModules []*moduleInfo
82 loadAlways bool
83}
84
85func (i inheritedDynamicModule) name() string {
86 return "_varmod"
87}
88
89func (i inheritedDynamicModule) entryName() string {
90 return i.name() + "_init"
91}
92
93func (i inheritedDynamicModule) emitSelect(gctx *generationContext) {
94 gctx.newLine()
95 gctx.writef("_entry = {")
96 gctx.indentLevel++
97 for _, mi := range i.candidateModules {
98 gctx.newLine()
99 gctx.writef(`"%s": (%q, %s),`, mi.originalPath, mi.moduleLocalName, mi.entryName())
100 }
101 gctx.indentLevel--
102 gctx.newLine()
103 gctx.write("}.get(")
104 i.path.emit(gctx)
105 gctx.write(")")
106 gctx.newLine()
107 gctx.writef("(%s, %s) = _entry if _entry else (None, None)", i.name(), i.entryName())
108 if i.loadAlways {
109 gctx.newLine()
110 gctx.writef("if not %s:", i.entryName())
111 gctx.indentLevel++
112 gctx.newLine()
113 gctx.write(`rblf.mkerror("cannot")`)
114 gctx.indentLevel--
115 }
116}
117
Sasha Smundak868c5e32021-09-23 16:20:58 -0700118func (i inheritedDynamicModule) shouldExist() bool {
Sasha Smundak6609ba72021-07-22 18:32:56 -0700119 return i.loadAlways
120}
121
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800122type inheritNode struct {
Sasha Smundak868c5e32021-09-23 16:20:58 -0700123 module inheritedModule
124 loadAlways bool
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800125}
126
127func (inn *inheritNode) emit(gctx *generationContext) {
128 // Unconditional case:
129 // rblf.inherit(handle, <module>, module_init)
130 // Conditional case:
131 // if <module>_init != None:
132 // same as above
Sasha Smundak6609ba72021-07-22 18:32:56 -0700133 inn.module.emitSelect(gctx)
134
135 name := inn.module.name()
136 entry := inn.module.entryName()
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800137 gctx.newLine()
Sasha Smundak868c5e32021-09-23 16:20:58 -0700138 if inn.loadAlways {
Sasha Smundak6609ba72021-07-22 18:32:56 -0700139 gctx.writef("%s(handle, %s, %s)", cfnInherit, name, entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800140 return
141 }
Sasha Smundak6609ba72021-07-22 18:32:56 -0700142
143 gctx.writef("if %s:", entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800144 gctx.indentLevel++
145 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700146 gctx.writef("%s(handle, %s, %s)", cfnInherit, name, entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800147 gctx.indentLevel--
148}
149
150type includeNode struct {
Sasha Smundak868c5e32021-09-23 16:20:58 -0700151 module inheritedModule
152 loadAlways bool
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800153}
154
155func (inn *includeNode) emit(gctx *generationContext) {
Sasha Smundak6609ba72021-07-22 18:32:56 -0700156 inn.module.emitSelect(gctx)
157 entry := inn.module.entryName()
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800158 gctx.newLine()
Sasha Smundak868c5e32021-09-23 16:20:58 -0700159 if inn.loadAlways {
Sasha Smundak6609ba72021-07-22 18:32:56 -0700160 gctx.writef("%s(g, handle)", entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800161 return
162 }
Sasha Smundak6609ba72021-07-22 18:32:56 -0700163
164 gctx.writef("if %s != None:", entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800165 gctx.indentLevel++
166 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700167 gctx.writef("%s(g, handle)", entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800168 gctx.indentLevel--
169}
170
171type assignmentFlavor int
172
173const (
174 // Assignment flavors
175 asgnSet assignmentFlavor = iota // := or =
176 asgnMaybeSet assignmentFlavor = iota // ?= and variable may be unset
177 asgnAppend assignmentFlavor = iota // += and variable has been set before
178 asgnMaybeAppend assignmentFlavor = iota // += and variable may be unset
179)
180
181type assignmentNode struct {
182 lhs variable
183 value starlarkExpr
184 mkValue *mkparser.MakeString
185 flavor assignmentFlavor
186 isTraced bool
187 previous *assignmentNode
188}
189
190func (asgn *assignmentNode) emit(gctx *generationContext) {
191 gctx.newLine()
192 gctx.inAssignment = true
193 asgn.lhs.emitSet(gctx, asgn)
194 gctx.inAssignment = false
195
196 if asgn.isTraced {
197 gctx.newLine()
198 gctx.tracedCount++
199 gctx.writef(`print("%s.%d: %s := ", `, gctx.starScript.mkFile, gctx.tracedCount, asgn.lhs.name())
200 asgn.lhs.emitGet(gctx, true)
201 gctx.writef(")")
202 }
203}
204
205type exprNode struct {
206 expr starlarkExpr
207}
208
209func (exn *exprNode) emit(gctx *generationContext) {
210 gctx.newLine()
211 exn.expr.emit(gctx)
212}
213
214type ifNode struct {
215 isElif bool // true if this is 'elif' statement
216 expr starlarkExpr
217}
218
219func (in *ifNode) emit(gctx *generationContext) {
220 ifElif := "if "
221 if in.isElif {
222 ifElif = "elif "
223 }
224
225 gctx.newLine()
226 if bad, ok := in.expr.(*badExpr); ok {
227 gctx.write("# MK2STAR ERROR converting:")
228 gctx.newLine()
229 gctx.writef("# %s", bad.node.Dump())
230 gctx.newLine()
231 gctx.writef("# %s", bad.message)
232 gctx.newLine()
233 // The init function emits a warning if the conversion was not
234 // fullly successful, so here we (arbitrarily) take the false path.
235 gctx.writef("%sFalse:", ifElif)
236 return
237 }
238 gctx.write(ifElif)
239 in.expr.emit(gctx)
240 gctx.write(":")
241}
242
243type elseNode struct{}
244
245func (br *elseNode) emit(gctx *generationContext) {
246 gctx.newLine()
247 gctx.write("else:")
248}
249
250// switchCase represents as single if/elseif/else branch. All the necessary
251// info about flavor (if/elseif/else) is supposed to be kept in `gate`.
252type switchCase struct {
253 gate starlarkNode
254 nodes []starlarkNode
255}
256
257func (cb *switchCase) newNode(node starlarkNode) {
258 cb.nodes = append(cb.nodes, node)
259}
260
261func (cb *switchCase) emit(gctx *generationContext) {
262 cb.gate.emit(gctx)
263 gctx.indentLevel++
264 hasStatements := false
265 emitNode := func(node starlarkNode) {
266 if _, ok := node.(*commentNode); !ok {
267 hasStatements = true
268 }
269 node.emit(gctx)
270 }
271 if len(cb.nodes) > 0 {
272 emitNode(cb.nodes[0])
273 for _, node := range cb.nodes[1:] {
274 emitNode(node)
275 }
276 if !hasStatements {
277 gctx.emitPass()
278 }
279 } else {
280 gctx.emitPass()
281 }
282 gctx.indentLevel--
283}
284
285// A single complete if ... elseif ... else ... endif sequences
286type switchNode struct {
287 ssCases []*switchCase
288}
289
290func (ssw *switchNode) newNode(node starlarkNode) {
291 switch br := node.(type) {
292 case *switchCase:
293 ssw.ssCases = append(ssw.ssCases, br)
294 default:
295 panic(fmt.Errorf("expected switchCase node, got %t", br))
296 }
297}
298
299func (ssw *switchNode) emit(gctx *generationContext) {
300 if len(ssw.ssCases) == 0 {
301 gctx.emitPass()
302 } else {
303 ssw.ssCases[0].emit(gctx)
304 for _, ssCase := range ssw.ssCases[1:] {
305 ssCase.emit(gctx)
306 }
307 }
308}