Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 1 | // 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 | |
| 15 | package mk2rbc |
| 16 | |
| 17 | import ( |
| 18 | "fmt" |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 19 | "strings" |
| 20 | ) |
| 21 | |
| 22 | type variable interface { |
| 23 | name() string |
Cole Faust | f063266 | 2022-04-07 13:59:24 -0700 | [diff] [blame] | 24 | emitGet(gctx *generationContext) |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 25 | emitSet(gctx *generationContext, asgn *assignmentNode) |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 26 | valueType() starlarkType |
Sasha Smundak | 9d011ab | 2021-07-09 16:00:57 -0700 | [diff] [blame] | 27 | setValueType(t starlarkType) |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 28 | defaultValueString() string |
| 29 | isPreset() bool |
| 30 | } |
| 31 | |
| 32 | type baseVariable struct { |
| 33 | nam string |
| 34 | typ starlarkType |
| 35 | preset bool // true if it has been initialized at startup |
| 36 | } |
| 37 | |
| 38 | func (v baseVariable) name() string { |
| 39 | return v.nam |
| 40 | } |
| 41 | |
| 42 | func (v baseVariable) valueType() starlarkType { |
| 43 | return v.typ |
| 44 | } |
| 45 | |
Sasha Smundak | 9d011ab | 2021-07-09 16:00:57 -0700 | [diff] [blame] | 46 | func (v *baseVariable) setValueType(t starlarkType) { |
| 47 | v.typ = t |
| 48 | } |
| 49 | |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 50 | func (v baseVariable) isPreset() bool { |
| 51 | return v.preset |
| 52 | } |
| 53 | |
| 54 | var defaultValuesByType = map[starlarkType]string{ |
| 55 | starlarkTypeUnknown: `""`, |
| 56 | starlarkTypeList: "[]", |
| 57 | starlarkTypeString: `""`, |
| 58 | starlarkTypeInt: "0", |
| 59 | starlarkTypeBool: "False", |
| 60 | starlarkTypeVoid: "None", |
| 61 | } |
| 62 | |
| 63 | func (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 | |
| 70 | type productConfigVariable struct { |
| 71 | baseVariable |
| 72 | } |
| 73 | |
| 74 | func (pcv productConfigVariable) emitSet(gctx *generationContext, asgn *assignmentNode) { |
| 75 | emitAssignment := func() { |
Cole Faust | f063266 | 2022-04-07 13:59:24 -0700 | [diff] [blame] | 76 | gctx.writef("cfg[%q] = ", pcv.nam) |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 77 | asgn.value.emitListVarCopy(gctx) |
| 78 | } |
| 79 | emitAppend := func() { |
Cole Faust | f063266 | 2022-04-07 13:59:24 -0700 | [diff] [blame] | 80 | gctx.writef("cfg[%q] += ", pcv.nam) |
Cole Faust | 0484c23 | 2021-12-22 14:08:08 -0800 | [diff] [blame] | 81 | value := asgn.value |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 82 | if pcv.valueType() == starlarkTypeString { |
| 83 | gctx.writef(`" " + `) |
Cole Faust | 0484c23 | 2021-12-22 14:08:08 -0800 | [diff] [blame] | 84 | value = &toStringExpr{expr: value} |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 85 | } |
Cole Faust | 0484c23 | 2021-12-22 14:08:08 -0800 | [diff] [blame] | 86 | value.emit(gctx) |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 87 | } |
Cole Faust | 816e080 | 2022-03-04 12:04:31 -0800 | [diff] [blame] | 88 | emitSetDefault := func() { |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 89 | 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 Faust | 816e080 | 2022-03-04 12:04:31 -0800 | [diff] [blame] | 95 | } |
| 96 | |
Cole Faust | e2a3798 | 2022-03-09 16:00:17 -0800 | [diff] [blame] | 97 | // If we are not sure variable has been assigned before, emit setdefault |
Cole Faust | f063266 | 2022-04-07 13:59:24 -0700 | [diff] [blame] | 98 | needsSetDefault := !gctx.hasBeenAssigned(&pcv) && !pcv.isPreset() && asgn.isSelfReferential() |
Cole Faust | e2a3798 | 2022-03-09 16:00:17 -0800 | [diff] [blame] | 99 | |
Cole Faust | 816e080 | 2022-03-04 12:04:31 -0800 | [diff] [blame] | 100 | switch asgn.flavor { |
| 101 | case asgnSet: |
Cole Faust | e2a3798 | 2022-03-09 16:00:17 -0800 | [diff] [blame] | 102 | if needsSetDefault { |
Cole Faust | 816e080 | 2022-03-04 12:04:31 -0800 | [diff] [blame] | 103 | emitSetDefault() |
| 104 | } |
| 105 | emitAssignment() |
| 106 | case asgnAppend: |
Cole Faust | e2a3798 | 2022-03-09 16:00:17 -0800 | [diff] [blame] | 107 | if needsSetDefault { |
| 108 | emitSetDefault() |
| 109 | } |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 110 | emitAppend() |
| 111 | case asgnMaybeSet: |
| 112 | gctx.writef("if cfg.get(%q) == None:", pcv.nam) |
| 113 | gctx.indentLevel++ |
| 114 | gctx.newLine() |
Cole Faust | e2a3798 | 2022-03-09 16:00:17 -0800 | [diff] [blame] | 115 | if needsSetDefault { |
| 116 | emitSetDefault() |
| 117 | } |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 118 | emitAssignment() |
| 119 | gctx.indentLevel-- |
| 120 | } |
Cole Faust | f063266 | 2022-04-07 13:59:24 -0700 | [diff] [blame] | 121 | |
| 122 | gctx.setHasBeenAssigned(&pcv) |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 123 | } |
| 124 | |
Cole Faust | f063266 | 2022-04-07 13:59:24 -0700 | [diff] [blame] | 125 | func (pcv productConfigVariable) emitGet(gctx *generationContext) { |
| 126 | if gctx.hasBeenAssigned(&pcv) || pcv.isPreset() { |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 127 | gctx.writef("cfg[%q]", pcv.nam) |
| 128 | } else { |
| 129 | gctx.writef("cfg.get(%q, %s)", pcv.nam, pcv.defaultValueString()) |
| 130 | } |
| 131 | } |
| 132 | |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 133 | type otherGlobalVariable struct { |
| 134 | baseVariable |
| 135 | } |
| 136 | |
| 137 | func (scv otherGlobalVariable) emitSet(gctx *generationContext, asgn *assignmentNode) { |
| 138 | emitAssignment := func() { |
Cole Faust | f063266 | 2022-04-07 13:59:24 -0700 | [diff] [blame] | 139 | gctx.writef("g[%q] = ", scv.nam) |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 140 | asgn.value.emitListVarCopy(gctx) |
| 141 | } |
| 142 | |
| 143 | emitAppend := func() { |
Cole Faust | f063266 | 2022-04-07 13:59:24 -0700 | [diff] [blame] | 144 | gctx.writef("g[%q] += ", scv.nam) |
Cole Faust | 0484c23 | 2021-12-22 14:08:08 -0800 | [diff] [blame] | 145 | value := asgn.value |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 146 | if scv.valueType() == starlarkTypeString { |
| 147 | gctx.writef(`" " + `) |
Cole Faust | 0484c23 | 2021-12-22 14:08:08 -0800 | [diff] [blame] | 148 | value = &toStringExpr{expr: value} |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 149 | } |
Cole Faust | 0484c23 | 2021-12-22 14:08:08 -0800 | [diff] [blame] | 150 | value.emit(gctx) |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 151 | } |
| 152 | |
Cole Faust | e2a3798 | 2022-03-09 16:00:17 -0800 | [diff] [blame] | 153 | // If we are not sure variable has been assigned before, emit setdefault |
Cole Faust | f063266 | 2022-04-07 13:59:24 -0700 | [diff] [blame] | 154 | needsSetDefault := !gctx.hasBeenAssigned(&scv) && !scv.isPreset() && asgn.isSelfReferential() |
Cole Faust | e2a3798 | 2022-03-09 16:00:17 -0800 | [diff] [blame] | 155 | |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 156 | switch asgn.flavor { |
| 157 | case asgnSet: |
Cole Faust | e2a3798 | 2022-03-09 16:00:17 -0800 | [diff] [blame] | 158 | if needsSetDefault { |
| 159 | gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString()) |
| 160 | gctx.newLine() |
| 161 | } |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 162 | emitAssignment() |
| 163 | case asgnAppend: |
Cole Faust | e2a3798 | 2022-03-09 16:00:17 -0800 | [diff] [blame] | 164 | if needsSetDefault { |
| 165 | gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString()) |
| 166 | gctx.newLine() |
| 167 | } |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 168 | emitAppend() |
| 169 | case asgnMaybeSet: |
| 170 | gctx.writef("if g.get(%q) == None:", scv.nam) |
| 171 | gctx.indentLevel++ |
| 172 | gctx.newLine() |
Cole Faust | e2a3798 | 2022-03-09 16:00:17 -0800 | [diff] [blame] | 173 | if needsSetDefault { |
| 174 | gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString()) |
| 175 | gctx.newLine() |
| 176 | } |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 177 | emitAssignment() |
| 178 | gctx.indentLevel-- |
| 179 | } |
Cole Faust | f063266 | 2022-04-07 13:59:24 -0700 | [diff] [blame] | 180 | |
| 181 | gctx.setHasBeenAssigned(&scv) |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 182 | } |
| 183 | |
Cole Faust | f063266 | 2022-04-07 13:59:24 -0700 | [diff] [blame] | 184 | func (scv otherGlobalVariable) emitGet(gctx *generationContext) { |
| 185 | if gctx.hasBeenAssigned(&scv) || scv.isPreset() { |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 186 | gctx.writef("g[%q]", scv.nam) |
| 187 | } else { |
| 188 | gctx.writef("g.get(%q, %s)", scv.nam, scv.defaultValueString()) |
| 189 | } |
| 190 | } |
| 191 | |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 192 | type localVariable struct { |
| 193 | baseVariable |
| 194 | } |
| 195 | |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 196 | func (lv localVariable) String() string { |
| 197 | return "_" + lv.nam |
| 198 | } |
| 199 | |
| 200 | func (lv localVariable) emitSet(gctx *generationContext, asgn *assignmentNode) { |
| 201 | switch asgn.flavor { |
Cole Faust | e2a3798 | 2022-03-09 16:00:17 -0800 | [diff] [blame] | 202 | case asgnSet, asgnMaybeSet: |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 203 | gctx.writef("%s = ", lv) |
| 204 | asgn.value.emitListVarCopy(gctx) |
| 205 | case asgnAppend: |
Cole Faust | f063266 | 2022-04-07 13:59:24 -0700 | [diff] [blame] | 206 | gctx.writef("%s += ", lv) |
Cole Faust | 0484c23 | 2021-12-22 14:08:08 -0800 | [diff] [blame] | 207 | value := asgn.value |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 208 | if lv.valueType() == starlarkTypeString { |
| 209 | gctx.writef(`" " + `) |
Cole Faust | 0484c23 | 2021-12-22 14:08:08 -0800 | [diff] [blame] | 210 | value = &toStringExpr{expr: value} |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 211 | } |
Cole Faust | 0484c23 | 2021-12-22 14:08:08 -0800 | [diff] [blame] | 212 | value.emit(gctx) |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 213 | } |
| 214 | } |
| 215 | |
Cole Faust | f063266 | 2022-04-07 13:59:24 -0700 | [diff] [blame] | 216 | func (lv localVariable) emitGet(gctx *generationContext) { |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 217 | gctx.writef("%s", lv) |
| 218 | } |
| 219 | |
| 220 | type predefinedVariable struct { |
| 221 | baseVariable |
| 222 | value starlarkExpr |
| 223 | } |
| 224 | |
Cole Faust | f063266 | 2022-04-07 13:59:24 -0700 | [diff] [blame] | 225 | func (pv predefinedVariable) emitGet(gctx *generationContext) { |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 226 | pv.value.emit(gctx) |
| 227 | } |
| 228 | |
Sasha Smundak | 6609ba7 | 2021-07-22 18:32:56 -0700 | [diff] [blame] | 229 | func (pv predefinedVariable) emitSet(gctx *generationContext, asgn *assignmentNode) { |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 230 | if expectedValue, ok1 := maybeString(pv.value); ok1 { |
| 231 | actualValue, ok2 := maybeString(asgn.value) |
| 232 | if ok2 { |
| 233 | if actualValue == expectedValue { |
| 234 | return |
| 235 | } |
Sasha Smundak | 422b614 | 2021-11-11 18:31:59 -0800 | [diff] [blame] | 236 | 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 Smundak | 6609ba7 | 2021-07-22 18:32:56 -0700 | [diff] [blame] | 239 | gctx.starScript.hasErrors = true |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 240 | return |
| 241 | } |
| 242 | } |
| 243 | panic(fmt.Errorf("cannot set predefined variable %s to %q", pv.name(), asgn.mkValue.Dump())) |
| 244 | } |
| 245 | |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 246 | var 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 | |
| 258 | var 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. |
| 275 | func (ctx *parseContext) addVariable(name string) variable { |
Cole Faust | f92c9f2 | 2022-03-14 14:35:50 -0700 | [diff] [blame] | 276 | // 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 Faust | 3c4fc99 | 2022-02-28 16:05:01 -0800 | [diff] [blame] | 282 | // 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 Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 290 | v, found := ctx.variables[name] |
| 291 | if !found { |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 292 | if vi, found := KnownVariables[name]; found { |
Cole Faust | f92c9f2 | 2022-03-14 14:35:50 -0700 | [diff] [blame] | 293 | _, preset := presetVariables[name] |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 294 | 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 Faust | 3c4fc99 | 2022-02-28 16:05:01 -0800 | [diff] [blame] | 300 | } else if isLocalVariable { |
Cole Faust | f92c9f2 | 2022-03-14 14:35:50 -0700 | [diff] [blame] | 301 | v = &localVariable{baseVariable{nam: name, typ: hintType}} |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 302 | } else { |
Cole Faust | f92c9f2 | 2022-03-14 14:35:50 -0700 | [diff] [blame] | 303 | vt := hintType |
Cole Faust | f5adedc | 2022-03-18 14:05:06 -0700 | [diff] [blame] | 304 | // 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 Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 309 | } |
Cole Faust | f5adedc | 2022-03-18 14:05:06 -0700 | [diff] [blame] | 310 | vt = vi.valueType |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 311 | } |
Sasha Smundak | 468e11f | 2021-08-26 09:10:23 -0700 | [diff] [blame] | 312 | if strings.HasSuffix(name, "_LIST") && vt == starlarkTypeUnknown { |
| 313 | // Heuristics: Variables with "_LIST" suffix are lists |
| 314 | vt = starlarkTypeList |
| 315 | } |
Sasha Smundak | b051c4e | 2020-11-05 20:45:07 -0800 | [diff] [blame] | 316 | v = &otherGlobalVariable{baseVariable{nam: name, typ: vt}} |
| 317 | } |
| 318 | ctx.variables[name] = v |
| 319 | } |
| 320 | return v |
| 321 | } |