blob: 0a26ed8b2b5ba61d2bee65240c2987d321298aa5 [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:
112 gctx.writef("if cfg.get(%q) == None:", pcv.nam)
113 gctx.indentLevel++
114 gctx.newLine()
Cole Fauste2a37982022-03-09 16:00:17 -0800115 if needsSetDefault {
116 emitSetDefault()
117 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800118 emitAssignment()
119 gctx.indentLevel--
120 }
Cole Faustf0632662022-04-07 13:59:24 -0700121
122 gctx.setHasBeenAssigned(&pcv)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800123}
124
Cole Faustf0632662022-04-07 13:59:24 -0700125func (pcv productConfigVariable) emitGet(gctx *generationContext) {
126 if gctx.hasBeenAssigned(&pcv) || pcv.isPreset() {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800127 gctx.writef("cfg[%q]", pcv.nam)
128 } else {
129 gctx.writef("cfg.get(%q, %s)", pcv.nam, pcv.defaultValueString())
130 }
131}
132
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800133type otherGlobalVariable struct {
134 baseVariable
135}
136
137func (scv otherGlobalVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
138 emitAssignment := func() {
Cole Faustf0632662022-04-07 13:59:24 -0700139 gctx.writef("g[%q] = ", scv.nam)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800140 asgn.value.emitListVarCopy(gctx)
141 }
142
143 emitAppend := func() {
Cole Faustf0632662022-04-07 13:59:24 -0700144 gctx.writef("g[%q] += ", scv.nam)
Cole Faust0484c232021-12-22 14:08:08 -0800145 value := asgn.value
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800146 if scv.valueType() == starlarkTypeString {
147 gctx.writef(`" " + `)
Cole Faust0484c232021-12-22 14:08:08 -0800148 value = &toStringExpr{expr: value}
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800149 }
Cole Faust0484c232021-12-22 14:08:08 -0800150 value.emit(gctx)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800151 }
152
Cole Fauste2a37982022-03-09 16:00:17 -0800153 // If we are not sure variable has been assigned before, emit setdefault
Cole Faustf0632662022-04-07 13:59:24 -0700154 needsSetDefault := !gctx.hasBeenAssigned(&scv) && !scv.isPreset() && asgn.isSelfReferential()
Cole Fauste2a37982022-03-09 16:00:17 -0800155
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800156 switch asgn.flavor {
157 case asgnSet:
Cole Fauste2a37982022-03-09 16:00:17 -0800158 if needsSetDefault {
159 gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
160 gctx.newLine()
161 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800162 emitAssignment()
163 case asgnAppend:
Cole Fauste2a37982022-03-09 16:00:17 -0800164 if needsSetDefault {
165 gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
166 gctx.newLine()
167 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800168 emitAppend()
169 case asgnMaybeSet:
170 gctx.writef("if g.get(%q) == None:", scv.nam)
171 gctx.indentLevel++
172 gctx.newLine()
Cole Fauste2a37982022-03-09 16:00:17 -0800173 if needsSetDefault {
174 gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
175 gctx.newLine()
176 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800177 emitAssignment()
178 gctx.indentLevel--
179 }
Cole Faustf0632662022-04-07 13:59:24 -0700180
181 gctx.setHasBeenAssigned(&scv)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800182}
183
Cole Faustf0632662022-04-07 13:59:24 -0700184func (scv otherGlobalVariable) emitGet(gctx *generationContext) {
185 if gctx.hasBeenAssigned(&scv) || scv.isPreset() {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800186 gctx.writef("g[%q]", scv.nam)
187 } else {
188 gctx.writef("g.get(%q, %s)", scv.nam, scv.defaultValueString())
189 }
190}
191
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800192type localVariable struct {
193 baseVariable
194}
195
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800196func (lv localVariable) String() string {
197 return "_" + lv.nam
198}
199
200func (lv localVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
201 switch asgn.flavor {
Cole Fauste2a37982022-03-09 16:00:17 -0800202 case asgnSet, asgnMaybeSet:
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800203 gctx.writef("%s = ", lv)
204 asgn.value.emitListVarCopy(gctx)
205 case asgnAppend:
Cole Faustf0632662022-04-07 13:59:24 -0700206 gctx.writef("%s += ", lv)
Cole Faust0484c232021-12-22 14:08:08 -0800207 value := asgn.value
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800208 if lv.valueType() == starlarkTypeString {
209 gctx.writef(`" " + `)
Cole Faust0484c232021-12-22 14:08:08 -0800210 value = &toStringExpr{expr: value}
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800211 }
Cole Faust0484c232021-12-22 14:08:08 -0800212 value.emit(gctx)
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800213 }
214}
215
Cole Faustf0632662022-04-07 13:59:24 -0700216func (lv localVariable) emitGet(gctx *generationContext) {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800217 gctx.writef("%s", lv)
218}
219
220type predefinedVariable struct {
221 baseVariable
222 value starlarkExpr
223}
224
Cole Faustf0632662022-04-07 13:59:24 -0700225func (pv predefinedVariable) emitGet(gctx *generationContext) {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800226 pv.value.emit(gctx)
227}
228
Sasha Smundak6609ba72021-07-22 18:32:56 -0700229func (pv predefinedVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800230 if expectedValue, ok1 := maybeString(pv.value); ok1 {
231 actualValue, ok2 := maybeString(asgn.value)
232 if ok2 {
233 if actualValue == expectedValue {
234 return
235 }
Sasha Smundak422b6142021-11-11 18:31:59 -0800236 gctx.emitConversionError(asgn.location,
237 fmt.Sprintf("cannot set predefined variable %s to %q, its value should be %q",
238 pv.name(), actualValue, expectedValue))
Sasha Smundak6609ba72021-07-22 18:32:56 -0700239 gctx.starScript.hasErrors = true
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800240 return
241 }
242 }
243 panic(fmt.Errorf("cannot set predefined variable %s to %q", pv.name(), asgn.mkValue.Dump()))
244}
245
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800246var 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 {
Cole Faustf92c9f22022-03-14 14:35:50 -0700276 // Get the hintType before potentially changing the variable name
277 var hintType starlarkType
278 var ok bool
279 if hintType, ok = ctx.typeHints[name]; !ok {
280 hintType = starlarkTypeUnknown
281 }
Cole Faust3c4fc992022-02-28 16:05:01 -0800282 // Heuristics: if variable's name is all lowercase, consider it local
283 // string variable.
284 isLocalVariable := name == strings.ToLower(name)
285 // Local variables can't have special characters in them, because they
286 // will be used as starlark identifiers
287 if isLocalVariable {
288 name = strings.ReplaceAll(strings.TrimSpace(name), "-", "_")
289 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800290 v, found := ctx.variables[name]
291 if !found {
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800292 if vi, found := KnownVariables[name]; found {
Cole Faustf92c9f22022-03-14 14:35:50 -0700293 _, preset := presetVariables[name]
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800294 switch vi.class {
295 case VarClassConfig:
296 v = &productConfigVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
297 case VarClassSoong:
298 v = &otherGlobalVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
299 }
Cole Faust3c4fc992022-02-28 16:05:01 -0800300 } else if isLocalVariable {
Cole Faustf92c9f22022-03-14 14:35:50 -0700301 v = &localVariable{baseVariable{nam: name, typ: hintType}}
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800302 } else {
Cole Faustf92c9f22022-03-14 14:35:50 -0700303 vt := hintType
Cole Faustf5adedc2022-03-18 14:05:06 -0700304 // Heuristics: local variables that contribute to corresponding config variables
305 if cfgVarName, found := localProductConfigVariables[name]; found && vt == starlarkTypeUnknown {
306 vi, found2 := KnownVariables[cfgVarName]
307 if !found2 {
308 panic(fmt.Errorf("unknown config variable %s for %s", cfgVarName, name))
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800309 }
Cole Faustf5adedc2022-03-18 14:05:06 -0700310 vt = vi.valueType
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800311 }
Sasha Smundak468e11f2021-08-26 09:10:23 -0700312 if strings.HasSuffix(name, "_LIST") && vt == starlarkTypeUnknown {
313 // Heuristics: Variables with "_LIST" suffix are lists
314 vt = starlarkTypeList
315 }
Sasha Smundakb051c4e2020-11-05 20:45:07 -0800316 v = &otherGlobalVariable{baseVariable{nam: name, typ: vt}}
317 }
318 ctx.variables[name] = v
319 }
320 return v
321}