variable.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  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, isDefined bool)
  22. emitSet(gctx *generationContext, asgn *assignmentNode)
  23. emitDefined(gctx *generationContext)
  24. valueType() starlarkType
  25. setValueType(t starlarkType)
  26. defaultValueString() string
  27. isPreset() bool
  28. }
  29. type baseVariable struct {
  30. nam string
  31. typ starlarkType
  32. preset bool // true if it has been initialized at startup
  33. }
  34. func (v baseVariable) name() string {
  35. return v.nam
  36. }
  37. func (v baseVariable) valueType() starlarkType {
  38. return v.typ
  39. }
  40. func (v *baseVariable) setValueType(t starlarkType) {
  41. v.typ = t
  42. }
  43. func (v baseVariable) isPreset() bool {
  44. return v.preset
  45. }
  46. var defaultValuesByType = map[starlarkType]string{
  47. starlarkTypeUnknown: `""`,
  48. starlarkTypeList: "[]",
  49. starlarkTypeString: `""`,
  50. starlarkTypeInt: "0",
  51. starlarkTypeBool: "False",
  52. starlarkTypeVoid: "None",
  53. }
  54. func (v baseVariable) defaultValueString() string {
  55. if v, ok := defaultValuesByType[v.valueType()]; ok {
  56. return v
  57. }
  58. panic(fmt.Errorf("%s has unknown type %q", v.name(), v.valueType()))
  59. }
  60. type productConfigVariable struct {
  61. baseVariable
  62. }
  63. func (pcv productConfigVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
  64. emitAssignment := func() {
  65. pcv.emitGet(gctx, true)
  66. gctx.write(" = ")
  67. asgn.value.emitListVarCopy(gctx)
  68. }
  69. emitAppend := func() {
  70. pcv.emitGet(gctx, true)
  71. gctx.write(" += ")
  72. if pcv.valueType() == starlarkTypeString {
  73. gctx.writef(`" " + `)
  74. }
  75. asgn.value.emit(gctx)
  76. }
  77. switch asgn.flavor {
  78. case asgnSet:
  79. emitAssignment()
  80. case asgnAppend:
  81. emitAppend()
  82. case asgnMaybeAppend:
  83. // If we are not sure variable has been assigned before, emit setdefault
  84. if pcv.typ == starlarkTypeList {
  85. gctx.writef("%s(handle, %q)", cfnSetListDefault, pcv.name())
  86. } else {
  87. gctx.writef("cfg.setdefault(%q, %s)", pcv.name(), pcv.defaultValueString())
  88. }
  89. gctx.newLine()
  90. emitAppend()
  91. case asgnMaybeSet:
  92. gctx.writef("if cfg.get(%q) == None:", pcv.nam)
  93. gctx.indentLevel++
  94. gctx.newLine()
  95. emitAssignment()
  96. gctx.indentLevel--
  97. }
  98. }
  99. func (pcv productConfigVariable) emitGet(gctx *generationContext, isDefined bool) {
  100. if isDefined || pcv.isPreset() {
  101. gctx.writef("cfg[%q]", pcv.nam)
  102. } else {
  103. gctx.writef("cfg.get(%q, %s)", pcv.nam, pcv.defaultValueString())
  104. }
  105. }
  106. func (pcv productConfigVariable) emitDefined(gctx *generationContext) {
  107. gctx.writef("g.get(%q) != None", pcv.name())
  108. }
  109. type otherGlobalVariable struct {
  110. baseVariable
  111. }
  112. func (scv otherGlobalVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
  113. emitAssignment := func() {
  114. scv.emitGet(gctx, true)
  115. gctx.write(" = ")
  116. asgn.value.emitListVarCopy(gctx)
  117. }
  118. emitAppend := func() {
  119. scv.emitGet(gctx, true)
  120. gctx.write(" += ")
  121. if scv.valueType() == starlarkTypeString {
  122. gctx.writef(`" " + `)
  123. }
  124. asgn.value.emit(gctx)
  125. }
  126. switch asgn.flavor {
  127. case asgnSet:
  128. emitAssignment()
  129. case asgnAppend:
  130. emitAppend()
  131. case asgnMaybeAppend:
  132. // If we are not sure variable has been assigned before, emit setdefault
  133. gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
  134. gctx.newLine()
  135. emitAppend()
  136. case asgnMaybeSet:
  137. gctx.writef("if g.get(%q) == None:", scv.nam)
  138. gctx.indentLevel++
  139. gctx.newLine()
  140. emitAssignment()
  141. gctx.indentLevel--
  142. }
  143. }
  144. func (scv otherGlobalVariable) emitGet(gctx *generationContext, isDefined bool) {
  145. if isDefined || scv.isPreset() {
  146. gctx.writef("g[%q]", scv.nam)
  147. } else {
  148. gctx.writef("g.get(%q, %s)", scv.nam, scv.defaultValueString())
  149. }
  150. }
  151. func (scv otherGlobalVariable) emitDefined(gctx *generationContext) {
  152. gctx.writef("g.get(%q) != None", scv.name())
  153. }
  154. type localVariable struct {
  155. baseVariable
  156. }
  157. func (lv localVariable) emitDefined(_ *generationContext) {
  158. panic("implement me")
  159. }
  160. func (lv localVariable) String() string {
  161. return "_" + lv.nam
  162. }
  163. func (lv localVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
  164. switch asgn.flavor {
  165. case asgnSet:
  166. gctx.writef("%s = ", lv)
  167. asgn.value.emitListVarCopy(gctx)
  168. case asgnAppend:
  169. lv.emitGet(gctx, false)
  170. gctx.write(" += ")
  171. if lv.valueType() == starlarkTypeString {
  172. gctx.writef(`" " + `)
  173. }
  174. asgn.value.emit(gctx)
  175. case asgnMaybeAppend:
  176. gctx.writef("%s(%q, ", cfnLocalAppend, lv)
  177. asgn.value.emit(gctx)
  178. gctx.write(")")
  179. case asgnMaybeSet:
  180. gctx.writef("%s(%q, ", cfnLocalSetDefault, lv)
  181. asgn.value.emit(gctx)
  182. gctx.write(")")
  183. }
  184. }
  185. func (lv localVariable) emitGet(gctx *generationContext, _ bool) {
  186. gctx.writef("%s", lv)
  187. }
  188. type predefinedVariable struct {
  189. baseVariable
  190. value starlarkExpr
  191. }
  192. func (pv predefinedVariable) emitGet(gctx *generationContext, _ bool) {
  193. pv.value.emit(gctx)
  194. }
  195. func (pv predefinedVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
  196. if expectedValue, ok1 := maybeString(pv.value); ok1 {
  197. actualValue, ok2 := maybeString(asgn.value)
  198. if ok2 {
  199. if actualValue == expectedValue {
  200. return
  201. }
  202. gctx.writef("# MK2RBC TRANSLATION ERROR: cannot set predefined variable %s to %q, its value should be %q",
  203. pv.name(), actualValue, expectedValue)
  204. gctx.newLine()
  205. gctx.write("pass")
  206. gctx.starScript.hasErrors = true
  207. return
  208. }
  209. }
  210. panic(fmt.Errorf("cannot set predefined variable %s to %q", pv.name(), asgn.mkValue.Dump()))
  211. }
  212. func (pv predefinedVariable) emitDefined(gctx *generationContext) {
  213. gctx.write("True")
  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. v, found := ctx.variables[name]
  244. if !found {
  245. _, preset := presetVariables[name]
  246. if vi, found := KnownVariables[name]; found {
  247. switch vi.class {
  248. case VarClassConfig:
  249. v = &productConfigVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
  250. case VarClassSoong:
  251. v = &otherGlobalVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
  252. }
  253. } else if name == strings.ToLower(name) {
  254. // Heuristics: if variable's name is all lowercase, consider it local
  255. // string variable.
  256. v = &localVariable{baseVariable{nam: name, typ: starlarkTypeUnknown}}
  257. } else {
  258. vt := starlarkTypeUnknown
  259. if strings.HasPrefix(name, "LOCAL_") {
  260. // Heuristics: local variables that contribute to corresponding config variables
  261. if cfgVarName, found := localProductConfigVariables[name]; found {
  262. vi, found2 := KnownVariables[cfgVarName]
  263. if !found2 {
  264. panic(fmt.Errorf("unknown config variable %s for %s", cfgVarName, name))
  265. }
  266. vt = vi.valueType
  267. }
  268. }
  269. v = &otherGlobalVariable{baseVariable{nam: name, typ: vt}}
  270. }
  271. ctx.variables[name] = v
  272. }
  273. return v
  274. }