blob: 8efe20766619402eb3a089302f43ce50e0f47346 [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)
60 isLoadAlways() bool
61}
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
75func (im inheritedStaticModule) isLoadAlways() bool {
76 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
118func (i inheritedDynamicModule) isLoadAlways() bool {
119 return i.loadAlways
120}
121
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800122type inheritNode struct {
Sasha Smundak6609ba72021-07-22 18:32:56 -0700123 module inheritedModule
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800124}
125
126func (inn *inheritNode) emit(gctx *generationContext) {
127 // Unconditional case:
128 // rblf.inherit(handle, <module>, module_init)
129 // Conditional case:
130 // if <module>_init != None:
131 // same as above
Sasha Smundak6609ba72021-07-22 18:32:56 -0700132 inn.module.emitSelect(gctx)
133
134 name := inn.module.name()
135 entry := inn.module.entryName()
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800136 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700137 if inn.module.isLoadAlways() {
138 gctx.writef("%s(handle, %s, %s)", cfnInherit, name, entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800139 return
140 }
Sasha Smundak6609ba72021-07-22 18:32:56 -0700141
142 gctx.writef("if %s:", entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800143 gctx.indentLevel++
144 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700145 gctx.writef("%s(handle, %s, %s)", cfnInherit, name, entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800146 gctx.indentLevel--
147}
148
149type includeNode struct {
Sasha Smundak6609ba72021-07-22 18:32:56 -0700150 module inheritedModule
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800151}
152
153func (inn *includeNode) emit(gctx *generationContext) {
Sasha Smundak6609ba72021-07-22 18:32:56 -0700154 inn.module.emitSelect(gctx)
155 entry := inn.module.entryName()
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800156 gctx.newLine()
Sasha Smundak6609ba72021-07-22 18:32:56 -0700157 if inn.module.isLoadAlways() {
158 gctx.writef("%s(g, handle)", entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800159 return
160 }
Sasha Smundak6609ba72021-07-22 18:32:56 -0700161
162 gctx.writef("if %s != None:", entry)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800163 gctx.indentLevel++
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 gctx.indentLevel--
167}
168
169type assignmentFlavor int
170
171const (
172 // Assignment flavors
173 asgnSet assignmentFlavor = iota // := or =
174 asgnMaybeSet assignmentFlavor = iota // ?= and variable may be unset
175 asgnAppend assignmentFlavor = iota // += and variable has been set before
176 asgnMaybeAppend assignmentFlavor = iota // += and variable may be unset
177)
178
179type assignmentNode struct {
180 lhs variable
181 value starlarkExpr
182 mkValue *mkparser.MakeString
183 flavor assignmentFlavor
184 isTraced bool
185 previous *assignmentNode
186}
187
188func (asgn *assignmentNode) emit(gctx *generationContext) {
189 gctx.newLine()
190 gctx.inAssignment = true
191 asgn.lhs.emitSet(gctx, asgn)
192 gctx.inAssignment = false
193
194 if asgn.isTraced {
195 gctx.newLine()
196 gctx.tracedCount++
197 gctx.writef(`print("%s.%d: %s := ", `, gctx.starScript.mkFile, gctx.tracedCount, asgn.lhs.name())
198 asgn.lhs.emitGet(gctx, true)
199 gctx.writef(")")
200 }
201}
202
203type exprNode struct {
204 expr starlarkExpr
205}
206
207func (exn *exprNode) emit(gctx *generationContext) {
208 gctx.newLine()
209 exn.expr.emit(gctx)
210}
211
212type ifNode struct {
213 isElif bool // true if this is 'elif' statement
214 expr starlarkExpr
215}
216
217func (in *ifNode) emit(gctx *generationContext) {
218 ifElif := "if "
219 if in.isElif {
220 ifElif = "elif "
221 }
222
223 gctx.newLine()
224 if bad, ok := in.expr.(*badExpr); ok {
225 gctx.write("# MK2STAR ERROR converting:")
226 gctx.newLine()
227 gctx.writef("# %s", bad.node.Dump())
228 gctx.newLine()
229 gctx.writef("# %s", bad.message)
230 gctx.newLine()
231 // The init function emits a warning if the conversion was not
232 // fullly successful, so here we (arbitrarily) take the false path.
233 gctx.writef("%sFalse:", ifElif)
234 return
235 }
236 gctx.write(ifElif)
237 in.expr.emit(gctx)
238 gctx.write(":")
239}
240
241type elseNode struct{}
242
243func (br *elseNode) emit(gctx *generationContext) {
244 gctx.newLine()
245 gctx.write("else:")
246}
247
248// switchCase represents as single if/elseif/else branch. All the necessary
249// info about flavor (if/elseif/else) is supposed to be kept in `gate`.
250type switchCase struct {
251 gate starlarkNode
252 nodes []starlarkNode
253}
254
255func (cb *switchCase) newNode(node starlarkNode) {
256 cb.nodes = append(cb.nodes, node)
257}
258
259func (cb *switchCase) emit(gctx *generationContext) {
260 cb.gate.emit(gctx)
261 gctx.indentLevel++
262 hasStatements := false
263 emitNode := func(node starlarkNode) {
264 if _, ok := node.(*commentNode); !ok {
265 hasStatements = true
266 }
267 node.emit(gctx)
268 }
269 if len(cb.nodes) > 0 {
270 emitNode(cb.nodes[0])
271 for _, node := range cb.nodes[1:] {
272 emitNode(node)
273 }
274 if !hasStatements {
275 gctx.emitPass()
276 }
277 } else {
278 gctx.emitPass()
279 }
280 gctx.indentLevel--
281}
282
283// A single complete if ... elseif ... else ... endif sequences
284type switchNode struct {
285 ssCases []*switchCase
286}
287
288func (ssw *switchNode) newNode(node starlarkNode) {
289 switch br := node.(type) {
290 case *switchCase:
291 ssw.ssCases = append(ssw.ssCases, br)
292 default:
293 panic(fmt.Errorf("expected switchCase node, got %t", br))
294 }
295}
296
297func (ssw *switchNode) emit(gctx *generationContext) {
298 if len(ssw.ssCases) == 0 {
299 gctx.emitPass()
300 } else {
301 ssw.ssCases[0].emit(gctx)
302 for _, ssCase := range ssw.ssCases[1:] {
303 ssCase.emit(gctx)
304 }
305 }
306}