variable.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  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. package mk2rbc
  15. import (
  16. "fmt"
  17. "strings"
  18. )
  19. type variable interface {
  20. name() string
  21. emitGet(gctx *generationContext)
  22. emitSet(gctx *generationContext, asgn *assignmentNode)
  23. valueType() starlarkType
  24. setValueType(t starlarkType)
  25. defaultValueString() string
  26. isPreset() bool
  27. }
  28. type baseVariable struct {
  29. nam string
  30. typ starlarkType
  31. preset bool // true if it has been initialized at startup
  32. }
  33. func (v baseVariable) name() string {
  34. return v.nam
  35. }
  36. func (v baseVariable) valueType() starlarkType {
  37. return v.typ
  38. }
  39. func (v *baseVariable) setValueType(t starlarkType) {
  40. v.typ = t
  41. }
  42. func (v baseVariable) isPreset() bool {
  43. return v.preset
  44. }
  45. var defaultValuesByType = map[starlarkType]string{
  46. starlarkTypeUnknown: `""`,
  47. starlarkTypeList: "[]",
  48. starlarkTypeString: `""`,
  49. starlarkTypeInt: "0",
  50. starlarkTypeBool: "False",
  51. starlarkTypeVoid: "None",
  52. }
  53. func (v baseVariable) defaultValueString() string {
  54. if v, ok := defaultValuesByType[v.valueType()]; ok {
  55. return v
  56. }
  57. panic(fmt.Errorf("%s has unknown type %q", v.name(), v.valueType()))
  58. }
  59. type productConfigVariable struct {
  60. baseVariable
  61. }
  62. func (pcv productConfigVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
  63. emitAssignment := func() {
  64. gctx.writef("cfg[%q] = ", pcv.nam)
  65. asgn.value.emitListVarCopy(gctx)
  66. }
  67. emitAppend := func() {
  68. gctx.writef("cfg[%q] += ", pcv.nam)
  69. value := asgn.value
  70. if pcv.valueType() == starlarkTypeString {
  71. gctx.writef(`" " + `)
  72. value = &toStringExpr{expr: value}
  73. }
  74. value.emit(gctx)
  75. }
  76. emitSetDefault := func() {
  77. if pcv.typ == starlarkTypeList {
  78. gctx.writef("%s(handle, %q)", cfnSetListDefault, pcv.name())
  79. } else {
  80. gctx.writef("cfg.setdefault(%q, %s)", pcv.name(), pcv.defaultValueString())
  81. }
  82. gctx.newLine()
  83. }
  84. // If we are not sure variable has been assigned before, emit setdefault
  85. needsSetDefault := !gctx.hasBeenAssigned(&pcv) && !pcv.isPreset() && asgn.isSelfReferential()
  86. switch asgn.flavor {
  87. case asgnSet:
  88. if needsSetDefault {
  89. emitSetDefault()
  90. }
  91. emitAssignment()
  92. case asgnAppend:
  93. if needsSetDefault {
  94. emitSetDefault()
  95. }
  96. emitAppend()
  97. case asgnMaybeSet:
  98. gctx.writef("if cfg.get(%q) == None:", pcv.nam)
  99. gctx.indentLevel++
  100. gctx.newLine()
  101. if needsSetDefault {
  102. emitSetDefault()
  103. }
  104. emitAssignment()
  105. gctx.indentLevel--
  106. }
  107. gctx.setHasBeenAssigned(&pcv)
  108. }
  109. func (pcv productConfigVariable) emitGet(gctx *generationContext) {
  110. if gctx.hasBeenAssigned(&pcv) || pcv.isPreset() {
  111. gctx.writef("cfg[%q]", pcv.nam)
  112. } else {
  113. gctx.writef("cfg.get(%q, %s)", pcv.nam, pcv.defaultValueString())
  114. }
  115. }
  116. type otherGlobalVariable struct {
  117. baseVariable
  118. }
  119. func (scv otherGlobalVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
  120. emitAssignment := func() {
  121. gctx.writef("g[%q] = ", scv.nam)
  122. asgn.value.emitListVarCopy(gctx)
  123. }
  124. emitAppend := func() {
  125. gctx.writef("g[%q] += ", scv.nam)
  126. value := asgn.value
  127. if scv.valueType() == starlarkTypeString {
  128. gctx.writef(`" " + `)
  129. value = &toStringExpr{expr: value}
  130. }
  131. value.emit(gctx)
  132. }
  133. // If we are not sure variable has been assigned before, emit setdefault
  134. needsSetDefault := !gctx.hasBeenAssigned(&scv) && !scv.isPreset() && asgn.isSelfReferential()
  135. switch asgn.flavor {
  136. case asgnSet:
  137. if needsSetDefault {
  138. gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
  139. gctx.newLine()
  140. }
  141. emitAssignment()
  142. case asgnAppend:
  143. if needsSetDefault {
  144. gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
  145. gctx.newLine()
  146. }
  147. emitAppend()
  148. case asgnMaybeSet:
  149. gctx.writef("if g.get(%q) == None:", scv.nam)
  150. gctx.indentLevel++
  151. gctx.newLine()
  152. if needsSetDefault {
  153. gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
  154. gctx.newLine()
  155. }
  156. emitAssignment()
  157. gctx.indentLevel--
  158. }
  159. gctx.setHasBeenAssigned(&scv)
  160. }
  161. func (scv otherGlobalVariable) emitGet(gctx *generationContext) {
  162. if gctx.hasBeenAssigned(&scv) || scv.isPreset() {
  163. gctx.writef("g[%q]", scv.nam)
  164. } else {
  165. gctx.writef("g.get(%q, %s)", scv.nam, scv.defaultValueString())
  166. }
  167. }
  168. type localVariable struct {
  169. baseVariable
  170. }
  171. func (lv localVariable) String() string {
  172. return "_" + lv.nam
  173. }
  174. func (lv localVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
  175. switch asgn.flavor {
  176. case asgnSet, asgnMaybeSet:
  177. gctx.writef("%s = ", lv)
  178. asgn.value.emitListVarCopy(gctx)
  179. case asgnAppend:
  180. gctx.writef("%s += ", lv)
  181. value := asgn.value
  182. if lv.valueType() == starlarkTypeString {
  183. gctx.writef(`" " + `)
  184. value = &toStringExpr{expr: value}
  185. }
  186. value.emit(gctx)
  187. }
  188. }
  189. func (lv localVariable) emitGet(gctx *generationContext) {
  190. gctx.writef("%s", lv)
  191. }
  192. type predefinedVariable struct {
  193. baseVariable
  194. value starlarkExpr
  195. }
  196. func (pv predefinedVariable) emitGet(gctx *generationContext) {
  197. pv.value.emit(gctx)
  198. }
  199. func (pv predefinedVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
  200. if expectedValue, ok1 := maybeString(pv.value); ok1 {
  201. actualValue, ok2 := maybeString(asgn.value)
  202. if ok2 {
  203. if actualValue == expectedValue {
  204. return
  205. }
  206. gctx.emitConversionError(asgn.location,
  207. fmt.Sprintf("cannot set predefined variable %s to %q, its value should be %q",
  208. pv.name(), actualValue, expectedValue))
  209. gctx.starScript.hasErrors = true
  210. return
  211. }
  212. }
  213. panic(fmt.Errorf("cannot set predefined variable %s to %q", pv.name(), asgn.mkValue.Dump()))
  214. }
  215. var localProductConfigVariables = map[string]string{
  216. "LOCAL_AUDIO_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
  217. "LOCAL_AUDIO_PRODUCT_COPY_FILES": "PRODUCT_COPY_FILES",
  218. "LOCAL_AUDIO_DEVICE_PACKAGE_OVERLAYS": "DEVICE_PACKAGE_OVERLAYS",
  219. "LOCAL_DUMPSTATE_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
  220. "LOCAL_GATEKEEPER_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
  221. "LOCAL_HEALTH_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
  222. "LOCAL_SENSOR_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
  223. "LOCAL_KEYMASTER_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
  224. "LOCAL_KEYMINT_PRODUCT_PACKAGE": "PRODUCT_PACKAGES",
  225. }
  226. var presetVariables = map[string]bool{
  227. "BUILD_ID": true,
  228. "HOST_ARCH": true,
  229. "HOST_OS": true,
  230. "HOST_BUILD_TYPE": true,
  231. "OUT_DIR": true,
  232. "PLATFORM_VERSION_CODENAME": true,
  233. "PLATFORM_VERSION": true,
  234. "TARGET_ARCH": true,
  235. "TARGET_ARCH_VARIANT": true,
  236. "TARGET_BUILD_TYPE": true,
  237. "TARGET_BUILD_VARIANT": true,
  238. "TARGET_PRODUCT": true,
  239. }
  240. // addVariable returns a variable with a given name. A variable is
  241. // added if it does not exist yet.
  242. func (ctx *parseContext) addVariable(name string) variable {
  243. // Get the hintType before potentially changing the variable name
  244. var hintType starlarkType
  245. var ok bool
  246. if hintType, ok = ctx.typeHints[name]; !ok {
  247. hintType = starlarkTypeUnknown
  248. }
  249. // Heuristics: if variable's name is all lowercase, consider it local
  250. // string variable.
  251. isLocalVariable := name == strings.ToLower(name)
  252. // Local variables can't have special characters in them, because they
  253. // will be used as starlark identifiers
  254. if isLocalVariable {
  255. name = strings.ReplaceAll(strings.TrimSpace(name), "-", "_")
  256. }
  257. v, found := ctx.variables[name]
  258. if !found {
  259. if vi, found := KnownVariables[name]; found {
  260. _, preset := presetVariables[name]
  261. switch vi.class {
  262. case VarClassConfig:
  263. v = &productConfigVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
  264. case VarClassSoong:
  265. v = &otherGlobalVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
  266. }
  267. } else if isLocalVariable {
  268. v = &localVariable{baseVariable{nam: name, typ: hintType}}
  269. } else {
  270. vt := hintType
  271. // Heuristics: local variables that contribute to corresponding config variables
  272. if cfgVarName, found := localProductConfigVariables[name]; found && vt == starlarkTypeUnknown {
  273. vi, found2 := KnownVariables[cfgVarName]
  274. if !found2 {
  275. panic(fmt.Errorf("unknown config variable %s for %s", cfgVarName, name))
  276. }
  277. vt = vi.valueType
  278. }
  279. if strings.HasSuffix(name, "_LIST") && vt == starlarkTypeUnknown {
  280. // Heuristics: Variables with "_LIST" suffix are lists
  281. vt = starlarkTypeList
  282. }
  283. v = &otherGlobalVariable{baseVariable{nam: name, typ: vt}}
  284. }
  285. ctx.variables[name] = v
  286. }
  287. return v
  288. }