blob: d38299d34cca09ea66ec96cfef7eb888997ed0c8 [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
Sasha Smundak422b6142021-11-11 18:31:59 -0800186 location ErrorLocation
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800187 isTraced bool
188 previous *assignmentNode
189}
190
191func (asgn *assignmentNode) emit(gctx *generationContext) {
192 gctx.newLine()
193 gctx.inAssignment = true
194 asgn.lhs.emitSet(gctx, asgn)
195 gctx.inAssignment = false
196
197 if asgn.isTraced {
198 gctx.newLine()
199 gctx.tracedCount++
200 gctx.writef(`print("%s.%d: %s := ", `, gctx.starScript.mkFile, gctx.tracedCount, asgn.lhs.name())
201 asgn.lhs.emitGet(gctx, true)
202 gctx.writef(")")
203 }
204}
205
206type exprNode struct {
207 expr starlarkExpr
208}
209
210func (exn *exprNode) emit(gctx *generationContext) {
211 gctx.newLine()
212 exn.expr.emit(gctx)
213}
214
215type ifNode struct {
216 isElif bool // true if this is 'elif' statement
217 expr starlarkExpr
218}
219
220func (in *ifNode) emit(gctx *generationContext) {
221 ifElif := "if "
222 if in.isElif {
223 ifElif = "elif "
224 }
225
226 gctx.newLine()
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800227 gctx.write(ifElif)
228 in.expr.emit(gctx)
229 gctx.write(":")
230}
231
232type elseNode struct{}
233
234func (br *elseNode) emit(gctx *generationContext) {
235 gctx.newLine()
236 gctx.write("else:")
237}
238
239// switchCase represents as single if/elseif/else branch. All the necessary
240// info about flavor (if/elseif/else) is supposed to be kept in `gate`.
241type switchCase struct {
242 gate starlarkNode
243 nodes []starlarkNode
244}
245
246func (cb *switchCase) newNode(node starlarkNode) {
247 cb.nodes = append(cb.nodes, node)
248}
249
250func (cb *switchCase) emit(gctx *generationContext) {
251 cb.gate.emit(gctx)
252 gctx.indentLevel++
253 hasStatements := false
254 emitNode := func(node starlarkNode) {
255 if _, ok := node.(*commentNode); !ok {
256 hasStatements = true
257 }
258 node.emit(gctx)
259 }
260 if len(cb.nodes) > 0 {
261 emitNode(cb.nodes[0])
262 for _, node := range cb.nodes[1:] {
263 emitNode(node)
264 }
265 if !hasStatements {
266 gctx.emitPass()
267 }
268 } else {
269 gctx.emitPass()
270 }
271 gctx.indentLevel--
272}
273
274// A single complete if ... elseif ... else ... endif sequences
275type switchNode struct {
276 ssCases []*switchCase
277}
278
279func (ssw *switchNode) newNode(node starlarkNode) {
280 switch br := node.(type) {
281 case *switchCase:
282 ssw.ssCases = append(ssw.ssCases, br)
283 default:
284 panic(fmt.Errorf("expected switchCase node, got %t", br))
285 }
286}
287
288func (ssw *switchNode) emit(gctx *generationContext) {
289 if len(ssw.ssCases) == 0 {
290 gctx.emitPass()
291 } else {
292 ssw.ssCases[0].emit(gctx)
293 for _, ssCase := range ssw.ssCases[1:] {
294 ssCase.emit(gctx)
295 }
296 }
297}