blob: 95e1f8ec7cd4affcdc04b00a23f7a9cee75a5e5c [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
Cole Faustf0632662022-04-07 13:59:24 -070024 emitGet(gctx *generationContext)
Sasha Smundakb051c4e2020-11-05 20:45:07 -080025 emitSet(gctx *generationContext, asgn *assignmentNode)
Sasha Smundakb051c4e2020-11-05 20:45:07 -080026 valueType() starlarkType
Sasha Smundak9d011ab2021-07-09 16:00:57 -070027 setValueType(t starlarkType)
Sasha Smundakb051c4e2020-11-05 20:45:07 -080028 defaultValueString() string
29 isPreset() bool
30}
31
32type baseVariable struct {
33 nam string
34 typ starlarkType
35 preset bool // true if it has been initialized at startup
36}
37
38func (v baseVariable) name() string {
39 return v.nam
40}
41
42func (v baseVariable) valueType() starlarkType {
43 return v.typ
44}
45
Sasha Smundak9d011ab2021-07-09 16:00:57 -070046func (v *baseVariable) setValueType(t starlarkType) {
47 v.typ = t
48}
49
Sasha Smundakb051c4e2020-11-05 20:45:07 -080050func (v baseVariable) isPreset() bool {
51 return v.preset
52}
53
54var defaultValuesByType = map[starlarkType]string{
55 starlarkTypeUnknown: `""`,
56 starlarkTypeList: "[]",
57 starlarkTypeString: `""`,
58 starlarkTypeInt: "0",
59 starlarkTypeBool: "False",
60 starlarkTypeVoid: "None",
61}
62
63func (v baseVariable) defaultValueString() string {
64 if v, ok := defaultValuesByType[v.valueType()]; ok {
65 return v
66 }
67 panic(fmt.Errorf("%s has unknown type %q", v.name(), v.valueType()))
68}
69
70type productConfigVariable struct {
71 baseVariable
72}
73
74func (pcv productConfigVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
75 emitAssignment := func() {
Cole Faustf0632662022-04-07 13:59:24 -070076 gctx.writef("cfg[%q] = ", pcv.nam)
Sasha Smundakb051c4e2020-11-05 20:45:07 -080077 asgn.value.emitListVarCopy(gctx)
78 }
79 emitAppend := func() {
Cole Faustf0632662022-04-07 13:59:24 -070080 gctx.writef("cfg[%q] += ", pcv.nam)
Cole Faust0484c232021-12-22 14:08:08 -080081 value := asgn.value
Sasha Smundakb051c4e2020-11-05 20:45:07 -080082 if pcv.valueType() == starlarkTypeString {
83 gctx.writef(`" " + `)
Cole Faust0484c232021-12-22 14:08:08 -080084 value = &toStringExpr{expr: value}
Sasha Smundakb051c4e2020-11-05 20:45:07 -080085 }
Cole Faust0484c232021-12-22 14:08:08 -080086 value.emit(gctx)
Sasha Smundakb051c4e2020-11-05 20:45:07 -080087 }
Cole Faust816e0802022-03-04 12:04:31 -080088 emitSetDefault := func() {
Sasha Smundakb051c4e2020-11-05 20:45:07 -080089 if pcv.typ == starlarkTypeList {
90 gctx.writef("%s(handle, %q)", cfnSetListDefault, pcv.name())
91 } else {
92 gctx.writef("cfg.setdefault(%q, %s)", pcv.name(), pcv.defaultValueString())
93 }
94 gctx.newLine()
Cole Faust816e0802022-03-04 12:04:31 -080095 }
96
Cole Fauste2a37982022-03-09 16:00:17 -080097 // If we are not sure variable has been assigned before, emit setdefault
Cole Faustf0632662022-04-07 13:59:24 -070098 needsSetDefault := !gctx.hasBeenAssigned(&pcv) && !pcv.isPreset() && asgn.isSelfReferential()
Cole Fauste2a37982022-03-09 16:00:17 -080099
Cole Faust816e0802022-03-04 12:04:31 -0800100 switch asgn.flavor {
101 case asgnSet:
Cole Fauste2a37982022-03-09 16:00:17 -0800102 if needsSetDefault {
Cole Faust816e0802022-03-04 12:04:31 -0800103 emitSetDefault()
104 }
105 emitAssignment()
106 case asgnAppend:
Cole Fauste2a37982022-03-09 16:00:17 -0800107 if needsSetDefault {
108 emitSetDefault()
109 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800110 emitAppend()
111 case asgnMaybeSet:
Cole Faust8e15f692023-10-09 12:26:21 -0700112 // In mk2rbc.go we never emit a maybeSet assignment for product config variables, because
113 // they are set to empty strings before running product config.
114 panic("Should never get here")
115 default:
116 panic("Unknown assignment flavor")
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800117 }
Cole Faustf0632662022-04-07 13:59:24 -0700118
119 gctx.setHasBeenAssigned(&pcv)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800120}
121
Cole Faustf0632662022-04-07 13:59:24 -0700122func (pcv productConfigVariable) emitGet(gctx *generationContext) {
123 if gctx.hasBeenAssigned(&pcv) || pcv.isPreset() {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800124 gctx.writef("cfg[%q]", pcv.nam)
125 } else {
126 gctx.writef("cfg.get(%q, %s)", pcv.nam, pcv.defaultValueString())
127 }
128}
129
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800130type otherGlobalVariable struct {
131 baseVariable
132}
133
134func (scv otherGlobalVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
135 emitAssignment := func() {
Cole Faustf0632662022-04-07 13:59:24 -0700136 gctx.writef("g[%q] = ", scv.nam)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800137 asgn.value.emitListVarCopy(gctx)
138 }
139
140 emitAppend := func() {
Cole Faustf0632662022-04-07 13:59:24 -0700141 gctx.writef("g[%q] += ", scv.nam)
Cole Faust0484c232021-12-22 14:08:08 -0800142 value := asgn.value
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800143 if scv.valueType() == starlarkTypeString {
144 gctx.writef(`" " + `)
Cole Faust0484c232021-12-22 14:08:08 -0800145 value = &toStringExpr{expr: value}
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800146 }
Cole Faust0484c232021-12-22 14:08:08 -0800147 value.emit(gctx)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800148 }
149
Cole Fauste2a37982022-03-09 16:00:17 -0800150 // If we are not sure variable has been assigned before, emit setdefault
Cole Faustf0632662022-04-07 13:59:24 -0700151 needsSetDefault := !gctx.hasBeenAssigned(&scv) && !scv.isPreset() && asgn.isSelfReferential()
Cole Fauste2a37982022-03-09 16:00:17 -0800152
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800153 switch asgn.flavor {
154 case asgnSet:
Cole Fauste2a37982022-03-09 16:00:17 -0800155 if needsSetDefault {
156 gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
157 gctx.newLine()
158 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800159 emitAssignment()
160 case asgnAppend:
Cole Fauste2a37982022-03-09 16:00:17 -0800161 if needsSetDefault {
162 gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
163 gctx.newLine()
164 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800165 emitAppend()
166 case asgnMaybeSet:
167 gctx.writef("if g.get(%q) == None:", scv.nam)
168 gctx.indentLevel++
169 gctx.newLine()
Cole Fauste2a37982022-03-09 16:00:17 -0800170 if needsSetDefault {
171 gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
172 gctx.newLine()
173 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800174 emitAssignment()
175 gctx.indentLevel--
176 }
Cole Faustf0632662022-04-07 13:59:24 -0700177
178 gctx.setHasBeenAssigned(&scv)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800179}
180
Cole Faustf0632662022-04-07 13:59:24 -0700181func (scv otherGlobalVariable) emitGet(gctx *generationContext) {
182 if gctx.hasBeenAssigned(&scv) || scv.isPreset() {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800183 gctx.writef("g[%q]", scv.nam)
184 } else {
185 gctx.writef("g.get(%q, %s)", scv.nam, scv.defaultValueString())
186 }
187}
188
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800189type localVariable struct {
190 baseVariable
191}
192
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800193func (lv localVariable) String() string {
194 return "_" + lv.nam
195}
196
197func (lv localVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
198 switch asgn.flavor {
Cole Fauste2a37982022-03-09 16:00:17 -0800199 case asgnSet, asgnMaybeSet:
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800200 gctx.writef("%s = ", lv)
201 asgn.value.emitListVarCopy(gctx)
202 case asgnAppend:
Cole Faustf0632662022-04-07 13:59:24 -0700203 gctx.writef("%s += ", lv)
Cole Faust0484c232021-12-22 14:08:08 -0800204 value := asgn.value
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800205 if lv.valueType() == starlarkTypeString {
206 gctx.writef(`" " + `)
Cole Faust0484c232021-12-22 14:08:08 -0800207 value = &toStringExpr{expr: value}
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800208 }
Cole Faust0484c232021-12-22 14:08:08 -0800209 value.emit(gctx)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800210 }
211}
212
Cole Faustf0632662022-04-07 13:59:24 -0700213func (lv localVariable) emitGet(gctx *generationContext) {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800214 gctx.writef("%s", lv)
215}
216
217type predefinedVariable struct {
218 baseVariable
219 value starlarkExpr
220}
221
Cole Faustf0632662022-04-07 13:59:24 -0700222func (pv predefinedVariable) emitGet(gctx *generationContext) {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800223 pv.value.emit(gctx)
224}
225
Sasha Smundak6609ba72021-07-22 18:32:56 -0700226func (pv predefinedVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800227 if expectedValue, ok1 := maybeString(pv.value); ok1 {
228 actualValue, ok2 := maybeString(asgn.value)
229 if ok2 {
230 if actualValue == expectedValue {
231 return
232 }
Sasha Smundak422b6142021-11-11 18:31:59 -0800233 gctx.emitConversionError(asgn.location,
234 fmt.Sprintf("cannot set predefined variable %s to %q, its value should be %q",
235 pv.name(), actualValue, expectedValue))
Sasha Smundak6609ba72021-07-22 18:32:56 -0700236 gctx.starScript.hasErrors = true
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800237 return
238 }
239 }
240 panic(fmt.Errorf("cannot set predefined variable %s to %q", pv.name(), asgn.mkValue.Dump()))
241}
242
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800243var localProductConfigVariables = map[string]string{
244 "LOCAL_AUDIO_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
245 "LOCAL_AUDIO_PRODUCT_COPY_FILES": "PRODUCT_COPY_FILES",
246 "LOCAL_AUDIO_DEVICE_PACKAGE_OVERLAYS": "DEVICE_PACKAGE_OVERLAYS",
247 "LOCAL_DUMPSTATE_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
248 "LOCAL_GATEKEEPER_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
249 "LOCAL_HEALTH_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
250 "LOCAL_SENSOR_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
251 "LOCAL_KEYMASTER_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
252 "LOCAL_KEYMINT_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
253}
254
255var presetVariables = map[string]bool{
256 "BUILD_ID": true,
257 "HOST_ARCH": true,
258 "HOST_OS": true,
259 "HOST_BUILD_TYPE": true,
260 "OUT_DIR": true,
261 "PLATFORM_VERSION_CODENAME": true,
262 "PLATFORM_VERSION": true,
263 "TARGET_ARCH": true,
264 "TARGET_ARCH_VARIANT": true,
265 "TARGET_BUILD_TYPE": true,
266 "TARGET_BUILD_VARIANT": true,
267 "TARGET_PRODUCT": true,
268}
269
270// addVariable returns a variable with a given name. A variable is
271// added if it does not exist yet.
272func (ctx *parseContext) addVariable(name string) variable {
Cole Faustf92c9f22022-03-14 14:35:50 -0700273 // Get the hintType before potentially changing the variable name
274 var hintType starlarkType
275 var ok bool
276 if hintType, ok = ctx.typeHints[name]; !ok {
277 hintType = starlarkTypeUnknown
278 }
Cole Faust3c4fc992022-02-28 16:05:01 -0800279 // Heuristics: if variable's name is all lowercase, consider it local
280 // string variable.
281 isLocalVariable := name == strings.ToLower(name)
282 // Local variables can't have special characters in them, because they
283 // will be used as starlark identifiers
284 if isLocalVariable {
285 name = strings.ReplaceAll(strings.TrimSpace(name), "-", "_")
286 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800287 v, found := ctx.variables[name]
288 if !found {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800289 if vi, found := KnownVariables[name]; found {
Cole Faustf92c9f22022-03-14 14:35:50 -0700290 _, preset := presetVariables[name]
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800291 switch vi.class {
292 case VarClassConfig:
293 v = &productConfigVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
294 case VarClassSoong:
295 v = &otherGlobalVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
296 }
Cole Faust3c4fc992022-02-28 16:05:01 -0800297 } else if isLocalVariable {
Cole Faustf92c9f22022-03-14 14:35:50 -0700298 v = &localVariable{baseVariable{nam: name, typ: hintType}}
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800299 } else {
Cole Faustf92c9f22022-03-14 14:35:50 -0700300 vt := hintType
Cole Faustf5adedc2022-03-18 14:05:06 -0700301 // Heuristics: local variables that contribute to corresponding config variables
302 if cfgVarName, found := localProductConfigVariables[name]; found && vt == starlarkTypeUnknown {
303 vi, found2 := KnownVariables[cfgVarName]
304 if !found2 {
305 panic(fmt.Errorf("unknown config variable %s for %s", cfgVarName, name))
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800306 }
Cole Faustf5adedc2022-03-18 14:05:06 -0700307 vt = vi.valueType
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800308 }
Sasha Smundak468e11f2021-08-26 09:10:23 -0700309 if strings.HasSuffix(name, "_LIST") && vt == starlarkTypeUnknown {
310 // Heuristics: Variables with "_LIST" suffix are lists
311 vt = starlarkTypeList
312 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800313 v = &otherGlobalVariable{baseVariable{nam: name, typ: vt}}
314 }
315 ctx.variables[name] = v
316 }
317 return v
318}