2020-11-06 05:45:07 +01:00
|
|
|
// Copyright 2021 Google LLC
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package mk2rbc
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
type variable interface {
|
|
|
|
name() string
|
2022-04-07 22:59:24 +02:00
|
|
|
emitGet(gctx *generationContext)
|
2020-11-06 05:45:07 +01:00
|
|
|
emitSet(gctx *generationContext, asgn *assignmentNode)
|
|
|
|
valueType() starlarkType
|
2021-07-10 01:00:57 +02:00
|
|
|
setValueType(t starlarkType)
|
2020-11-06 05:45:07 +01:00
|
|
|
defaultValueString() string
|
|
|
|
isPreset() bool
|
|
|
|
}
|
|
|
|
|
|
|
|
type baseVariable struct {
|
|
|
|
nam string
|
|
|
|
typ starlarkType
|
|
|
|
preset bool // true if it has been initialized at startup
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v baseVariable) name() string {
|
|
|
|
return v.nam
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v baseVariable) valueType() starlarkType {
|
|
|
|
return v.typ
|
|
|
|
}
|
|
|
|
|
2021-07-10 01:00:57 +02:00
|
|
|
func (v *baseVariable) setValueType(t starlarkType) {
|
|
|
|
v.typ = t
|
|
|
|
}
|
|
|
|
|
2020-11-06 05:45:07 +01:00
|
|
|
func (v baseVariable) isPreset() bool {
|
|
|
|
return v.preset
|
|
|
|
}
|
|
|
|
|
|
|
|
var defaultValuesByType = map[starlarkType]string{
|
|
|
|
starlarkTypeUnknown: `""`,
|
|
|
|
starlarkTypeList: "[]",
|
|
|
|
starlarkTypeString: `""`,
|
|
|
|
starlarkTypeInt: "0",
|
|
|
|
starlarkTypeBool: "False",
|
|
|
|
starlarkTypeVoid: "None",
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v baseVariable) defaultValueString() string {
|
|
|
|
if v, ok := defaultValuesByType[v.valueType()]; ok {
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
panic(fmt.Errorf("%s has unknown type %q", v.name(), v.valueType()))
|
|
|
|
}
|
|
|
|
|
|
|
|
type productConfigVariable struct {
|
|
|
|
baseVariable
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pcv productConfigVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
|
|
|
|
emitAssignment := func() {
|
2022-04-07 22:59:24 +02:00
|
|
|
gctx.writef("cfg[%q] = ", pcv.nam)
|
2020-11-06 05:45:07 +01:00
|
|
|
asgn.value.emitListVarCopy(gctx)
|
|
|
|
}
|
|
|
|
emitAppend := func() {
|
2022-04-07 22:59:24 +02:00
|
|
|
gctx.writef("cfg[%q] += ", pcv.nam)
|
2021-12-22 23:08:08 +01:00
|
|
|
value := asgn.value
|
2020-11-06 05:45:07 +01:00
|
|
|
if pcv.valueType() == starlarkTypeString {
|
|
|
|
gctx.writef(`" " + `)
|
2021-12-22 23:08:08 +01:00
|
|
|
value = &toStringExpr{expr: value}
|
2020-11-06 05:45:07 +01:00
|
|
|
}
|
2021-12-22 23:08:08 +01:00
|
|
|
value.emit(gctx)
|
2020-11-06 05:45:07 +01:00
|
|
|
}
|
2022-03-04 21:04:31 +01:00
|
|
|
emitSetDefault := func() {
|
|
|
|
if pcv.typ == starlarkTypeList {
|
|
|
|
gctx.writef("%s(handle, %q)", cfnSetListDefault, pcv.name())
|
|
|
|
} else {
|
|
|
|
gctx.writef("cfg.setdefault(%q, %s)", pcv.name(), pcv.defaultValueString())
|
|
|
|
}
|
|
|
|
gctx.newLine()
|
|
|
|
}
|
2020-11-06 05:45:07 +01:00
|
|
|
|
2022-03-10 01:00:17 +01:00
|
|
|
// If we are not sure variable has been assigned before, emit setdefault
|
2022-04-07 22:59:24 +02:00
|
|
|
needsSetDefault := !gctx.hasBeenAssigned(&pcv) && !pcv.isPreset() && asgn.isSelfReferential()
|
2022-03-10 01:00:17 +01:00
|
|
|
|
2020-11-06 05:45:07 +01:00
|
|
|
switch asgn.flavor {
|
|
|
|
case asgnSet:
|
2022-03-10 01:00:17 +01:00
|
|
|
if needsSetDefault {
|
2022-03-04 21:04:31 +01:00
|
|
|
emitSetDefault()
|
|
|
|
}
|
2020-11-06 05:45:07 +01:00
|
|
|
emitAssignment()
|
|
|
|
case asgnAppend:
|
2022-03-10 01:00:17 +01:00
|
|
|
if needsSetDefault {
|
|
|
|
emitSetDefault()
|
|
|
|
}
|
2020-11-06 05:45:07 +01:00
|
|
|
emitAppend()
|
|
|
|
case asgnMaybeSet:
|
2023-10-09 21:26:21 +02:00
|
|
|
// In mk2rbc.go we never emit a maybeSet assignment for product config variables, because
|
|
|
|
// they are set to empty strings before running product config.
|
|
|
|
panic("Should never get here")
|
|
|
|
default:
|
|
|
|
panic("Unknown assignment flavor")
|
2020-11-06 05:45:07 +01:00
|
|
|
}
|
2022-04-07 22:59:24 +02:00
|
|
|
|
|
|
|
gctx.setHasBeenAssigned(&pcv)
|
2020-11-06 05:45:07 +01:00
|
|
|
}
|
|
|
|
|
2022-04-07 22:59:24 +02:00
|
|
|
func (pcv productConfigVariable) emitGet(gctx *generationContext) {
|
|
|
|
if gctx.hasBeenAssigned(&pcv) || pcv.isPreset() {
|
2020-11-06 05:45:07 +01:00
|
|
|
gctx.writef("cfg[%q]", pcv.nam)
|
|
|
|
} else {
|
|
|
|
gctx.writef("cfg.get(%q, %s)", pcv.nam, pcv.defaultValueString())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type otherGlobalVariable struct {
|
|
|
|
baseVariable
|
|
|
|
}
|
|
|
|
|
|
|
|
func (scv otherGlobalVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
|
|
|
|
emitAssignment := func() {
|
2022-04-07 22:59:24 +02:00
|
|
|
gctx.writef("g[%q] = ", scv.nam)
|
2020-11-06 05:45:07 +01:00
|
|
|
asgn.value.emitListVarCopy(gctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
emitAppend := func() {
|
2022-04-07 22:59:24 +02:00
|
|
|
gctx.writef("g[%q] += ", scv.nam)
|
2021-12-22 23:08:08 +01:00
|
|
|
value := asgn.value
|
2020-11-06 05:45:07 +01:00
|
|
|
if scv.valueType() == starlarkTypeString {
|
|
|
|
gctx.writef(`" " + `)
|
2021-12-22 23:08:08 +01:00
|
|
|
value = &toStringExpr{expr: value}
|
2020-11-06 05:45:07 +01:00
|
|
|
}
|
2021-12-22 23:08:08 +01:00
|
|
|
value.emit(gctx)
|
2020-11-06 05:45:07 +01:00
|
|
|
}
|
|
|
|
|
2022-03-10 01:00:17 +01:00
|
|
|
// If we are not sure variable has been assigned before, emit setdefault
|
2022-04-07 22:59:24 +02:00
|
|
|
needsSetDefault := !gctx.hasBeenAssigned(&scv) && !scv.isPreset() && asgn.isSelfReferential()
|
2022-03-10 01:00:17 +01:00
|
|
|
|
2020-11-06 05:45:07 +01:00
|
|
|
switch asgn.flavor {
|
|
|
|
case asgnSet:
|
2022-03-10 01:00:17 +01:00
|
|
|
if needsSetDefault {
|
|
|
|
gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
|
|
|
|
gctx.newLine()
|
|
|
|
}
|
2020-11-06 05:45:07 +01:00
|
|
|
emitAssignment()
|
|
|
|
case asgnAppend:
|
2022-03-10 01:00:17 +01:00
|
|
|
if needsSetDefault {
|
|
|
|
gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
|
|
|
|
gctx.newLine()
|
|
|
|
}
|
2020-11-06 05:45:07 +01:00
|
|
|
emitAppend()
|
|
|
|
case asgnMaybeSet:
|
|
|
|
gctx.writef("if g.get(%q) == None:", scv.nam)
|
|
|
|
gctx.indentLevel++
|
|
|
|
gctx.newLine()
|
2022-03-10 01:00:17 +01:00
|
|
|
if needsSetDefault {
|
|
|
|
gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
|
|
|
|
gctx.newLine()
|
|
|
|
}
|
2020-11-06 05:45:07 +01:00
|
|
|
emitAssignment()
|
|
|
|
gctx.indentLevel--
|
|
|
|
}
|
2022-04-07 22:59:24 +02:00
|
|
|
|
|
|
|
gctx.setHasBeenAssigned(&scv)
|
2020-11-06 05:45:07 +01:00
|
|
|
}
|
|
|
|
|
2022-04-07 22:59:24 +02:00
|
|
|
func (scv otherGlobalVariable) emitGet(gctx *generationContext) {
|
|
|
|
if gctx.hasBeenAssigned(&scv) || scv.isPreset() {
|
2020-11-06 05:45:07 +01:00
|
|
|
gctx.writef("g[%q]", scv.nam)
|
|
|
|
} else {
|
|
|
|
gctx.writef("g.get(%q, %s)", scv.nam, scv.defaultValueString())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type localVariable struct {
|
|
|
|
baseVariable
|
|
|
|
}
|
|
|
|
|
|
|
|
func (lv localVariable) String() string {
|
|
|
|
return "_" + lv.nam
|
|
|
|
}
|
|
|
|
|
|
|
|
func (lv localVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
|
|
|
|
switch asgn.flavor {
|
2022-03-10 01:00:17 +01:00
|
|
|
case asgnSet, asgnMaybeSet:
|
2020-11-06 05:45:07 +01:00
|
|
|
gctx.writef("%s = ", lv)
|
|
|
|
asgn.value.emitListVarCopy(gctx)
|
|
|
|
case asgnAppend:
|
2022-04-07 22:59:24 +02:00
|
|
|
gctx.writef("%s += ", lv)
|
2021-12-22 23:08:08 +01:00
|
|
|
value := asgn.value
|
2020-11-06 05:45:07 +01:00
|
|
|
if lv.valueType() == starlarkTypeString {
|
|
|
|
gctx.writef(`" " + `)
|
2021-12-22 23:08:08 +01:00
|
|
|
value = &toStringExpr{expr: value}
|
2020-11-06 05:45:07 +01:00
|
|
|
}
|
2021-12-22 23:08:08 +01:00
|
|
|
value.emit(gctx)
|
2020-11-06 05:45:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-07 22:59:24 +02:00
|
|
|
func (lv localVariable) emitGet(gctx *generationContext) {
|
2020-11-06 05:45:07 +01:00
|
|
|
gctx.writef("%s", lv)
|
|
|
|
}
|
|
|
|
|
|
|
|
type predefinedVariable struct {
|
|
|
|
baseVariable
|
|
|
|
value starlarkExpr
|
|
|
|
}
|
|
|
|
|
2022-04-07 22:59:24 +02:00
|
|
|
func (pv predefinedVariable) emitGet(gctx *generationContext) {
|
2020-11-06 05:45:07 +01:00
|
|
|
pv.value.emit(gctx)
|
|
|
|
}
|
|
|
|
|
2021-07-23 03:32:56 +02:00
|
|
|
func (pv predefinedVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
|
2020-11-06 05:45:07 +01:00
|
|
|
if expectedValue, ok1 := maybeString(pv.value); ok1 {
|
|
|
|
actualValue, ok2 := maybeString(asgn.value)
|
|
|
|
if ok2 {
|
|
|
|
if actualValue == expectedValue {
|
|
|
|
return
|
|
|
|
}
|
2021-11-12 03:31:59 +01:00
|
|
|
gctx.emitConversionError(asgn.location,
|
|
|
|
fmt.Sprintf("cannot set predefined variable %s to %q, its value should be %q",
|
|
|
|
pv.name(), actualValue, expectedValue))
|
2021-07-23 03:32:56 +02:00
|
|
|
gctx.starScript.hasErrors = true
|
2020-11-06 05:45:07 +01:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
panic(fmt.Errorf("cannot set predefined variable %s to %q", pv.name(), asgn.mkValue.Dump()))
|
|
|
|
}
|
|
|
|
|
|
|
|
var localProductConfigVariables = map[string]string{
|
|
|
|
"LOCAL_AUDIO_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
|
|
|
|
"LOCAL_AUDIO_PRODUCT_COPY_FILES": "PRODUCT_COPY_FILES",
|
|
|
|
"LOCAL_AUDIO_DEVICE_PACKAGE_OVERLAYS": "DEVICE_PACKAGE_OVERLAYS",
|
|
|
|
"LOCAL_DUMPSTATE_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
|
|
|
|
"LOCAL_GATEKEEPER_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
|
|
|
|
"LOCAL_HEALTH_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
|
|
|
|
"LOCAL_SENSOR_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
|
|
|
|
"LOCAL_KEYMASTER_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
|
|
|
|
"LOCAL_KEYMINT_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
|
|
|
|
}
|
|
|
|
|
|
|
|
var presetVariables = map[string]bool{
|
|
|
|
"BUILD_ID": true,
|
|
|
|
"HOST_ARCH": true,
|
|
|
|
"HOST_OS": true,
|
|
|
|
"HOST_BUILD_TYPE": true,
|
|
|
|
"OUT_DIR": true,
|
|
|
|
"PLATFORM_VERSION_CODENAME": true,
|
|
|
|
"PLATFORM_VERSION": true,
|
|
|
|
"TARGET_ARCH": true,
|
|
|
|
"TARGET_ARCH_VARIANT": true,
|
|
|
|
"TARGET_BUILD_TYPE": true,
|
|
|
|
"TARGET_BUILD_VARIANT": true,
|
|
|
|
"TARGET_PRODUCT": true,
|
|
|
|
}
|
|
|
|
|
|
|
|
// addVariable returns a variable with a given name. A variable is
|
|
|
|
// added if it does not exist yet.
|
|
|
|
func (ctx *parseContext) addVariable(name string) variable {
|
2022-03-14 22:35:50 +01:00
|
|
|
// Get the hintType before potentially changing the variable name
|
|
|
|
var hintType starlarkType
|
|
|
|
var ok bool
|
|
|
|
if hintType, ok = ctx.typeHints[name]; !ok {
|
|
|
|
hintType = starlarkTypeUnknown
|
|
|
|
}
|
2022-03-01 01:05:01 +01:00
|
|
|
// Heuristics: if variable's name is all lowercase, consider it local
|
|
|
|
// string variable.
|
|
|
|
isLocalVariable := name == strings.ToLower(name)
|
|
|
|
// Local variables can't have special characters in them, because they
|
|
|
|
// will be used as starlark identifiers
|
|
|
|
if isLocalVariable {
|
|
|
|
name = strings.ReplaceAll(strings.TrimSpace(name), "-", "_")
|
|
|
|
}
|
2020-11-06 05:45:07 +01:00
|
|
|
v, found := ctx.variables[name]
|
|
|
|
if !found {
|
|
|
|
if vi, found := KnownVariables[name]; found {
|
2022-03-14 22:35:50 +01:00
|
|
|
_, preset := presetVariables[name]
|
2020-11-06 05:45:07 +01:00
|
|
|
switch vi.class {
|
|
|
|
case VarClassConfig:
|
|
|
|
v = &productConfigVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
|
|
|
|
case VarClassSoong:
|
|
|
|
v = &otherGlobalVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
|
|
|
|
}
|
2022-03-01 01:05:01 +01:00
|
|
|
} else if isLocalVariable {
|
2022-03-14 22:35:50 +01:00
|
|
|
v = &localVariable{baseVariable{nam: name, typ: hintType}}
|
2020-11-06 05:45:07 +01:00
|
|
|
} else {
|
2022-03-14 22:35:50 +01:00
|
|
|
vt := hintType
|
2022-03-18 22:05:06 +01:00
|
|
|
// Heuristics: local variables that contribute to corresponding config variables
|
|
|
|
if cfgVarName, found := localProductConfigVariables[name]; found && vt == starlarkTypeUnknown {
|
|
|
|
vi, found2 := KnownVariables[cfgVarName]
|
|
|
|
if !found2 {
|
|
|
|
panic(fmt.Errorf("unknown config variable %s for %s", cfgVarName, name))
|
2020-11-06 05:45:07 +01:00
|
|
|
}
|
2022-03-18 22:05:06 +01:00
|
|
|
vt = vi.valueType
|
2020-11-06 05:45:07 +01:00
|
|
|
}
|
2021-08-26 18:10:23 +02:00
|
|
|
if strings.HasSuffix(name, "_LIST") && vt == starlarkTypeUnknown {
|
|
|
|
// Heuristics: Variables with "_LIST" suffix are lists
|
|
|
|
vt = starlarkTypeList
|
|
|
|
}
|
2020-11-06 05:45:07 +01:00
|
|
|
v = &otherGlobalVariable{baseVariable{nam: name, typ: vt}}
|
|
|
|
}
|
|
|
|
ctx.variables[name] = v
|
|
|
|
}
|
|
|
|
return v
|
|
|
|
}
|