blob: d4b42226f4a09f86f7d3fdbdfd52f099e521ef06 [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
45type inheritedModule struct {
46 path string // Converted Starlark file path
47 originalPath string // Makefile file path
48 moduleName string
49 moduleLocalName string
50 loadAlways bool
51}
52
53func (im inheritedModule) name() string {
54 return MakePath2ModuleName(im.originalPath)
55}
56
57func (im inheritedModule) entryName() string {
58 return im.moduleLocalName + "_init"
59}
60
61type inheritNode struct {
62 *inheritedModule
63}
64
65func (inn *inheritNode) emit(gctx *generationContext) {
66 // Unconditional case:
67 // rblf.inherit(handle, <module>, module_init)
68 // Conditional case:
69 // if <module>_init != None:
70 // same as above
71 gctx.newLine()
72 if inn.loadAlways {
73 gctx.writef("%s(handle, %q, %s)", cfnInherit, inn.name(), inn.entryName())
74 return
75 }
76 gctx.writef("if %s != None:", inn.entryName())
77 gctx.indentLevel++
78 gctx.newLine()
79 gctx.writef("%s(handle, %q, %s)", cfnInherit, inn.name(), inn.entryName())
80 gctx.indentLevel--
81}
82
83type includeNode struct {
84 *inheritedModule
85}
86
87func (inn *includeNode) emit(gctx *generationContext) {
88 gctx.newLine()
89 if inn.loadAlways {
90 gctx.writef("%s(g, handle)", inn.entryName())
91 return
92 }
93 gctx.writef("if %s != None:", inn.entryName())
94 gctx.indentLevel++
95 gctx.newLine()
96 gctx.writef("%s(g, handle)", inn.entryName())
97 gctx.indentLevel--
98}
99
100type assignmentFlavor int
101
102const (
103 // Assignment flavors
104 asgnSet assignmentFlavor = iota // := or =
105 asgnMaybeSet assignmentFlavor = iota // ?= and variable may be unset
106 asgnAppend assignmentFlavor = iota // += and variable has been set before
107 asgnMaybeAppend assignmentFlavor = iota // += and variable may be unset
108)
109
110type assignmentNode struct {
111 lhs variable
112 value starlarkExpr
113 mkValue *mkparser.MakeString
114 flavor assignmentFlavor
115 isTraced bool
116 previous *assignmentNode
117}
118
119func (asgn *assignmentNode) emit(gctx *generationContext) {
120 gctx.newLine()
121 gctx.inAssignment = true
122 asgn.lhs.emitSet(gctx, asgn)
123 gctx.inAssignment = false
124
125 if asgn.isTraced {
126 gctx.newLine()
127 gctx.tracedCount++
128 gctx.writef(`print("%s.%d: %s := ", `, gctx.starScript.mkFile, gctx.tracedCount, asgn.lhs.name())
129 asgn.lhs.emitGet(gctx, true)
130 gctx.writef(")")
131 }
132}
133
134type exprNode struct {
135 expr starlarkExpr
136}
137
138func (exn *exprNode) emit(gctx *generationContext) {
139 gctx.newLine()
140 exn.expr.emit(gctx)
141}
142
143type ifNode struct {
144 isElif bool // true if this is 'elif' statement
145 expr starlarkExpr
146}
147
148func (in *ifNode) emit(gctx *generationContext) {
149 ifElif := "if "
150 if in.isElif {
151 ifElif = "elif "
152 }
153
154 gctx.newLine()
155 if bad, ok := in.expr.(*badExpr); ok {
156 gctx.write("# MK2STAR ERROR converting:")
157 gctx.newLine()
158 gctx.writef("# %s", bad.node.Dump())
159 gctx.newLine()
160 gctx.writef("# %s", bad.message)
161 gctx.newLine()
162 // The init function emits a warning if the conversion was not
163 // fullly successful, so here we (arbitrarily) take the false path.
164 gctx.writef("%sFalse:", ifElif)
165 return
166 }
167 gctx.write(ifElif)
168 in.expr.emit(gctx)
169 gctx.write(":")
170}
171
172type elseNode struct{}
173
174func (br *elseNode) emit(gctx *generationContext) {
175 gctx.newLine()
176 gctx.write("else:")
177}
178
179// switchCase represents as single if/elseif/else branch. All the necessary
180// info about flavor (if/elseif/else) is supposed to be kept in `gate`.
181type switchCase struct {
182 gate starlarkNode
183 nodes []starlarkNode
184}
185
186func (cb *switchCase) newNode(node starlarkNode) {
187 cb.nodes = append(cb.nodes, node)
188}
189
190func (cb *switchCase) emit(gctx *generationContext) {
191 cb.gate.emit(gctx)
192 gctx.indentLevel++
193 hasStatements := false
194 emitNode := func(node starlarkNode) {
195 if _, ok := node.(*commentNode); !ok {
196 hasStatements = true
197 }
198 node.emit(gctx)
199 }
200 if len(cb.nodes) > 0 {
201 emitNode(cb.nodes[0])
202 for _, node := range cb.nodes[1:] {
203 emitNode(node)
204 }
205 if !hasStatements {
206 gctx.emitPass()
207 }
208 } else {
209 gctx.emitPass()
210 }
211 gctx.indentLevel--
212}
213
214// A single complete if ... elseif ... else ... endif sequences
215type switchNode struct {
216 ssCases []*switchCase
217}
218
219func (ssw *switchNode) newNode(node starlarkNode) {
220 switch br := node.(type) {
221 case *switchCase:
222 ssw.ssCases = append(ssw.ssCases, br)
223 default:
224 panic(fmt.Errorf("expected switchCase node, got %t", br))
225 }
226}
227
228func (ssw *switchNode) emit(gctx *generationContext) {
229 if len(ssw.ssCases) == 0 {
230 gctx.emitPass()
231 } else {
232 ssw.ssCases[0].emit(gctx)
233 for _, ssCase := range ssw.ssCases[1:] {
234 ssCase.emit(gctx)
235 }
236 }
237}