blob: be1b17428e76bfa55e4bbae79359a5ed28133a42 [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(" += ")
Cole Faust0484c232021-12-22 14:08:08 -080084 value := asgn.value
Sasha Smundakb051c4e2020-11-05 20:45:07 -080085 if pcv.valueType() == starlarkTypeString {
86 gctx.writef(`" " + `)
Cole Faust0484c232021-12-22 14:08:08 -080087 value = &toStringExpr{expr: value}
Sasha Smundakb051c4e2020-11-05 20:45:07 -080088 }
Cole Faust0484c232021-12-22 14:08:08 -080089 value.emit(gctx)
Sasha Smundakb051c4e2020-11-05 20:45:07 -080090 }
Cole Faust816e0802022-03-04 12:04:31 -080091 emitSetDefault := func() {
Sasha Smundakb051c4e2020-11-05 20:45:07 -080092 if pcv.typ == starlarkTypeList {
93 gctx.writef("%s(handle, %q)", cfnSetListDefault, pcv.name())
94 } else {
95 gctx.writef("cfg.setdefault(%q, %s)", pcv.name(), pcv.defaultValueString())
96 }
97 gctx.newLine()
Cole Faust816e0802022-03-04 12:04:31 -080098 }
99
Cole Fauste2a37982022-03-09 16:00:17 -0800100 // If we are not sure variable has been assigned before, emit setdefault
101 needsSetDefault := asgn.previous == nil && !pcv.isPreset() && asgn.isSelfReferential()
102
Cole Faust816e0802022-03-04 12:04:31 -0800103 switch asgn.flavor {
104 case asgnSet:
Cole Fauste2a37982022-03-09 16:00:17 -0800105 if needsSetDefault {
Cole Faust816e0802022-03-04 12:04:31 -0800106 emitSetDefault()
107 }
108 emitAssignment()
109 case asgnAppend:
Cole Fauste2a37982022-03-09 16:00:17 -0800110 if needsSetDefault {
111 emitSetDefault()
112 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800113 emitAppend()
114 case asgnMaybeSet:
115 gctx.writef("if cfg.get(%q) == None:", pcv.nam)
116 gctx.indentLevel++
117 gctx.newLine()
Cole Fauste2a37982022-03-09 16:00:17 -0800118 if needsSetDefault {
119 emitSetDefault()
120 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800121 emitAssignment()
122 gctx.indentLevel--
123 }
124}
125
126func (pcv productConfigVariable) emitGet(gctx *generationContext, isDefined bool) {
127 if isDefined || pcv.isPreset() {
128 gctx.writef("cfg[%q]", pcv.nam)
129 } else {
130 gctx.writef("cfg.get(%q, %s)", pcv.nam, pcv.defaultValueString())
131 }
132}
133
134func (pcv productConfigVariable) emitDefined(gctx *generationContext) {
Cole Fauste2a37982022-03-09 16:00:17 -0800135 gctx.writef("cfg.get(%q) != None", pcv.name())
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800136}
137
138type otherGlobalVariable struct {
139 baseVariable
140}
141
142func (scv otherGlobalVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
143 emitAssignment := func() {
144 scv.emitGet(gctx, true)
145 gctx.write(" = ")
146 asgn.value.emitListVarCopy(gctx)
147 }
148
149 emitAppend := func() {
150 scv.emitGet(gctx, true)
151 gctx.write(" += ")
Cole Faust0484c232021-12-22 14:08:08 -0800152 value := asgn.value
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800153 if scv.valueType() == starlarkTypeString {
154 gctx.writef(`" " + `)
Cole Faust0484c232021-12-22 14:08:08 -0800155 value = &toStringExpr{expr: value}
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800156 }
Cole Faust0484c232021-12-22 14:08:08 -0800157 value.emit(gctx)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800158 }
159
Cole Fauste2a37982022-03-09 16:00:17 -0800160 // If we are not sure variable has been assigned before, emit setdefault
161 needsSetDefault := asgn.previous == nil && !scv.isPreset() && asgn.isSelfReferential()
162
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800163 switch asgn.flavor {
164 case asgnSet:
Cole Fauste2a37982022-03-09 16:00:17 -0800165 if needsSetDefault {
166 gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
167 gctx.newLine()
168 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800169 emitAssignment()
170 case asgnAppend:
Cole Fauste2a37982022-03-09 16:00:17 -0800171 if needsSetDefault {
172 gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
173 gctx.newLine()
174 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800175 emitAppend()
176 case asgnMaybeSet:
177 gctx.writef("if g.get(%q) == None:", scv.nam)
178 gctx.indentLevel++
179 gctx.newLine()
Cole Fauste2a37982022-03-09 16:00:17 -0800180 if needsSetDefault {
181 gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
182 gctx.newLine()
183 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800184 emitAssignment()
185 gctx.indentLevel--
186 }
187}
188
189func (scv otherGlobalVariable) emitGet(gctx *generationContext, isDefined bool) {
190 if isDefined || scv.isPreset() {
191 gctx.writef("g[%q]", scv.nam)
192 } else {
193 gctx.writef("g.get(%q, %s)", scv.nam, scv.defaultValueString())
194 }
195}
196
197func (scv otherGlobalVariable) emitDefined(gctx *generationContext) {
198 gctx.writef("g.get(%q) != None", scv.name())
199}
200
201type localVariable struct {
202 baseVariable
203}
204
Sasha Smundakc4fa93e2021-11-05 14:38:46 -0700205func (lv localVariable) emitDefined(gctx *generationContext) {
206 gctx.writef(lv.String())
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800207}
208
209func (lv localVariable) String() string {
210 return "_" + lv.nam
211}
212
213func (lv localVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
214 switch asgn.flavor {
Cole Fauste2a37982022-03-09 16:00:17 -0800215 case asgnSet, asgnMaybeSet:
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800216 gctx.writef("%s = ", lv)
217 asgn.value.emitListVarCopy(gctx)
218 case asgnAppend:
219 lv.emitGet(gctx, false)
220 gctx.write(" += ")
Cole Faust0484c232021-12-22 14:08:08 -0800221 value := asgn.value
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800222 if lv.valueType() == starlarkTypeString {
223 gctx.writef(`" " + `)
Cole Faust0484c232021-12-22 14:08:08 -0800224 value = &toStringExpr{expr: value}
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800225 }
Cole Faust0484c232021-12-22 14:08:08 -0800226 value.emit(gctx)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800227 }
228}
229
230func (lv localVariable) emitGet(gctx *generationContext, _ bool) {
231 gctx.writef("%s", lv)
232}
233
234type predefinedVariable struct {
235 baseVariable
236 value starlarkExpr
237}
238
239func (pv predefinedVariable) emitGet(gctx *generationContext, _ bool) {
240 pv.value.emit(gctx)
241}
242
Sasha Smundak6609ba72021-07-22 18:32:56 -0700243func (pv predefinedVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800244 if expectedValue, ok1 := maybeString(pv.value); ok1 {
245 actualValue, ok2 := maybeString(asgn.value)
246 if ok2 {
247 if actualValue == expectedValue {
248 return
249 }
Sasha Smundak422b6142021-11-11 18:31:59 -0800250 gctx.emitConversionError(asgn.location,
251 fmt.Sprintf("cannot set predefined variable %s to %q, its value should be %q",
252 pv.name(), actualValue, expectedValue))
Sasha Smundak6609ba72021-07-22 18:32:56 -0700253 gctx.starScript.hasErrors = true
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800254 return
255 }
256 }
257 panic(fmt.Errorf("cannot set predefined variable %s to %q", pv.name(), asgn.mkValue.Dump()))
258}
259
260func (pv predefinedVariable) emitDefined(gctx *generationContext) {
261 gctx.write("True")
262}
263
264var localProductConfigVariables = map[string]string{
265 "LOCAL_AUDIO_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
266 "LOCAL_AUDIO_PRODUCT_COPY_FILES": "PRODUCT_COPY_FILES",
267 "LOCAL_AUDIO_DEVICE_PACKAGE_OVERLAYS": "DEVICE_PACKAGE_OVERLAYS",
268 "LOCAL_DUMPSTATE_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
269 "LOCAL_GATEKEEPER_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
270 "LOCAL_HEALTH_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
271 "LOCAL_SENSOR_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
272 "LOCAL_KEYMASTER_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
273 "LOCAL_KEYMINT_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
274}
275
276var presetVariables = map[string]bool{
277 "BUILD_ID": true,
278 "HOST_ARCH": true,
279 "HOST_OS": true,
280 "HOST_BUILD_TYPE": true,
281 "OUT_DIR": true,
282 "PLATFORM_VERSION_CODENAME": true,
283 "PLATFORM_VERSION": true,
284 "TARGET_ARCH": true,
285 "TARGET_ARCH_VARIANT": true,
286 "TARGET_BUILD_TYPE": true,
287 "TARGET_BUILD_VARIANT": true,
288 "TARGET_PRODUCT": true,
289}
290
291// addVariable returns a variable with a given name. A variable is
292// added if it does not exist yet.
293func (ctx *parseContext) addVariable(name string) variable {
Cole Faustf92c9f22022-03-14 14:35:50 -0700294 // Get the hintType before potentially changing the variable name
295 var hintType starlarkType
296 var ok bool
297 if hintType, ok = ctx.typeHints[name]; !ok {
298 hintType = starlarkTypeUnknown
299 }
Cole Faust3c4fc992022-02-28 16:05:01 -0800300 // Heuristics: if variable's name is all lowercase, consider it local
301 // string variable.
302 isLocalVariable := name == strings.ToLower(name)
303 // Local variables can't have special characters in them, because they
304 // will be used as starlark identifiers
305 if isLocalVariable {
306 name = strings.ReplaceAll(strings.TrimSpace(name), "-", "_")
307 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800308 v, found := ctx.variables[name]
309 if !found {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800310 if vi, found := KnownVariables[name]; found {
Cole Faustf92c9f22022-03-14 14:35:50 -0700311 _, preset := presetVariables[name]
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800312 switch vi.class {
313 case VarClassConfig:
314 v = &productConfigVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
315 case VarClassSoong:
316 v = &otherGlobalVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
317 }
Cole Faust3c4fc992022-02-28 16:05:01 -0800318 } else if isLocalVariable {
Cole Faustf92c9f22022-03-14 14:35:50 -0700319 v = &localVariable{baseVariable{nam: name, typ: hintType}}
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800320 } else {
Cole Faustf92c9f22022-03-14 14:35:50 -0700321 vt := hintType
Cole Faustf5adedc2022-03-18 14:05:06 -0700322 // Heuristics: local variables that contribute to corresponding config variables
323 if cfgVarName, found := localProductConfigVariables[name]; found && vt == starlarkTypeUnknown {
324 vi, found2 := KnownVariables[cfgVarName]
325 if !found2 {
326 panic(fmt.Errorf("unknown config variable %s for %s", cfgVarName, name))
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800327 }
Cole Faustf5adedc2022-03-18 14:05:06 -0700328 vt = vi.valueType
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800329 }
Sasha Smundak468e11f2021-08-26 09:10:23 -0700330 if strings.HasSuffix(name, "_LIST") && vt == starlarkTypeUnknown {
331 // Heuristics: Variables with "_LIST" suffix are lists
332 vt = starlarkTypeList
333 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800334 v = &otherGlobalVariable{baseVariable{nam: name, typ: vt}}
335 }
336 ctx.variables[name] = v
337 }
338 return v
339}