xref: /aosp_15_r20/build/soong/mk2rbc/variable.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright 2021 Google LLC
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//      http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage mk2rbc
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"fmt"
19*333d2b36SAndroid Build Coastguard Worker	"strings"
20*333d2b36SAndroid Build Coastguard Worker)
21*333d2b36SAndroid Build Coastguard Worker
22*333d2b36SAndroid Build Coastguard Workertype variable interface {
23*333d2b36SAndroid Build Coastguard Worker	name() string
24*333d2b36SAndroid Build Coastguard Worker	emitGet(gctx *generationContext)
25*333d2b36SAndroid Build Coastguard Worker	emitSet(gctx *generationContext, asgn *assignmentNode)
26*333d2b36SAndroid Build Coastguard Worker	valueType() starlarkType
27*333d2b36SAndroid Build Coastguard Worker	setValueType(t starlarkType)
28*333d2b36SAndroid Build Coastguard Worker	defaultValueString() string
29*333d2b36SAndroid Build Coastguard Worker	isPreset() bool
30*333d2b36SAndroid Build Coastguard Worker}
31*333d2b36SAndroid Build Coastguard Worker
32*333d2b36SAndroid Build Coastguard Workertype baseVariable struct {
33*333d2b36SAndroid Build Coastguard Worker	nam    string
34*333d2b36SAndroid Build Coastguard Worker	typ    starlarkType
35*333d2b36SAndroid Build Coastguard Worker	preset bool // true if it has been initialized at startup
36*333d2b36SAndroid Build Coastguard Worker}
37*333d2b36SAndroid Build Coastguard Worker
38*333d2b36SAndroid Build Coastguard Workerfunc (v baseVariable) name() string {
39*333d2b36SAndroid Build Coastguard Worker	return v.nam
40*333d2b36SAndroid Build Coastguard Worker}
41*333d2b36SAndroid Build Coastguard Worker
42*333d2b36SAndroid Build Coastguard Workerfunc (v baseVariable) valueType() starlarkType {
43*333d2b36SAndroid Build Coastguard Worker	return v.typ
44*333d2b36SAndroid Build Coastguard Worker}
45*333d2b36SAndroid Build Coastguard Worker
46*333d2b36SAndroid Build Coastguard Workerfunc (v *baseVariable) setValueType(t starlarkType) {
47*333d2b36SAndroid Build Coastguard Worker	v.typ = t
48*333d2b36SAndroid Build Coastguard Worker}
49*333d2b36SAndroid Build Coastguard Worker
50*333d2b36SAndroid Build Coastguard Workerfunc (v baseVariable) isPreset() bool {
51*333d2b36SAndroid Build Coastguard Worker	return v.preset
52*333d2b36SAndroid Build Coastguard Worker}
53*333d2b36SAndroid Build Coastguard Worker
54*333d2b36SAndroid Build Coastguard Workervar defaultValuesByType = map[starlarkType]string{
55*333d2b36SAndroid Build Coastguard Worker	starlarkTypeUnknown: `""`,
56*333d2b36SAndroid Build Coastguard Worker	starlarkTypeList:    "[]",
57*333d2b36SAndroid Build Coastguard Worker	starlarkTypeString:  `""`,
58*333d2b36SAndroid Build Coastguard Worker	starlarkTypeInt:     "0",
59*333d2b36SAndroid Build Coastguard Worker	starlarkTypeBool:    "False",
60*333d2b36SAndroid Build Coastguard Worker	starlarkTypeVoid:    "None",
61*333d2b36SAndroid Build Coastguard Worker}
62*333d2b36SAndroid Build Coastguard Worker
63*333d2b36SAndroid Build Coastguard Workerfunc (v baseVariable) defaultValueString() string {
64*333d2b36SAndroid Build Coastguard Worker	if v, ok := defaultValuesByType[v.valueType()]; ok {
65*333d2b36SAndroid Build Coastguard Worker		return v
66*333d2b36SAndroid Build Coastguard Worker	}
67*333d2b36SAndroid Build Coastguard Worker	panic(fmt.Errorf("%s has unknown type %q", v.name(), v.valueType()))
68*333d2b36SAndroid Build Coastguard Worker}
69*333d2b36SAndroid Build Coastguard Worker
70*333d2b36SAndroid Build Coastguard Workertype productConfigVariable struct {
71*333d2b36SAndroid Build Coastguard Worker	baseVariable
72*333d2b36SAndroid Build Coastguard Worker}
73*333d2b36SAndroid Build Coastguard Worker
74*333d2b36SAndroid Build Coastguard Workerfunc (pcv productConfigVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
75*333d2b36SAndroid Build Coastguard Worker	emitAssignment := func() {
76*333d2b36SAndroid Build Coastguard Worker		gctx.writef("cfg[%q] = ", pcv.nam)
77*333d2b36SAndroid Build Coastguard Worker		asgn.value.emitListVarCopy(gctx)
78*333d2b36SAndroid Build Coastguard Worker	}
79*333d2b36SAndroid Build Coastguard Worker	emitAppend := func() {
80*333d2b36SAndroid Build Coastguard Worker		gctx.writef("cfg[%q] += ", pcv.nam)
81*333d2b36SAndroid Build Coastguard Worker		value := asgn.value
82*333d2b36SAndroid Build Coastguard Worker		if pcv.valueType() == starlarkTypeString {
83*333d2b36SAndroid Build Coastguard Worker			gctx.writef(`" " + `)
84*333d2b36SAndroid Build Coastguard Worker			value = &toStringExpr{expr: value}
85*333d2b36SAndroid Build Coastguard Worker		}
86*333d2b36SAndroid Build Coastguard Worker		value.emit(gctx)
87*333d2b36SAndroid Build Coastguard Worker	}
88*333d2b36SAndroid Build Coastguard Worker	emitSetDefault := func() {
89*333d2b36SAndroid Build Coastguard Worker		if pcv.typ == starlarkTypeList {
90*333d2b36SAndroid Build Coastguard Worker			gctx.writef("%s(handle, %q)", cfnSetListDefault, pcv.name())
91*333d2b36SAndroid Build Coastguard Worker		} else {
92*333d2b36SAndroid Build Coastguard Worker			gctx.writef("cfg.setdefault(%q, %s)", pcv.name(), pcv.defaultValueString())
93*333d2b36SAndroid Build Coastguard Worker		}
94*333d2b36SAndroid Build Coastguard Worker		gctx.newLine()
95*333d2b36SAndroid Build Coastguard Worker	}
96*333d2b36SAndroid Build Coastguard Worker
97*333d2b36SAndroid Build Coastguard Worker	// If we are not sure variable has been assigned before, emit setdefault
98*333d2b36SAndroid Build Coastguard Worker	needsSetDefault := !gctx.hasBeenAssigned(&pcv) && !pcv.isPreset() && asgn.isSelfReferential()
99*333d2b36SAndroid Build Coastguard Worker
100*333d2b36SAndroid Build Coastguard Worker	switch asgn.flavor {
101*333d2b36SAndroid Build Coastguard Worker	case asgnSet:
102*333d2b36SAndroid Build Coastguard Worker		if needsSetDefault {
103*333d2b36SAndroid Build Coastguard Worker			emitSetDefault()
104*333d2b36SAndroid Build Coastguard Worker		}
105*333d2b36SAndroid Build Coastguard Worker		emitAssignment()
106*333d2b36SAndroid Build Coastguard Worker	case asgnAppend:
107*333d2b36SAndroid Build Coastguard Worker		if needsSetDefault {
108*333d2b36SAndroid Build Coastguard Worker			emitSetDefault()
109*333d2b36SAndroid Build Coastguard Worker		}
110*333d2b36SAndroid Build Coastguard Worker		emitAppend()
111*333d2b36SAndroid Build Coastguard Worker	case asgnMaybeSet:
112*333d2b36SAndroid Build Coastguard Worker		// In mk2rbc.go we never emit a maybeSet assignment for product config variables, because
113*333d2b36SAndroid Build Coastguard Worker		// they are set to empty strings before running product config.
114*333d2b36SAndroid Build Coastguard Worker		panic("Should never get here")
115*333d2b36SAndroid Build Coastguard Worker	default:
116*333d2b36SAndroid Build Coastguard Worker		panic("Unknown assignment flavor")
117*333d2b36SAndroid Build Coastguard Worker	}
118*333d2b36SAndroid Build Coastguard Worker
119*333d2b36SAndroid Build Coastguard Worker	gctx.setHasBeenAssigned(&pcv)
120*333d2b36SAndroid Build Coastguard Worker}
121*333d2b36SAndroid Build Coastguard Worker
122*333d2b36SAndroid Build Coastguard Workerfunc (pcv productConfigVariable) emitGet(gctx *generationContext) {
123*333d2b36SAndroid Build Coastguard Worker	if gctx.hasBeenAssigned(&pcv) || pcv.isPreset() {
124*333d2b36SAndroid Build Coastguard Worker		gctx.writef("cfg[%q]", pcv.nam)
125*333d2b36SAndroid Build Coastguard Worker	} else {
126*333d2b36SAndroid Build Coastguard Worker		gctx.writef("cfg.get(%q, %s)", pcv.nam, pcv.defaultValueString())
127*333d2b36SAndroid Build Coastguard Worker	}
128*333d2b36SAndroid Build Coastguard Worker}
129*333d2b36SAndroid Build Coastguard Worker
130*333d2b36SAndroid Build Coastguard Workertype otherGlobalVariable struct {
131*333d2b36SAndroid Build Coastguard Worker	baseVariable
132*333d2b36SAndroid Build Coastguard Worker}
133*333d2b36SAndroid Build Coastguard Worker
134*333d2b36SAndroid Build Coastguard Workerfunc (scv otherGlobalVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
135*333d2b36SAndroid Build Coastguard Worker	emitAssignment := func() {
136*333d2b36SAndroid Build Coastguard Worker		gctx.writef("g[%q] = ", scv.nam)
137*333d2b36SAndroid Build Coastguard Worker		asgn.value.emitListVarCopy(gctx)
138*333d2b36SAndroid Build Coastguard Worker	}
139*333d2b36SAndroid Build Coastguard Worker
140*333d2b36SAndroid Build Coastguard Worker	emitAppend := func() {
141*333d2b36SAndroid Build Coastguard Worker		gctx.writef("g[%q] += ", scv.nam)
142*333d2b36SAndroid Build Coastguard Worker		value := asgn.value
143*333d2b36SAndroid Build Coastguard Worker		if scv.valueType() == starlarkTypeString {
144*333d2b36SAndroid Build Coastguard Worker			gctx.writef(`" " + `)
145*333d2b36SAndroid Build Coastguard Worker			value = &toStringExpr{expr: value}
146*333d2b36SAndroid Build Coastguard Worker		}
147*333d2b36SAndroid Build Coastguard Worker		value.emit(gctx)
148*333d2b36SAndroid Build Coastguard Worker	}
149*333d2b36SAndroid Build Coastguard Worker
150*333d2b36SAndroid Build Coastguard Worker	// If we are not sure variable has been assigned before, emit setdefault
151*333d2b36SAndroid Build Coastguard Worker	needsSetDefault := !gctx.hasBeenAssigned(&scv) && !scv.isPreset() && asgn.isSelfReferential()
152*333d2b36SAndroid Build Coastguard Worker
153*333d2b36SAndroid Build Coastguard Worker	switch asgn.flavor {
154*333d2b36SAndroid Build Coastguard Worker	case asgnSet:
155*333d2b36SAndroid Build Coastguard Worker		if needsSetDefault {
156*333d2b36SAndroid Build Coastguard Worker			gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
157*333d2b36SAndroid Build Coastguard Worker			gctx.newLine()
158*333d2b36SAndroid Build Coastguard Worker		}
159*333d2b36SAndroid Build Coastguard Worker		emitAssignment()
160*333d2b36SAndroid Build Coastguard Worker	case asgnAppend:
161*333d2b36SAndroid Build Coastguard Worker		if needsSetDefault {
162*333d2b36SAndroid Build Coastguard Worker			gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
163*333d2b36SAndroid Build Coastguard Worker			gctx.newLine()
164*333d2b36SAndroid Build Coastguard Worker		}
165*333d2b36SAndroid Build Coastguard Worker		emitAppend()
166*333d2b36SAndroid Build Coastguard Worker	case asgnMaybeSet:
167*333d2b36SAndroid Build Coastguard Worker		gctx.writef("if g.get(%q) == None:", scv.nam)
168*333d2b36SAndroid Build Coastguard Worker		gctx.indentLevel++
169*333d2b36SAndroid Build Coastguard Worker		gctx.newLine()
170*333d2b36SAndroid Build Coastguard Worker		if needsSetDefault {
171*333d2b36SAndroid Build Coastguard Worker			gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
172*333d2b36SAndroid Build Coastguard Worker			gctx.newLine()
173*333d2b36SAndroid Build Coastguard Worker		}
174*333d2b36SAndroid Build Coastguard Worker		emitAssignment()
175*333d2b36SAndroid Build Coastguard Worker		gctx.indentLevel--
176*333d2b36SAndroid Build Coastguard Worker	}
177*333d2b36SAndroid Build Coastguard Worker
178*333d2b36SAndroid Build Coastguard Worker	gctx.setHasBeenAssigned(&scv)
179*333d2b36SAndroid Build Coastguard Worker}
180*333d2b36SAndroid Build Coastguard Worker
181*333d2b36SAndroid Build Coastguard Workerfunc (scv otherGlobalVariable) emitGet(gctx *generationContext) {
182*333d2b36SAndroid Build Coastguard Worker	if gctx.hasBeenAssigned(&scv) || scv.isPreset() {
183*333d2b36SAndroid Build Coastguard Worker		gctx.writef("g[%q]", scv.nam)
184*333d2b36SAndroid Build Coastguard Worker	} else {
185*333d2b36SAndroid Build Coastguard Worker		gctx.writef("g.get(%q, %s)", scv.nam, scv.defaultValueString())
186*333d2b36SAndroid Build Coastguard Worker	}
187*333d2b36SAndroid Build Coastguard Worker}
188*333d2b36SAndroid Build Coastguard Worker
189*333d2b36SAndroid Build Coastguard Workertype localVariable struct {
190*333d2b36SAndroid Build Coastguard Worker	baseVariable
191*333d2b36SAndroid Build Coastguard Worker}
192*333d2b36SAndroid Build Coastguard Worker
193*333d2b36SAndroid Build Coastguard Workerfunc (lv localVariable) String() string {
194*333d2b36SAndroid Build Coastguard Worker	return "_" + lv.nam
195*333d2b36SAndroid Build Coastguard Worker}
196*333d2b36SAndroid Build Coastguard Worker
197*333d2b36SAndroid Build Coastguard Workerfunc (lv localVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
198*333d2b36SAndroid Build Coastguard Worker	switch asgn.flavor {
199*333d2b36SAndroid Build Coastguard Worker	case asgnSet, asgnMaybeSet:
200*333d2b36SAndroid Build Coastguard Worker		gctx.writef("%s = ", lv)
201*333d2b36SAndroid Build Coastguard Worker		asgn.value.emitListVarCopy(gctx)
202*333d2b36SAndroid Build Coastguard Worker	case asgnAppend:
203*333d2b36SAndroid Build Coastguard Worker		gctx.writef("%s += ", lv)
204*333d2b36SAndroid Build Coastguard Worker		value := asgn.value
205*333d2b36SAndroid Build Coastguard Worker		if lv.valueType() == starlarkTypeString {
206*333d2b36SAndroid Build Coastguard Worker			gctx.writef(`" " + `)
207*333d2b36SAndroid Build Coastguard Worker			value = &toStringExpr{expr: value}
208*333d2b36SAndroid Build Coastguard Worker		}
209*333d2b36SAndroid Build Coastguard Worker		value.emit(gctx)
210*333d2b36SAndroid Build Coastguard Worker	}
211*333d2b36SAndroid Build Coastguard Worker}
212*333d2b36SAndroid Build Coastguard Worker
213*333d2b36SAndroid Build Coastguard Workerfunc (lv localVariable) emitGet(gctx *generationContext) {
214*333d2b36SAndroid Build Coastguard Worker	gctx.writef("%s", lv)
215*333d2b36SAndroid Build Coastguard Worker}
216*333d2b36SAndroid Build Coastguard Worker
217*333d2b36SAndroid Build Coastguard Workertype predefinedVariable struct {
218*333d2b36SAndroid Build Coastguard Worker	baseVariable
219*333d2b36SAndroid Build Coastguard Worker	value starlarkExpr
220*333d2b36SAndroid Build Coastguard Worker}
221*333d2b36SAndroid Build Coastguard Worker
222*333d2b36SAndroid Build Coastguard Workerfunc (pv predefinedVariable) emitGet(gctx *generationContext) {
223*333d2b36SAndroid Build Coastguard Worker	pv.value.emit(gctx)
224*333d2b36SAndroid Build Coastguard Worker}
225*333d2b36SAndroid Build Coastguard Worker
226*333d2b36SAndroid Build Coastguard Workerfunc (pv predefinedVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
227*333d2b36SAndroid Build Coastguard Worker	if expectedValue, ok1 := maybeString(pv.value); ok1 {
228*333d2b36SAndroid Build Coastguard Worker		actualValue, ok2 := maybeString(asgn.value)
229*333d2b36SAndroid Build Coastguard Worker		if ok2 {
230*333d2b36SAndroid Build Coastguard Worker			if actualValue == expectedValue {
231*333d2b36SAndroid Build Coastguard Worker				return
232*333d2b36SAndroid Build Coastguard Worker			}
233*333d2b36SAndroid Build Coastguard Worker			gctx.emitConversionError(asgn.location,
234*333d2b36SAndroid Build Coastguard Worker				fmt.Sprintf("cannot set predefined variable %s to %q, its value should be %q",
235*333d2b36SAndroid Build Coastguard Worker					pv.name(), actualValue, expectedValue))
236*333d2b36SAndroid Build Coastguard Worker			gctx.starScript.hasErrors = true
237*333d2b36SAndroid Build Coastguard Worker			return
238*333d2b36SAndroid Build Coastguard Worker		}
239*333d2b36SAndroid Build Coastguard Worker	}
240*333d2b36SAndroid Build Coastguard Worker	panic(fmt.Errorf("cannot set predefined variable %s to %q", pv.name(), asgn.mkValue.Dump()))
241*333d2b36SAndroid Build Coastguard Worker}
242*333d2b36SAndroid Build Coastguard Worker
243*333d2b36SAndroid Build Coastguard Workervar localProductConfigVariables = map[string]string{
244*333d2b36SAndroid Build Coastguard Worker	"LOCAL_AUDIO_PRODUCT_PACKAGE":         "PRODUCT_PACKAGES",
245*333d2b36SAndroid Build Coastguard Worker	"LOCAL_AUDIO_PRODUCT_COPY_FILES":      "PRODUCT_COPY_FILES",
246*333d2b36SAndroid Build Coastguard Worker	"LOCAL_AUDIO_DEVICE_PACKAGE_OVERLAYS": "DEVICE_PACKAGE_OVERLAYS",
247*333d2b36SAndroid Build Coastguard Worker	"LOCAL_DUMPSTATE_PRODUCT_PACKAGE":     "PRODUCT_PACKAGES",
248*333d2b36SAndroid Build Coastguard Worker	"LOCAL_GATEKEEPER_PRODUCT_PACKAGE":    "PRODUCT_PACKAGES",
249*333d2b36SAndroid Build Coastguard Worker	"LOCAL_HEALTH_PRODUCT_PACKAGE":        "PRODUCT_PACKAGES",
250*333d2b36SAndroid Build Coastguard Worker	"LOCAL_SENSOR_PRODUCT_PACKAGE":        "PRODUCT_PACKAGES",
251*333d2b36SAndroid Build Coastguard Worker	"LOCAL_KEYMASTER_PRODUCT_PACKAGE":     "PRODUCT_PACKAGES",
252*333d2b36SAndroid Build Coastguard Worker	"LOCAL_KEYMINT_PRODUCT_PACKAGE":       "PRODUCT_PACKAGES",
253*333d2b36SAndroid Build Coastguard Worker}
254*333d2b36SAndroid Build Coastguard Worker
255*333d2b36SAndroid Build Coastguard Workervar presetVariables = map[string]bool{
256*333d2b36SAndroid Build Coastguard Worker	"BUILD_ID":                  true,
257*333d2b36SAndroid Build Coastguard Worker	"HOST_ARCH":                 true,
258*333d2b36SAndroid Build Coastguard Worker	"HOST_OS":                   true,
259*333d2b36SAndroid Build Coastguard Worker	"HOST_BUILD_TYPE":           true,
260*333d2b36SAndroid Build Coastguard Worker	"OUT_DIR":                   true,
261*333d2b36SAndroid Build Coastguard Worker	"PLATFORM_VERSION_CODENAME": true,
262*333d2b36SAndroid Build Coastguard Worker	"PLATFORM_VERSION":          true,
263*333d2b36SAndroid Build Coastguard Worker	"TARGET_ARCH":               true,
264*333d2b36SAndroid Build Coastguard Worker	"TARGET_ARCH_VARIANT":       true,
265*333d2b36SAndroid Build Coastguard Worker	"TARGET_BUILD_TYPE":         true,
266*333d2b36SAndroid Build Coastguard Worker	"TARGET_BUILD_VARIANT":      true,
267*333d2b36SAndroid Build Coastguard Worker	"TARGET_PRODUCT":            true,
268*333d2b36SAndroid Build Coastguard Worker}
269*333d2b36SAndroid Build Coastguard Worker
270*333d2b36SAndroid Build Coastguard Worker// addVariable returns a variable with a given name. A variable is
271*333d2b36SAndroid Build Coastguard Worker// added if it does not exist yet.
272*333d2b36SAndroid Build Coastguard Workerfunc (ctx *parseContext) addVariable(name string) variable {
273*333d2b36SAndroid Build Coastguard Worker	// Get the hintType before potentially changing the variable name
274*333d2b36SAndroid Build Coastguard Worker	var hintType starlarkType
275*333d2b36SAndroid Build Coastguard Worker	var ok bool
276*333d2b36SAndroid Build Coastguard Worker	if hintType, ok = ctx.typeHints[name]; !ok {
277*333d2b36SAndroid Build Coastguard Worker		hintType = starlarkTypeUnknown
278*333d2b36SAndroid Build Coastguard Worker	}
279*333d2b36SAndroid Build Coastguard Worker	// Heuristics: if variable's name is all lowercase, consider it local
280*333d2b36SAndroid Build Coastguard Worker	// string variable.
281*333d2b36SAndroid Build Coastguard Worker	isLocalVariable := name == strings.ToLower(name)
282*333d2b36SAndroid Build Coastguard Worker	// Local variables can't have special characters in them, because they
283*333d2b36SAndroid Build Coastguard Worker	// will be used as starlark identifiers
284*333d2b36SAndroid Build Coastguard Worker	if isLocalVariable {
285*333d2b36SAndroid Build Coastguard Worker		name = strings.ReplaceAll(strings.TrimSpace(name), "-", "_")
286*333d2b36SAndroid Build Coastguard Worker	}
287*333d2b36SAndroid Build Coastguard Worker	v, found := ctx.variables[name]
288*333d2b36SAndroid Build Coastguard Worker	if !found {
289*333d2b36SAndroid Build Coastguard Worker		if vi, found := KnownVariables[name]; found {
290*333d2b36SAndroid Build Coastguard Worker			_, preset := presetVariables[name]
291*333d2b36SAndroid Build Coastguard Worker			switch vi.class {
292*333d2b36SAndroid Build Coastguard Worker			case VarClassConfig:
293*333d2b36SAndroid Build Coastguard Worker				v = &productConfigVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
294*333d2b36SAndroid Build Coastguard Worker			case VarClassSoong:
295*333d2b36SAndroid Build Coastguard Worker				v = &otherGlobalVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
296*333d2b36SAndroid Build Coastguard Worker			}
297*333d2b36SAndroid Build Coastguard Worker		} else if isLocalVariable {
298*333d2b36SAndroid Build Coastguard Worker			v = &localVariable{baseVariable{nam: name, typ: hintType}}
299*333d2b36SAndroid Build Coastguard Worker		} else {
300*333d2b36SAndroid Build Coastguard Worker			vt := hintType
301*333d2b36SAndroid Build Coastguard Worker			// Heuristics: local variables that contribute to corresponding config variables
302*333d2b36SAndroid Build Coastguard Worker			if cfgVarName, found := localProductConfigVariables[name]; found && vt == starlarkTypeUnknown {
303*333d2b36SAndroid Build Coastguard Worker				vi, found2 := KnownVariables[cfgVarName]
304*333d2b36SAndroid Build Coastguard Worker				if !found2 {
305*333d2b36SAndroid Build Coastguard Worker					panic(fmt.Errorf("unknown config variable %s for %s", cfgVarName, name))
306*333d2b36SAndroid Build Coastguard Worker				}
307*333d2b36SAndroid Build Coastguard Worker				vt = vi.valueType
308*333d2b36SAndroid Build Coastguard Worker			}
309*333d2b36SAndroid Build Coastguard Worker			if strings.HasSuffix(name, "_LIST") && vt == starlarkTypeUnknown {
310*333d2b36SAndroid Build Coastguard Worker				// Heuristics: Variables with "_LIST" suffix are lists
311*333d2b36SAndroid Build Coastguard Worker				vt = starlarkTypeList
312*333d2b36SAndroid Build Coastguard Worker			}
313*333d2b36SAndroid Build Coastguard Worker			v = &otherGlobalVariable{baseVariable{nam: name, typ: vt}}
314*333d2b36SAndroid Build Coastguard Worker		}
315*333d2b36SAndroid Build Coastguard Worker		ctx.variables[name] = v
316*333d2b36SAndroid Build Coastguard Worker	}
317*333d2b36SAndroid Build Coastguard Worker	return v
318*333d2b36SAndroid Build Coastguard Worker}
319