blob: ded07fed6bac592016974e4bc7c36a16aa71f92d [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"
Sasha Smundakb051c4e2020-11-05 20:45:07 -080019 "strings"
20)
21
22type variable interface {
23 name() string
24 emitGet(gctx *generationContext, isDefined bool)
25 emitSet(gctx *generationContext, asgn *assignmentNode)
26 emitDefined(gctx *generationContext)
27 valueType() starlarkType
Sasha Smundak9d011ab2021-07-09 16:00:57 -070028 setValueType(t starlarkType)
Sasha Smundakb051c4e2020-11-05 20:45:07 -080029 defaultValueString() string
30 isPreset() bool
31}
32
33type baseVariable struct {
34 nam string
35 typ starlarkType
36 preset bool // true if it has been initialized at startup
37}
38
39func (v baseVariable) name() string {
40 return v.nam
41}
42
43func (v baseVariable) valueType() starlarkType {
44 return v.typ
45}
46
Sasha Smundak9d011ab2021-07-09 16:00:57 -070047func (v *baseVariable) setValueType(t starlarkType) {
48 v.typ = t
49}
50
Sasha Smundakb051c4e2020-11-05 20:45:07 -080051func (v baseVariable) isPreset() bool {
52 return v.preset
53}
54
55var defaultValuesByType = map[starlarkType]string{
56 starlarkTypeUnknown: `""`,
57 starlarkTypeList: "[]",
58 starlarkTypeString: `""`,
59 starlarkTypeInt: "0",
60 starlarkTypeBool: "False",
61 starlarkTypeVoid: "None",
62}
63
64func (v baseVariable) defaultValueString() string {
65 if v, ok := defaultValuesByType[v.valueType()]; ok {
66 return v
67 }
68 panic(fmt.Errorf("%s has unknown type %q", v.name(), v.valueType()))
69}
70
71type productConfigVariable struct {
72 baseVariable
73}
74
75func (pcv productConfigVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
76 emitAssignment := func() {
77 pcv.emitGet(gctx, true)
78 gctx.write(" = ")
79 asgn.value.emitListVarCopy(gctx)
80 }
81 emitAppend := func() {
82 pcv.emitGet(gctx, true)
83 gctx.write(" += ")
84 if pcv.valueType() == starlarkTypeString {
85 gctx.writef(`" " + `)
86 }
87 asgn.value.emit(gctx)
88 }
89
90 switch asgn.flavor {
91 case asgnSet:
92 emitAssignment()
93 case asgnAppend:
94 emitAppend()
95 case asgnMaybeAppend:
96 // If we are not sure variable has been assigned before, emit setdefault
97 if pcv.typ == starlarkTypeList {
98 gctx.writef("%s(handle, %q)", cfnSetListDefault, pcv.name())
99 } else {
100 gctx.writef("cfg.setdefault(%q, %s)", pcv.name(), pcv.defaultValueString())
101 }
102 gctx.newLine()
103 emitAppend()
104 case asgnMaybeSet:
105 gctx.writef("if cfg.get(%q) == None:", pcv.nam)
106 gctx.indentLevel++
107 gctx.newLine()
108 emitAssignment()
109 gctx.indentLevel--
110 }
111}
112
113func (pcv productConfigVariable) emitGet(gctx *generationContext, isDefined bool) {
114 if isDefined || pcv.isPreset() {
115 gctx.writef("cfg[%q]", pcv.nam)
116 } else {
117 gctx.writef("cfg.get(%q, %s)", pcv.nam, pcv.defaultValueString())
118 }
119}
120
121func (pcv productConfigVariable) emitDefined(gctx *generationContext) {
122 gctx.writef("g.get(%q) != None", pcv.name())
123}
124
125type otherGlobalVariable struct {
126 baseVariable
127}
128
129func (scv otherGlobalVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
130 emitAssignment := func() {
131 scv.emitGet(gctx, true)
132 gctx.write(" = ")
133 asgn.value.emitListVarCopy(gctx)
134 }
135
136 emitAppend := func() {
137 scv.emitGet(gctx, true)
138 gctx.write(" += ")
139 if scv.valueType() == starlarkTypeString {
140 gctx.writef(`" " + `)
141 }
142 asgn.value.emit(gctx)
143 }
144
145 switch asgn.flavor {
146 case asgnSet:
147 emitAssignment()
148 case asgnAppend:
149 emitAppend()
150 case asgnMaybeAppend:
151 // If we are not sure variable has been assigned before, emit setdefault
152 gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
153 gctx.newLine()
154 emitAppend()
155 case asgnMaybeSet:
156 gctx.writef("if g.get(%q) == None:", scv.nam)
157 gctx.indentLevel++
158 gctx.newLine()
159 emitAssignment()
160 gctx.indentLevel--
161 }
162}
163
164func (scv otherGlobalVariable) emitGet(gctx *generationContext, isDefined bool) {
165 if isDefined || scv.isPreset() {
166 gctx.writef("g[%q]", scv.nam)
167 } else {
168 gctx.writef("g.get(%q, %s)", scv.nam, scv.defaultValueString())
169 }
170}
171
172func (scv otherGlobalVariable) emitDefined(gctx *generationContext) {
173 gctx.writef("g.get(%q) != None", scv.name())
174}
175
176type localVariable struct {
177 baseVariable
178}
179
Sasha Smundakc4fa93e2021-11-05 14:38:46 -0700180func (lv localVariable) emitDefined(gctx *generationContext) {
181 gctx.writef(lv.String())
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800182}
183
184func (lv localVariable) String() string {
185 return "_" + lv.nam
186}
187
188func (lv localVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
189 switch asgn.flavor {
190 case asgnSet:
191 gctx.writef("%s = ", lv)
192 asgn.value.emitListVarCopy(gctx)
193 case asgnAppend:
194 lv.emitGet(gctx, false)
195 gctx.write(" += ")
196 if lv.valueType() == starlarkTypeString {
197 gctx.writef(`" " + `)
198 }
199 asgn.value.emit(gctx)
200 case asgnMaybeAppend:
201 gctx.writef("%s(%q, ", cfnLocalAppend, lv)
202 asgn.value.emit(gctx)
203 gctx.write(")")
204 case asgnMaybeSet:
205 gctx.writef("%s(%q, ", cfnLocalSetDefault, lv)
206 asgn.value.emit(gctx)
207 gctx.write(")")
208 }
209}
210
211func (lv localVariable) emitGet(gctx *generationContext, _ bool) {
212 gctx.writef("%s", lv)
213}
214
215type predefinedVariable struct {
216 baseVariable
217 value starlarkExpr
218}
219
220func (pv predefinedVariable) emitGet(gctx *generationContext, _ bool) {
221 pv.value.emit(gctx)
222}
223
Sasha Smundak6609ba72021-07-22 18:32:56 -0700224func (pv predefinedVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800225 if expectedValue, ok1 := maybeString(pv.value); ok1 {
226 actualValue, ok2 := maybeString(asgn.value)
227 if ok2 {
228 if actualValue == expectedValue {
229 return
230 }
Sasha Smundak6609ba72021-07-22 18:32:56 -0700231 gctx.writef("# MK2RBC TRANSLATION ERROR: cannot set predefined variable %s to %q, its value should be %q",
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800232 pv.name(), actualValue, expectedValue)
Sasha Smundak6609ba72021-07-22 18:32:56 -0700233 gctx.newLine()
234 gctx.write("pass")
235 gctx.starScript.hasErrors = true
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800236 return
237 }
238 }
239 panic(fmt.Errorf("cannot set predefined variable %s to %q", pv.name(), asgn.mkValue.Dump()))
240}
241
242func (pv predefinedVariable) emitDefined(gctx *generationContext) {
243 gctx.write("True")
244}
245
246var localProductConfigVariables = map[string]string{
247 "LOCAL_AUDIO_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
248 "LOCAL_AUDIO_PRODUCT_COPY_FILES": "PRODUCT_COPY_FILES",
249 "LOCAL_AUDIO_DEVICE_PACKAGE_OVERLAYS": "DEVICE_PACKAGE_OVERLAYS",
250 "LOCAL_DUMPSTATE_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
251 "LOCAL_GATEKEEPER_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
252 "LOCAL_HEALTH_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
253 "LOCAL_SENSOR_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
254 "LOCAL_KEYMASTER_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
255 "LOCAL_KEYMINT_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
256}
257
258var presetVariables = map[string]bool{
259 "BUILD_ID": true,
260 "HOST_ARCH": true,
261 "HOST_OS": true,
262 "HOST_BUILD_TYPE": true,
263 "OUT_DIR": true,
264 "PLATFORM_VERSION_CODENAME": true,
265 "PLATFORM_VERSION": true,
266 "TARGET_ARCH": true,
267 "TARGET_ARCH_VARIANT": true,
268 "TARGET_BUILD_TYPE": true,
269 "TARGET_BUILD_VARIANT": true,
270 "TARGET_PRODUCT": true,
271}
272
273// addVariable returns a variable with a given name. A variable is
274// added if it does not exist yet.
275func (ctx *parseContext) addVariable(name string) variable {
276 v, found := ctx.variables[name]
277 if !found {
278 _, preset := presetVariables[name]
279 if vi, found := KnownVariables[name]; found {
280 switch vi.class {
281 case VarClassConfig:
282 v = &productConfigVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
283 case VarClassSoong:
284 v = &otherGlobalVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
285 }
286 } else if name == strings.ToLower(name) {
287 // Heuristics: if variable's name is all lowercase, consider it local
288 // string variable.
Sasha Smundak9d011ab2021-07-09 16:00:57 -0700289 v = &localVariable{baseVariable{nam: name, typ: starlarkTypeUnknown}}
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800290 } else {
291 vt := starlarkTypeUnknown
292 if strings.HasPrefix(name, "LOCAL_") {
293 // Heuristics: local variables that contribute to corresponding config variables
294 if cfgVarName, found := localProductConfigVariables[name]; found {
295 vi, found2 := KnownVariables[cfgVarName]
296 if !found2 {
297 panic(fmt.Errorf("unknown config variable %s for %s", cfgVarName, name))
298 }
299 vt = vi.valueType
300 }
301 }
Sasha Smundak468e11f2021-08-26 09:10:23 -0700302 if strings.HasSuffix(name, "_LIST") && vt == starlarkTypeUnknown {
303 // Heuristics: Variables with "_LIST" suffix are lists
304 vt = starlarkTypeList
305 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800306 v = &otherGlobalVariable{baseVariable{nam: name, typ: vt}}
307 }
308 ctx.variables[name] = v
309 }
310 return v
311}