mk2rbc.go 73 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228
  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. // Convert makefile containing device configuration to Starlark file
  15. // The conversion can handle the following constructs in a makefile:
  16. // - comments
  17. // - simple variable assignments
  18. // - $(call init-product,<file>)
  19. // - $(call inherit-product-if-exists
  20. // - if directives
  21. //
  22. // All other constructs are carried over to the output starlark file as comments.
  23. package mk2rbc
  24. import (
  25. "bytes"
  26. "fmt"
  27. "io"
  28. "io/fs"
  29. "io/ioutil"
  30. "os"
  31. "path/filepath"
  32. "regexp"
  33. "sort"
  34. "strconv"
  35. "strings"
  36. "text/scanner"
  37. mkparser "android/soong/androidmk/parser"
  38. )
  39. const (
  40. annotationCommentPrefix = "RBC#"
  41. baseUri = "//build/make/core:product_config.rbc"
  42. // The name of the struct exported by the product_config.rbc
  43. // that contains the functions and variables available to
  44. // product configuration Starlark files.
  45. baseName = "rblf"
  46. soongNsPrefix = "SOONG_CONFIG_"
  47. // And here are the functions and variables:
  48. cfnGetCfg = baseName + ".cfg"
  49. cfnMain = baseName + ".product_configuration"
  50. cfnBoardMain = baseName + ".board_configuration"
  51. cfnPrintVars = baseName + ".printvars"
  52. cfnInherit = baseName + ".inherit"
  53. cfnSetListDefault = baseName + ".setdefault"
  54. )
  55. const (
  56. soongConfigAppend = "soong_config_append"
  57. soongConfigAssign = "soong_config_set"
  58. )
  59. var knownFunctions = map[string]interface {
  60. parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr
  61. }{
  62. "abspath": &simpleCallParser{name: baseName + ".abspath", returnType: starlarkTypeString},
  63. "add-product-dex-preopt-module-config": &simpleCallParser{name: baseName + ".add_product_dex_preopt_module_config", returnType: starlarkTypeString, addHandle: true},
  64. "add_soong_config_namespace": &simpleCallParser{name: baseName + ".soong_config_namespace", returnType: starlarkTypeVoid, addGlobals: true},
  65. "add_soong_config_var_value": &simpleCallParser{name: baseName + ".soong_config_set", returnType: starlarkTypeVoid, addGlobals: true},
  66. soongConfigAssign: &simpleCallParser{name: baseName + ".soong_config_set", returnType: starlarkTypeVoid, addGlobals: true},
  67. soongConfigAppend: &simpleCallParser{name: baseName + ".soong_config_append", returnType: starlarkTypeVoid, addGlobals: true},
  68. "soong_config_get": &simpleCallParser{name: baseName + ".soong_config_get", returnType: starlarkTypeString, addGlobals: true},
  69. "add-to-product-copy-files-if-exists": &simpleCallParser{name: baseName + ".copy_if_exists", returnType: starlarkTypeList},
  70. "addprefix": &simpleCallParser{name: baseName + ".addprefix", returnType: starlarkTypeList},
  71. "addsuffix": &simpleCallParser{name: baseName + ".addsuffix", returnType: starlarkTypeList},
  72. "and": &andOrParser{isAnd: true},
  73. "clear-var-list": &simpleCallParser{name: baseName + ".clear_var_list", returnType: starlarkTypeVoid, addGlobals: true, addHandle: true},
  74. "copy-files": &simpleCallParser{name: baseName + ".copy_files", returnType: starlarkTypeList},
  75. "dir": &simpleCallParser{name: baseName + ".dir", returnType: starlarkTypeString},
  76. "dist-for-goals": &simpleCallParser{name: baseName + ".mkdist_for_goals", returnType: starlarkTypeVoid, addGlobals: true},
  77. "enforce-product-packages-exist": &simpleCallParser{name: baseName + ".enforce_product_packages_exist", returnType: starlarkTypeVoid, addHandle: true},
  78. "error": &makeControlFuncParser{name: baseName + ".mkerror"},
  79. "findstring": &simpleCallParser{name: baseName + ".findstring", returnType: starlarkTypeInt},
  80. "find-copy-subdir-files": &simpleCallParser{name: baseName + ".find_and_copy", returnType: starlarkTypeList},
  81. "filter": &simpleCallParser{name: baseName + ".filter", returnType: starlarkTypeList},
  82. "filter-out": &simpleCallParser{name: baseName + ".filter_out", returnType: starlarkTypeList},
  83. "firstword": &simpleCallParser{name: baseName + ".first_word", returnType: starlarkTypeString},
  84. "foreach": &foreachCallParser{},
  85. "if": &ifCallParser{},
  86. "info": &makeControlFuncParser{name: baseName + ".mkinfo"},
  87. "is-board-platform": &simpleCallParser{name: baseName + ".board_platform_is", returnType: starlarkTypeBool, addGlobals: true},
  88. "is-board-platform2": &simpleCallParser{name: baseName + ".board_platform_is", returnType: starlarkTypeBool, addGlobals: true},
  89. "is-board-platform-in-list": &simpleCallParser{name: baseName + ".board_platform_in", returnType: starlarkTypeBool, addGlobals: true},
  90. "is-board-platform-in-list2": &simpleCallParser{name: baseName + ".board_platform_in", returnType: starlarkTypeBool, addGlobals: true},
  91. "is-product-in-list": &isProductInListCallParser{},
  92. "is-vendor-board-platform": &isVendorBoardPlatformCallParser{},
  93. "is-vendor-board-qcom": &isVendorBoardQcomCallParser{},
  94. "lastword": &simpleCallParser{name: baseName + ".last_word", returnType: starlarkTypeString},
  95. "notdir": &simpleCallParser{name: baseName + ".notdir", returnType: starlarkTypeString},
  96. "math_max": &mathMaxOrMinCallParser{function: "max"},
  97. "math_min": &mathMaxOrMinCallParser{function: "min"},
  98. "math_gt_or_eq": &mathComparisonCallParser{op: ">="},
  99. "math_gt": &mathComparisonCallParser{op: ">"},
  100. "math_lt": &mathComparisonCallParser{op: "<"},
  101. "my-dir": &myDirCallParser{},
  102. "or": &andOrParser{isAnd: false},
  103. "patsubst": &substCallParser{fname: "patsubst"},
  104. "product-copy-files-by-pattern": &simpleCallParser{name: baseName + ".product_copy_files_by_pattern", returnType: starlarkTypeList},
  105. "require-artifacts-in-path": &simpleCallParser{name: baseName + ".require_artifacts_in_path", returnType: starlarkTypeVoid, addHandle: true},
  106. "require-artifacts-in-path-relaxed": &simpleCallParser{name: baseName + ".require_artifacts_in_path_relaxed", returnType: starlarkTypeVoid, addHandle: true},
  107. // TODO(asmundak): remove it once all calls are removed from configuration makefiles. see b/183161002
  108. "shell": &shellCallParser{},
  109. "sort": &simpleCallParser{name: baseName + ".mksort", returnType: starlarkTypeList},
  110. "strip": &simpleCallParser{name: baseName + ".mkstrip", returnType: starlarkTypeString},
  111. "subst": &substCallParser{fname: "subst"},
  112. "to-lower": &lowerUpperParser{isUpper: false},
  113. "to-upper": &lowerUpperParser{isUpper: true},
  114. "warning": &makeControlFuncParser{name: baseName + ".mkwarning"},
  115. "word": &wordCallParser{},
  116. "words": &wordsCallParser{},
  117. "wildcard": &simpleCallParser{name: baseName + ".expand_wildcard", returnType: starlarkTypeList},
  118. }
  119. // The same as knownFunctions, but returns a []starlarkNode instead of a starlarkExpr
  120. var knownNodeFunctions = map[string]interface {
  121. parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) []starlarkNode
  122. }{
  123. "eval": &evalNodeParser{},
  124. "if": &ifCallNodeParser{},
  125. "inherit-product": &inheritProductCallParser{loadAlways: true},
  126. "inherit-product-if-exists": &inheritProductCallParser{loadAlways: false},
  127. "foreach": &foreachCallNodeParser{},
  128. }
  129. // These look like variables, but are actually functions, and would give
  130. // undefined variable errors if we converted them as variables. Instead,
  131. // emit an error instead of converting them.
  132. var unsupportedFunctions = map[string]bool{
  133. "local-generated-sources-dir": true,
  134. "local-intermediates-dir": true,
  135. }
  136. // These are functions that we don't implement conversions for, but
  137. // we allow seeing their definitions in the product config files.
  138. var ignoredDefines = map[string]bool{
  139. "find-word-in-list": true, // internal macro
  140. "get-vendor-board-platforms": true, // internal macro, used by is-board-platform, etc.
  141. "is-android-codename": true, // unused by product config
  142. "is-android-codename-in-list": true, // unused by product config
  143. "is-chipset-in-board-platform": true, // unused by product config
  144. "is-chipset-prefix-in-board-platform": true, // unused by product config
  145. "is-not-board-platform": true, // defined but never used
  146. "is-platform-sdk-version-at-least": true, // unused by product config
  147. "match-prefix": true, // internal macro
  148. "match-word": true, // internal macro
  149. "match-word-in-list": true, // internal macro
  150. "tb-modules": true, // defined in hardware/amlogic/tb_modules/tb_detect.mk, unused
  151. }
  152. var identifierFullMatchRegex = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$")
  153. // Conversion request parameters
  154. type Request struct {
  155. MkFile string // file to convert
  156. Reader io.Reader // if set, read input from this stream instead
  157. OutputSuffix string // generated Starlark files suffix
  158. OutputDir string // if set, root of the output hierarchy
  159. ErrorLogger ErrorLogger
  160. TracedVariables []string // trace assignment to these variables
  161. TraceCalls bool
  162. SourceFS fs.FS
  163. MakefileFinder MakefileFinder
  164. }
  165. // ErrorLogger prints errors and gathers error statistics.
  166. // Its NewError function is called on every error encountered during the conversion.
  167. type ErrorLogger interface {
  168. NewError(el ErrorLocation, node mkparser.Node, text string, args ...interface{})
  169. }
  170. type ErrorLocation struct {
  171. MkFile string
  172. MkLine int
  173. }
  174. func (el ErrorLocation) String() string {
  175. return fmt.Sprintf("%s:%d", el.MkFile, el.MkLine)
  176. }
  177. // Derives module name for a given file. It is base name
  178. // (file name without suffix), with some characters replaced to make it a Starlark identifier
  179. func moduleNameForFile(mkFile string) string {
  180. base := strings.TrimSuffix(filepath.Base(mkFile), filepath.Ext(mkFile))
  181. // TODO(asmundak): what else can be in the product file names?
  182. return strings.NewReplacer("-", "_", ".", "_").Replace(base)
  183. }
  184. func cloneMakeString(mkString *mkparser.MakeString) *mkparser.MakeString {
  185. r := &mkparser.MakeString{StringPos: mkString.StringPos}
  186. r.Strings = append(r.Strings, mkString.Strings...)
  187. r.Variables = append(r.Variables, mkString.Variables...)
  188. return r
  189. }
  190. func isMakeControlFunc(s string) bool {
  191. return s == "error" || s == "warning" || s == "info"
  192. }
  193. // varAssignmentScope points to the last assignment for each variable
  194. // in the current block. It is used during the parsing to chain
  195. // the assignments to a variable together.
  196. type varAssignmentScope struct {
  197. outer *varAssignmentScope
  198. vars map[string]bool
  199. }
  200. // Starlark output generation context
  201. type generationContext struct {
  202. buf strings.Builder
  203. starScript *StarlarkScript
  204. indentLevel int
  205. inAssignment bool
  206. tracedCount int
  207. varAssignments *varAssignmentScope
  208. }
  209. func NewGenerateContext(ss *StarlarkScript) *generationContext {
  210. return &generationContext{
  211. starScript: ss,
  212. varAssignments: &varAssignmentScope{
  213. outer: nil,
  214. vars: make(map[string]bool),
  215. },
  216. }
  217. }
  218. func (gctx *generationContext) pushVariableAssignments() {
  219. va := &varAssignmentScope{
  220. outer: gctx.varAssignments,
  221. vars: make(map[string]bool),
  222. }
  223. gctx.varAssignments = va
  224. }
  225. func (gctx *generationContext) popVariableAssignments() {
  226. gctx.varAssignments = gctx.varAssignments.outer
  227. }
  228. func (gctx *generationContext) hasBeenAssigned(v variable) bool {
  229. for va := gctx.varAssignments; va != nil; va = va.outer {
  230. if _, ok := va.vars[v.name()]; ok {
  231. return true
  232. }
  233. }
  234. return false
  235. }
  236. func (gctx *generationContext) setHasBeenAssigned(v variable) {
  237. gctx.varAssignments.vars[v.name()] = true
  238. }
  239. // emit returns generated script
  240. func (gctx *generationContext) emit() string {
  241. ss := gctx.starScript
  242. // The emitted code has the following layout:
  243. // <initial comments>
  244. // preamble, i.e.,
  245. // load statement for the runtime support
  246. // load statement for each unique submodule pulled in by this one
  247. // def init(g, handle):
  248. // cfg = rblf.cfg(handle)
  249. // <statements>
  250. // <warning if conversion was not clean>
  251. iNode := len(ss.nodes)
  252. for i, node := range ss.nodes {
  253. if _, ok := node.(*commentNode); !ok {
  254. iNode = i
  255. break
  256. }
  257. node.emit(gctx)
  258. }
  259. gctx.emitPreamble()
  260. gctx.newLine()
  261. // The arguments passed to the init function are the global dictionary
  262. // ('g') and the product configuration dictionary ('cfg')
  263. gctx.write("def init(g, handle):")
  264. gctx.indentLevel++
  265. if gctx.starScript.traceCalls {
  266. gctx.newLine()
  267. gctx.writef(`print(">%s")`, gctx.starScript.mkFile)
  268. }
  269. gctx.newLine()
  270. gctx.writef("cfg = %s(handle)", cfnGetCfg)
  271. for _, node := range ss.nodes[iNode:] {
  272. node.emit(gctx)
  273. }
  274. if gctx.starScript.traceCalls {
  275. gctx.newLine()
  276. gctx.writef(`print("<%s")`, gctx.starScript.mkFile)
  277. }
  278. gctx.indentLevel--
  279. gctx.write("\n")
  280. return gctx.buf.String()
  281. }
  282. func (gctx *generationContext) emitPreamble() {
  283. gctx.newLine()
  284. gctx.writef("load(%q, %q)", baseUri, baseName)
  285. // Emit exactly one load statement for each URI.
  286. loadedSubConfigs := make(map[string]string)
  287. for _, mi := range gctx.starScript.inherited {
  288. uri := mi.path
  289. if m, ok := loadedSubConfigs[uri]; ok {
  290. // No need to emit load statement, but fix module name.
  291. mi.moduleLocalName = m
  292. continue
  293. }
  294. if mi.optional || mi.missing {
  295. uri += "|init"
  296. }
  297. gctx.newLine()
  298. gctx.writef("load(%q, %s = \"init\")", uri, mi.entryName())
  299. loadedSubConfigs[uri] = mi.moduleLocalName
  300. }
  301. gctx.write("\n")
  302. }
  303. func (gctx *generationContext) emitPass() {
  304. gctx.newLine()
  305. gctx.write("pass")
  306. }
  307. func (gctx *generationContext) write(ss ...string) {
  308. for _, s := range ss {
  309. gctx.buf.WriteString(s)
  310. }
  311. }
  312. func (gctx *generationContext) writef(format string, args ...interface{}) {
  313. gctx.write(fmt.Sprintf(format, args...))
  314. }
  315. func (gctx *generationContext) newLine() {
  316. if gctx.buf.Len() == 0 {
  317. return
  318. }
  319. gctx.write("\n")
  320. gctx.writef("%*s", 2*gctx.indentLevel, "")
  321. }
  322. func (gctx *generationContext) emitConversionError(el ErrorLocation, message string) {
  323. gctx.writef(`rblf.mk2rbc_error("%s", %q)`, el, message)
  324. }
  325. func (gctx *generationContext) emitLoadCheck(im inheritedModule) {
  326. if !im.needsLoadCheck() {
  327. return
  328. }
  329. gctx.newLine()
  330. gctx.writef("if not %s:", im.entryName())
  331. gctx.indentLevel++
  332. gctx.newLine()
  333. gctx.write(`rblf.mkerror("`, gctx.starScript.mkFile, `", "Cannot find %s" % (`)
  334. im.pathExpr().emit(gctx)
  335. gctx.write("))")
  336. gctx.indentLevel--
  337. }
  338. type knownVariable struct {
  339. name string
  340. class varClass
  341. valueType starlarkType
  342. }
  343. type knownVariables map[string]knownVariable
  344. func (pcv knownVariables) NewVariable(name string, varClass varClass, valueType starlarkType) {
  345. v, exists := pcv[name]
  346. if !exists {
  347. pcv[name] = knownVariable{name, varClass, valueType}
  348. return
  349. }
  350. // Conflict resolution:
  351. // * config class trumps everything
  352. // * any type trumps unknown type
  353. match := varClass == v.class
  354. if !match {
  355. if varClass == VarClassConfig {
  356. v.class = VarClassConfig
  357. match = true
  358. } else if v.class == VarClassConfig {
  359. match = true
  360. }
  361. }
  362. if valueType != v.valueType {
  363. if valueType != starlarkTypeUnknown {
  364. if v.valueType == starlarkTypeUnknown {
  365. v.valueType = valueType
  366. } else {
  367. match = false
  368. }
  369. }
  370. }
  371. if !match {
  372. fmt.Fprintf(os.Stderr, "cannot redefine %s as %v/%v (already defined as %v/%v)\n",
  373. name, varClass, valueType, v.class, v.valueType)
  374. }
  375. }
  376. // All known product variables.
  377. var KnownVariables = make(knownVariables)
  378. func init() {
  379. for _, kv := range []string{
  380. // Kernel-related variables that we know are lists.
  381. "BOARD_VENDOR_KERNEL_MODULES",
  382. "BOARD_VENDOR_RAMDISK_KERNEL_MODULES",
  383. "BOARD_VENDOR_RAMDISK_KERNEL_MODULES_LOAD",
  384. "BOARD_RECOVERY_KERNEL_MODULES",
  385. // Other variables we knwo are lists
  386. "ART_APEX_JARS",
  387. } {
  388. KnownVariables.NewVariable(kv, VarClassSoong, starlarkTypeList)
  389. }
  390. }
  391. // Information about the generated Starlark script.
  392. type StarlarkScript struct {
  393. mkFile string
  394. moduleName string
  395. mkPos scanner.Position
  396. nodes []starlarkNode
  397. inherited []*moduleInfo
  398. hasErrors bool
  399. traceCalls bool // print enter/exit each init function
  400. sourceFS fs.FS
  401. makefileFinder MakefileFinder
  402. nodeLocator func(pos mkparser.Pos) int
  403. }
  404. // parseContext holds the script we are generating and all the ephemeral data
  405. // needed during the parsing.
  406. type parseContext struct {
  407. script *StarlarkScript
  408. nodes []mkparser.Node // Makefile as parsed by mkparser
  409. currentNodeIndex int // Node in it we are processing
  410. ifNestLevel int
  411. moduleNameCount map[string]int // count of imported modules with given basename
  412. fatalError error
  413. outputSuffix string
  414. errorLogger ErrorLogger
  415. tracedVariables map[string]bool // variables to be traced in the generated script
  416. variables map[string]variable
  417. outputDir string
  418. dependentModules map[string]*moduleInfo
  419. soongNamespaces map[string]map[string]bool
  420. includeTops []string
  421. typeHints map[string]starlarkType
  422. atTopOfMakefile bool
  423. }
  424. func newParseContext(ss *StarlarkScript, nodes []mkparser.Node) *parseContext {
  425. predefined := []struct{ name, value string }{
  426. {"SRC_TARGET_DIR", filepath.Join("build", "make", "target")},
  427. {"LOCAL_PATH", filepath.Dir(ss.mkFile)},
  428. {"MAKEFILE_LIST", ss.mkFile},
  429. {"TOPDIR", ""}, // TOPDIR is just set to an empty string in cleanbuild.mk and core.mk
  430. // TODO(asmundak): maybe read it from build/make/core/envsetup.mk?
  431. {"TARGET_COPY_OUT_SYSTEM", "system"},
  432. {"TARGET_COPY_OUT_SYSTEM_OTHER", "system_other"},
  433. {"TARGET_COPY_OUT_DATA", "data"},
  434. {"TARGET_COPY_OUT_ASAN", filepath.Join("data", "asan")},
  435. {"TARGET_COPY_OUT_OEM", "oem"},
  436. {"TARGET_COPY_OUT_RAMDISK", "ramdisk"},
  437. {"TARGET_COPY_OUT_DEBUG_RAMDISK", "debug_ramdisk"},
  438. {"TARGET_COPY_OUT_VENDOR_DEBUG_RAMDISK", "vendor_debug_ramdisk"},
  439. {"TARGET_COPY_OUT_TEST_HARNESS_RAMDISK", "test_harness_ramdisk"},
  440. {"TARGET_COPY_OUT_ROOT", "root"},
  441. {"TARGET_COPY_OUT_RECOVERY", "recovery"},
  442. {"TARGET_COPY_OUT_VENDOR_RAMDISK", "vendor_ramdisk"},
  443. // TODO(asmundak): to process internal config files, we need the following variables:
  444. // TARGET_VENDOR
  445. // target_base_product
  446. //
  447. // the following utility variables are set in build/make/common/core.mk:
  448. {"empty", ""},
  449. {"space", " "},
  450. {"comma", ","},
  451. {"newline", "\n"},
  452. {"pound", "#"},
  453. {"backslash", "\\"},
  454. }
  455. ctx := &parseContext{
  456. script: ss,
  457. nodes: nodes,
  458. currentNodeIndex: 0,
  459. ifNestLevel: 0,
  460. moduleNameCount: make(map[string]int),
  461. variables: make(map[string]variable),
  462. dependentModules: make(map[string]*moduleInfo),
  463. soongNamespaces: make(map[string]map[string]bool),
  464. includeTops: []string{},
  465. typeHints: make(map[string]starlarkType),
  466. atTopOfMakefile: true,
  467. }
  468. for _, item := range predefined {
  469. ctx.variables[item.name] = &predefinedVariable{
  470. baseVariable: baseVariable{nam: item.name, typ: starlarkTypeString},
  471. value: &stringLiteralExpr{item.value},
  472. }
  473. }
  474. return ctx
  475. }
  476. func (ctx *parseContext) hasNodes() bool {
  477. return ctx.currentNodeIndex < len(ctx.nodes)
  478. }
  479. func (ctx *parseContext) getNode() mkparser.Node {
  480. if !ctx.hasNodes() {
  481. return nil
  482. }
  483. node := ctx.nodes[ctx.currentNodeIndex]
  484. ctx.currentNodeIndex++
  485. return node
  486. }
  487. func (ctx *parseContext) backNode() {
  488. if ctx.currentNodeIndex <= 0 {
  489. panic("Cannot back off")
  490. }
  491. ctx.currentNodeIndex--
  492. }
  493. func (ctx *parseContext) handleAssignment(a *mkparser.Assignment) []starlarkNode {
  494. // Handle only simple variables
  495. if !a.Name.Const() || a.Target != nil {
  496. return []starlarkNode{ctx.newBadNode(a, "Only simple variables are handled")}
  497. }
  498. name := a.Name.Strings[0]
  499. // The `override` directive
  500. // override FOO :=
  501. // is parsed as an assignment to a variable named `override FOO`.
  502. // There are very few places where `override` is used, just flag it.
  503. if strings.HasPrefix(name, "override ") {
  504. return []starlarkNode{ctx.newBadNode(a, "cannot handle override directive")}
  505. }
  506. if name == ".KATI_READONLY" {
  507. // Skip assignments to .KATI_READONLY. If it was in the output file, it
  508. // would be an error because it would be sorted before the definition of
  509. // the variable it's trying to make readonly.
  510. return []starlarkNode{}
  511. }
  512. // Soong configuration
  513. if strings.HasPrefix(name, soongNsPrefix) {
  514. return ctx.handleSoongNsAssignment(strings.TrimPrefix(name, soongNsPrefix), a)
  515. }
  516. lhs := ctx.addVariable(name)
  517. if lhs == nil {
  518. return []starlarkNode{ctx.newBadNode(a, "unknown variable %s", name)}
  519. }
  520. _, isTraced := ctx.tracedVariables[lhs.name()]
  521. asgn := &assignmentNode{lhs: lhs, mkValue: a.Value, isTraced: isTraced, location: ctx.errorLocation(a)}
  522. if lhs.valueType() == starlarkTypeUnknown {
  523. // Try to divine variable type from the RHS
  524. asgn.value = ctx.parseMakeString(a, a.Value)
  525. inferred_type := asgn.value.typ()
  526. if inferred_type != starlarkTypeUnknown {
  527. lhs.setValueType(inferred_type)
  528. }
  529. }
  530. if lhs.valueType() == starlarkTypeList {
  531. xConcat, xBad := ctx.buildConcatExpr(a)
  532. if xBad != nil {
  533. asgn.value = xBad
  534. } else {
  535. switch len(xConcat.items) {
  536. case 0:
  537. asgn.value = &listExpr{}
  538. case 1:
  539. asgn.value = xConcat.items[0]
  540. default:
  541. asgn.value = xConcat
  542. }
  543. }
  544. } else {
  545. asgn.value = ctx.parseMakeString(a, a.Value)
  546. }
  547. if asgn.lhs.valueType() == starlarkTypeString &&
  548. asgn.value.typ() != starlarkTypeUnknown &&
  549. asgn.value.typ() != starlarkTypeString {
  550. asgn.value = &toStringExpr{expr: asgn.value}
  551. }
  552. switch a.Type {
  553. case "=", ":=":
  554. asgn.flavor = asgnSet
  555. case "+=":
  556. asgn.flavor = asgnAppend
  557. case "?=":
  558. asgn.flavor = asgnMaybeSet
  559. default:
  560. panic(fmt.Errorf("unexpected assignment type %s", a.Type))
  561. }
  562. return []starlarkNode{asgn}
  563. }
  564. func (ctx *parseContext) handleSoongNsAssignment(name string, asgn *mkparser.Assignment) []starlarkNode {
  565. val := ctx.parseMakeString(asgn, asgn.Value)
  566. if xBad, ok := val.(*badExpr); ok {
  567. return []starlarkNode{&exprNode{expr: xBad}}
  568. }
  569. // Unfortunately, Soong namespaces can be set up by directly setting corresponding Make
  570. // variables instead of via add_soong_config_namespace + add_soong_config_var_value.
  571. // Try to divine the call from the assignment as follows:
  572. if name == "NAMESPACES" {
  573. // Upon seeng
  574. // SOONG_CONFIG_NAMESPACES += foo
  575. // remember that there is a namespace `foo` and act as we saw
  576. // $(call add_soong_config_namespace,foo)
  577. s, ok := maybeString(val)
  578. if !ok {
  579. return []starlarkNode{ctx.newBadNode(asgn, "cannot handle variables in SOONG_CONFIG_NAMESPACES assignment, please use add_soong_config_namespace instead")}
  580. }
  581. result := make([]starlarkNode, 0)
  582. for _, ns := range strings.Fields(s) {
  583. ctx.addSoongNamespace(ns)
  584. result = append(result, &exprNode{&callExpr{
  585. name: baseName + ".soong_config_namespace",
  586. args: []starlarkExpr{&globalsExpr{}, &stringLiteralExpr{ns}},
  587. returnType: starlarkTypeVoid,
  588. }})
  589. }
  590. return result
  591. } else {
  592. // Upon seeing
  593. // SOONG_CONFIG_x_y = v
  594. // find a namespace called `x` and act as if we encountered
  595. // $(call soong_config_set,x,y,v)
  596. // or check that `x_y` is a namespace, and then add the RHS of this assignment as variables in
  597. // it.
  598. // Emit an error in the ambiguous situation (namespaces `foo_bar` with a variable `baz`
  599. // and `foo` with a variable `bar_baz`.
  600. namespaceName := ""
  601. if ctx.hasSoongNamespace(name) {
  602. namespaceName = name
  603. }
  604. var varName string
  605. for pos, ch := range name {
  606. if !(ch == '_' && ctx.hasSoongNamespace(name[0:pos])) {
  607. continue
  608. }
  609. if namespaceName != "" {
  610. return []starlarkNode{ctx.newBadNode(asgn, "ambiguous soong namespace (may be either `%s` or `%s`)", namespaceName, name[0:pos])}
  611. }
  612. namespaceName = name[0:pos]
  613. varName = name[pos+1:]
  614. }
  615. if namespaceName == "" {
  616. return []starlarkNode{ctx.newBadNode(asgn, "cannot figure out Soong namespace, please use add_soong_config_var_value macro instead")}
  617. }
  618. if varName == "" {
  619. // Remember variables in this namespace
  620. s, ok := maybeString(val)
  621. if !ok {
  622. return []starlarkNode{ctx.newBadNode(asgn, "cannot handle variables in SOONG_CONFIG_ assignment, please use add_soong_config_var_value instead")}
  623. }
  624. ctx.updateSoongNamespace(asgn.Type != "+=", namespaceName, strings.Fields(s))
  625. return []starlarkNode{}
  626. }
  627. // Finally, handle assignment to a namespace variable
  628. if !ctx.hasNamespaceVar(namespaceName, varName) {
  629. return []starlarkNode{ctx.newBadNode(asgn, "no %s variable in %s namespace, please use add_soong_config_var_value instead", varName, namespaceName)}
  630. }
  631. fname := baseName + "." + soongConfigAssign
  632. if asgn.Type == "+=" {
  633. fname = baseName + "." + soongConfigAppend
  634. }
  635. return []starlarkNode{&exprNode{&callExpr{
  636. name: fname,
  637. args: []starlarkExpr{&globalsExpr{}, &stringLiteralExpr{namespaceName}, &stringLiteralExpr{varName}, val},
  638. returnType: starlarkTypeVoid,
  639. }}}
  640. }
  641. }
  642. func (ctx *parseContext) buildConcatExpr(a *mkparser.Assignment) (*concatExpr, *badExpr) {
  643. xConcat := &concatExpr{}
  644. var xItemList *listExpr
  645. addToItemList := func(x ...starlarkExpr) {
  646. if xItemList == nil {
  647. xItemList = &listExpr{[]starlarkExpr{}}
  648. }
  649. xItemList.items = append(xItemList.items, x...)
  650. }
  651. finishItemList := func() {
  652. if xItemList != nil {
  653. xConcat.items = append(xConcat.items, xItemList)
  654. xItemList = nil
  655. }
  656. }
  657. items := a.Value.Words()
  658. for _, item := range items {
  659. // A function call in RHS is supposed to return a list, all other item
  660. // expressions return individual elements.
  661. switch x := ctx.parseMakeString(a, item).(type) {
  662. case *badExpr:
  663. return nil, x
  664. case *stringLiteralExpr:
  665. addToItemList(maybeConvertToStringList(x).(*listExpr).items...)
  666. default:
  667. switch x.typ() {
  668. case starlarkTypeList:
  669. finishItemList()
  670. xConcat.items = append(xConcat.items, x)
  671. case starlarkTypeString:
  672. finishItemList()
  673. xConcat.items = append(xConcat.items, &callExpr{
  674. object: x,
  675. name: "split",
  676. args: nil,
  677. returnType: starlarkTypeList,
  678. })
  679. default:
  680. addToItemList(x)
  681. }
  682. }
  683. }
  684. if xItemList != nil {
  685. xConcat.items = append(xConcat.items, xItemList)
  686. }
  687. return xConcat, nil
  688. }
  689. func (ctx *parseContext) newDependentModule(path string, optional bool) *moduleInfo {
  690. modulePath := ctx.loadedModulePath(path)
  691. if mi, ok := ctx.dependentModules[modulePath]; ok {
  692. mi.optional = mi.optional && optional
  693. return mi
  694. }
  695. moduleName := moduleNameForFile(path)
  696. moduleLocalName := "_" + moduleName
  697. n, found := ctx.moduleNameCount[moduleName]
  698. if found {
  699. moduleLocalName += fmt.Sprintf("%d", n)
  700. }
  701. ctx.moduleNameCount[moduleName] = n + 1
  702. _, err := fs.Stat(ctx.script.sourceFS, path)
  703. mi := &moduleInfo{
  704. path: modulePath,
  705. originalPath: path,
  706. moduleLocalName: moduleLocalName,
  707. optional: optional,
  708. missing: err != nil,
  709. }
  710. ctx.dependentModules[modulePath] = mi
  711. ctx.script.inherited = append(ctx.script.inherited, mi)
  712. return mi
  713. }
  714. func (ctx *parseContext) handleSubConfig(
  715. v mkparser.Node, pathExpr starlarkExpr, loadAlways bool, processModule func(inheritedModule) starlarkNode) []starlarkNode {
  716. // Allow seeing $(sort $(wildcard realPathExpr)) or $(wildcard realPathExpr)
  717. // because those are functionally the same as not having the sort/wildcard calls.
  718. if ce, ok := pathExpr.(*callExpr); ok && ce.name == "rblf.mksort" && len(ce.args) == 1 {
  719. if ce2, ok2 := ce.args[0].(*callExpr); ok2 && ce2.name == "rblf.expand_wildcard" && len(ce2.args) == 1 {
  720. pathExpr = ce2.args[0]
  721. }
  722. } else if ce2, ok2 := pathExpr.(*callExpr); ok2 && ce2.name == "rblf.expand_wildcard" && len(ce2.args) == 1 {
  723. pathExpr = ce2.args[0]
  724. }
  725. // In a simple case, the name of a module to inherit/include is known statically.
  726. if path, ok := maybeString(pathExpr); ok {
  727. // Note that even if this directive loads a module unconditionally, a module may be
  728. // absent without causing any harm if this directive is inside an if/else block.
  729. moduleShouldExist := loadAlways && ctx.ifNestLevel == 0
  730. if strings.Contains(path, "*") {
  731. if paths, err := fs.Glob(ctx.script.sourceFS, path); err == nil {
  732. sort.Strings(paths)
  733. result := make([]starlarkNode, 0)
  734. for _, p := range paths {
  735. mi := ctx.newDependentModule(p, !moduleShouldExist)
  736. result = append(result, processModule(inheritedStaticModule{mi, loadAlways}))
  737. }
  738. return result
  739. } else {
  740. return []starlarkNode{ctx.newBadNode(v, "cannot glob wildcard argument")}
  741. }
  742. } else {
  743. mi := ctx.newDependentModule(path, !moduleShouldExist)
  744. return []starlarkNode{processModule(inheritedStaticModule{mi, loadAlways})}
  745. }
  746. }
  747. // If module path references variables (e.g., $(v1)/foo/$(v2)/device-config.mk), find all the paths in the
  748. // source tree that may be a match and the corresponding variable values. For instance, if the source tree
  749. // contains vendor1/foo/abc/dev.mk and vendor2/foo/def/dev.mk, the first one will be inherited when
  750. // (v1, v2) == ('vendor1', 'abc'), and the second one when (v1, v2) == ('vendor2', 'def').
  751. // We then emit the code that loads all of them, e.g.:
  752. // load("//vendor1/foo/abc:dev.rbc", _dev1_init="init")
  753. // load("//vendor2/foo/def/dev.rbc", _dev2_init="init")
  754. // And then inherit it as follows:
  755. // _e = {
  756. // "vendor1/foo/abc/dev.mk": ("vendor1/foo/abc/dev", _dev1_init),
  757. // "vendor2/foo/def/dev.mk": ("vendor2/foo/def/dev", _dev_init2) }.get("%s/foo/%s/dev.mk" % (v1, v2))
  758. // if _e:
  759. // rblf.inherit(handle, _e[0], _e[1])
  760. //
  761. var matchingPaths []string
  762. var needsWarning = false
  763. if interpolate, ok := pathExpr.(*interpolateExpr); ok {
  764. pathPattern := []string{interpolate.chunks[0]}
  765. for _, chunk := range interpolate.chunks[1:] {
  766. if chunk != "" {
  767. pathPattern = append(pathPattern, chunk)
  768. }
  769. }
  770. if len(pathPattern) == 1 {
  771. pathPattern = append(pathPattern, "")
  772. }
  773. matchingPaths = ctx.findMatchingPaths(pathPattern)
  774. needsWarning = pathPattern[0] == "" && len(ctx.includeTops) == 0
  775. } else if len(ctx.includeTops) > 0 {
  776. matchingPaths = append(matchingPaths, ctx.findMatchingPaths([]string{"", ""})...)
  777. } else {
  778. return []starlarkNode{ctx.newBadNode(v, "inherit-product/include argument is too complex")}
  779. }
  780. // Safeguard against $(call inherit-product,$(PRODUCT_PATH))
  781. const maxMatchingFiles = 150
  782. if len(matchingPaths) > maxMatchingFiles {
  783. return []starlarkNode{ctx.newBadNode(v, "there are >%d files matching the pattern, please rewrite it", maxMatchingFiles)}
  784. }
  785. res := inheritedDynamicModule{pathExpr, []*moduleInfo{}, loadAlways, ctx.errorLocation(v), needsWarning}
  786. for _, p := range matchingPaths {
  787. // A product configuration files discovered dynamically may attempt to inherit
  788. // from another one which does not exist in this source tree. Prevent load errors
  789. // by always loading the dynamic files as optional.
  790. res.candidateModules = append(res.candidateModules, ctx.newDependentModule(p, true))
  791. }
  792. return []starlarkNode{processModule(res)}
  793. }
  794. func (ctx *parseContext) findMatchingPaths(pattern []string) []string {
  795. files := ctx.script.makefileFinder.Find(".")
  796. if len(pattern) == 0 {
  797. return files
  798. }
  799. // Create regular expression from the pattern
  800. regexString := "^" + regexp.QuoteMeta(pattern[0])
  801. for _, s := range pattern[1:] {
  802. regexString += ".*" + regexp.QuoteMeta(s)
  803. }
  804. regexString += "$"
  805. rex := regexp.MustCompile(regexString)
  806. includeTopRegexString := ""
  807. if len(ctx.includeTops) > 0 {
  808. for i, top := range ctx.includeTops {
  809. if i > 0 {
  810. includeTopRegexString += "|"
  811. }
  812. includeTopRegexString += "^" + regexp.QuoteMeta(top)
  813. }
  814. } else {
  815. includeTopRegexString = ".*"
  816. }
  817. includeTopRegex := regexp.MustCompile(includeTopRegexString)
  818. // Now match
  819. var res []string
  820. for _, p := range files {
  821. if rex.MatchString(p) && includeTopRegex.MatchString(p) {
  822. res = append(res, p)
  823. }
  824. }
  825. return res
  826. }
  827. type inheritProductCallParser struct {
  828. loadAlways bool
  829. }
  830. func (p *inheritProductCallParser) parse(ctx *parseContext, v mkparser.Node, args *mkparser.MakeString) []starlarkNode {
  831. args.TrimLeftSpaces()
  832. args.TrimRightSpaces()
  833. pathExpr := ctx.parseMakeString(v, args)
  834. if _, ok := pathExpr.(*badExpr); ok {
  835. return []starlarkNode{ctx.newBadNode(v, "Unable to parse argument to inherit")}
  836. }
  837. return ctx.handleSubConfig(v, pathExpr, p.loadAlways, func(im inheritedModule) starlarkNode {
  838. return &inheritNode{im, p.loadAlways}
  839. })
  840. }
  841. func (ctx *parseContext) handleInclude(v *mkparser.Directive) []starlarkNode {
  842. loadAlways := v.Name[0] != '-'
  843. return ctx.handleSubConfig(v, ctx.parseMakeString(v, v.Args), loadAlways, func(im inheritedModule) starlarkNode {
  844. return &includeNode{im, loadAlways}
  845. })
  846. }
  847. func (ctx *parseContext) handleVariable(v *mkparser.Variable) []starlarkNode {
  848. // Handle:
  849. // $(call inherit-product,...)
  850. // $(call inherit-product-if-exists,...)
  851. // $(info xxx)
  852. // $(warning xxx)
  853. // $(error xxx)
  854. // $(call other-custom-functions,...)
  855. if name, args, ok := ctx.maybeParseFunctionCall(v, v.Name); ok {
  856. if kf, ok := knownNodeFunctions[name]; ok {
  857. return kf.parse(ctx, v, args)
  858. }
  859. }
  860. return []starlarkNode{&exprNode{expr: ctx.parseReference(v, v.Name)}}
  861. }
  862. func (ctx *parseContext) maybeHandleDefine(directive *mkparser.Directive) starlarkNode {
  863. macro_name := strings.Fields(directive.Args.Strings[0])[0]
  864. // Ignore the macros that we handle
  865. _, ignored := ignoredDefines[macro_name]
  866. _, known := knownFunctions[macro_name]
  867. if !ignored && !known {
  868. return ctx.newBadNode(directive, "define is not supported: %s", macro_name)
  869. }
  870. return nil
  871. }
  872. func (ctx *parseContext) handleIfBlock(ifDirective *mkparser.Directive) starlarkNode {
  873. ssSwitch := &switchNode{
  874. ssCases: []*switchCase{ctx.processBranch(ifDirective)},
  875. }
  876. for ctx.hasNodes() && ctx.fatalError == nil {
  877. node := ctx.getNode()
  878. switch x := node.(type) {
  879. case *mkparser.Directive:
  880. switch x.Name {
  881. case "else", "elifdef", "elifndef", "elifeq", "elifneq":
  882. ssSwitch.ssCases = append(ssSwitch.ssCases, ctx.processBranch(x))
  883. case "endif":
  884. return ssSwitch
  885. default:
  886. return ctx.newBadNode(node, "unexpected directive %s", x.Name)
  887. }
  888. default:
  889. return ctx.newBadNode(ifDirective, "unexpected statement")
  890. }
  891. }
  892. if ctx.fatalError == nil {
  893. ctx.fatalError = fmt.Errorf("no matching endif for %s", ifDirective.Dump())
  894. }
  895. return ctx.newBadNode(ifDirective, "no matching endif for %s", ifDirective.Dump())
  896. }
  897. // processBranch processes a single branch (if/elseif/else) until the next directive
  898. // on the same level.
  899. func (ctx *parseContext) processBranch(check *mkparser.Directive) *switchCase {
  900. block := &switchCase{gate: ctx.parseCondition(check)}
  901. defer func() {
  902. ctx.ifNestLevel--
  903. }()
  904. ctx.ifNestLevel++
  905. for ctx.hasNodes() {
  906. node := ctx.getNode()
  907. if d, ok := node.(*mkparser.Directive); ok {
  908. switch d.Name {
  909. case "else", "elifdef", "elifndef", "elifeq", "elifneq", "endif":
  910. ctx.backNode()
  911. return block
  912. }
  913. }
  914. block.nodes = append(block.nodes, ctx.handleSimpleStatement(node)...)
  915. }
  916. ctx.fatalError = fmt.Errorf("no matching endif for %s", check.Dump())
  917. return block
  918. }
  919. func (ctx *parseContext) parseCondition(check *mkparser.Directive) starlarkNode {
  920. switch check.Name {
  921. case "ifdef", "ifndef", "elifdef", "elifndef":
  922. if !check.Args.Const() {
  923. return ctx.newBadNode(check, "ifdef variable ref too complex: %s", check.Args.Dump())
  924. }
  925. v := NewVariableRefExpr(ctx.addVariable(check.Args.Strings[0]))
  926. if strings.HasSuffix(check.Name, "ndef") {
  927. v = &notExpr{v}
  928. }
  929. return &ifNode{
  930. isElif: strings.HasPrefix(check.Name, "elif"),
  931. expr: v,
  932. }
  933. case "ifeq", "ifneq", "elifeq", "elifneq":
  934. return &ifNode{
  935. isElif: strings.HasPrefix(check.Name, "elif"),
  936. expr: ctx.parseCompare(check),
  937. }
  938. case "else":
  939. return &elseNode{}
  940. default:
  941. panic(fmt.Errorf("%s: unknown directive: %s", ctx.script.mkFile, check.Dump()))
  942. }
  943. }
  944. func (ctx *parseContext) newBadExpr(node mkparser.Node, text string, args ...interface{}) starlarkExpr {
  945. if ctx.errorLogger != nil {
  946. ctx.errorLogger.NewError(ctx.errorLocation(node), node, text, args...)
  947. }
  948. ctx.script.hasErrors = true
  949. return &badExpr{errorLocation: ctx.errorLocation(node), message: fmt.Sprintf(text, args...)}
  950. }
  951. // records that the given node failed to be converted and includes an explanatory message
  952. func (ctx *parseContext) newBadNode(failedNode mkparser.Node, message string, args ...interface{}) starlarkNode {
  953. return &exprNode{ctx.newBadExpr(failedNode, message, args...)}
  954. }
  955. func (ctx *parseContext) parseCompare(cond *mkparser.Directive) starlarkExpr {
  956. // Strip outer parentheses
  957. mkArg := cloneMakeString(cond.Args)
  958. mkArg.Strings[0] = strings.TrimLeft(mkArg.Strings[0], "( ")
  959. n := len(mkArg.Strings)
  960. mkArg.Strings[n-1] = strings.TrimRight(mkArg.Strings[n-1], ") ")
  961. args := mkArg.Split(",")
  962. // TODO(asmundak): handle the case where the arguments are in quotes and space-separated
  963. if len(args) != 2 {
  964. return ctx.newBadExpr(cond, "ifeq/ifneq len(args) != 2 %s", cond.Dump())
  965. }
  966. args[0].TrimRightSpaces()
  967. args[1].TrimLeftSpaces()
  968. isEq := !strings.HasSuffix(cond.Name, "neq")
  969. xLeft := ctx.parseMakeString(cond, args[0])
  970. xRight := ctx.parseMakeString(cond, args[1])
  971. if bad, ok := xLeft.(*badExpr); ok {
  972. return bad
  973. }
  974. if bad, ok := xRight.(*badExpr); ok {
  975. return bad
  976. }
  977. if expr, ok := ctx.parseCompareSpecialCases(cond, xLeft, xRight); ok {
  978. return expr
  979. }
  980. var stringOperand string
  981. var otherOperand starlarkExpr
  982. if s, ok := maybeString(xLeft); ok {
  983. stringOperand = s
  984. otherOperand = xRight
  985. } else if s, ok := maybeString(xRight); ok {
  986. stringOperand = s
  987. otherOperand = xLeft
  988. }
  989. // If we've identified one of the operands as being a string literal, check
  990. // for some special cases we can do to simplify the resulting expression.
  991. if otherOperand != nil {
  992. if stringOperand == "" {
  993. if isEq {
  994. return negateExpr(otherOperand)
  995. } else {
  996. return otherOperand
  997. }
  998. }
  999. if stringOperand == "true" && otherOperand.typ() == starlarkTypeBool {
  1000. if !isEq {
  1001. return negateExpr(otherOperand)
  1002. } else {
  1003. return otherOperand
  1004. }
  1005. }
  1006. if otherOperand.typ() == starlarkTypeList {
  1007. fields := strings.Fields(stringOperand)
  1008. elements := make([]starlarkExpr, len(fields))
  1009. for i, s := range fields {
  1010. elements[i] = &stringLiteralExpr{literal: s}
  1011. }
  1012. return &eqExpr{
  1013. left: otherOperand,
  1014. right: &listExpr{elements},
  1015. isEq: isEq,
  1016. }
  1017. }
  1018. if intOperand, err := strconv.Atoi(strings.TrimSpace(stringOperand)); err == nil && otherOperand.typ() == starlarkTypeInt {
  1019. return &eqExpr{
  1020. left: otherOperand,
  1021. right: &intLiteralExpr{literal: intOperand},
  1022. isEq: isEq,
  1023. }
  1024. }
  1025. }
  1026. return &eqExpr{left: xLeft, right: xRight, isEq: isEq}
  1027. }
  1028. // Given an if statement's directive and the left/right starlarkExprs,
  1029. // check if the starlarkExprs are one of a few hardcoded special cases
  1030. // that can be converted to a simpler equality expression than simply comparing
  1031. // the two.
  1032. func (ctx *parseContext) parseCompareSpecialCases(directive *mkparser.Directive, left starlarkExpr,
  1033. right starlarkExpr) (starlarkExpr, bool) {
  1034. isEq := !strings.HasSuffix(directive.Name, "neq")
  1035. // All the special cases require a call on one side and a
  1036. // string literal/variable on the other. Turn the left/right variables into
  1037. // call/value variables, and return false if that's not possible.
  1038. var value starlarkExpr = nil
  1039. call, ok := left.(*callExpr)
  1040. if ok {
  1041. switch right.(type) {
  1042. case *stringLiteralExpr, *variableRefExpr:
  1043. value = right
  1044. }
  1045. } else {
  1046. call, _ = right.(*callExpr)
  1047. switch left.(type) {
  1048. case *stringLiteralExpr, *variableRefExpr:
  1049. value = left
  1050. }
  1051. }
  1052. if call == nil || value == nil {
  1053. return nil, false
  1054. }
  1055. switch call.name {
  1056. case baseName + ".filter":
  1057. return ctx.parseCompareFilterFuncResult(directive, call, value, isEq)
  1058. case baseName + ".findstring":
  1059. return ctx.parseCheckFindstringFuncResult(directive, call, value, !isEq), true
  1060. case baseName + ".strip":
  1061. return ctx.parseCompareStripFuncResult(directive, call, value, !isEq), true
  1062. }
  1063. return nil, false
  1064. }
  1065. func (ctx *parseContext) parseCompareFilterFuncResult(cond *mkparser.Directive,
  1066. filterFuncCall *callExpr, xValue starlarkExpr, negate bool) (starlarkExpr, bool) {
  1067. // We handle:
  1068. // * ifeq/ifneq (,$(filter v1 v2 ..., EXPR) becomes if EXPR not in/in ["v1", "v2", ...]
  1069. // * ifeq/ifneq (,$(filter EXPR, v1 v2 ...) becomes if EXPR not in/in ["v1", "v2", ...]
  1070. if x, ok := xValue.(*stringLiteralExpr); !ok || x.literal != "" {
  1071. return nil, false
  1072. }
  1073. xPattern := filterFuncCall.args[0]
  1074. xText := filterFuncCall.args[1]
  1075. var xInList *stringLiteralExpr
  1076. var expr starlarkExpr
  1077. var ok bool
  1078. if xInList, ok = xPattern.(*stringLiteralExpr); ok && !strings.ContainsRune(xInList.literal, '%') && xText.typ() == starlarkTypeList {
  1079. expr = xText
  1080. } else if xInList, ok = xText.(*stringLiteralExpr); ok {
  1081. expr = xPattern
  1082. } else {
  1083. return nil, false
  1084. }
  1085. slExpr := newStringListExpr(strings.Fields(xInList.literal))
  1086. // Generate simpler code for the common cases:
  1087. if expr.typ() == starlarkTypeList {
  1088. if len(slExpr.items) == 1 {
  1089. // Checking that a string belongs to list
  1090. return &inExpr{isNot: negate, list: expr, expr: slExpr.items[0]}, true
  1091. } else {
  1092. return nil, false
  1093. }
  1094. } else if len(slExpr.items) == 1 {
  1095. return &eqExpr{left: expr, right: slExpr.items[0], isEq: !negate}, true
  1096. } else {
  1097. return &inExpr{isNot: negate, list: newStringListExpr(strings.Fields(xInList.literal)), expr: expr}, true
  1098. }
  1099. }
  1100. func (ctx *parseContext) parseCheckFindstringFuncResult(directive *mkparser.Directive,
  1101. xCall *callExpr, xValue starlarkExpr, negate bool) starlarkExpr {
  1102. if isEmptyString(xValue) {
  1103. return &eqExpr{
  1104. left: &callExpr{
  1105. object: xCall.args[1],
  1106. name: "find",
  1107. args: []starlarkExpr{xCall.args[0]},
  1108. returnType: starlarkTypeInt,
  1109. },
  1110. right: &intLiteralExpr{-1},
  1111. isEq: !negate,
  1112. }
  1113. } else if s, ok := maybeString(xValue); ok {
  1114. if s2, ok := maybeString(xCall.args[0]); ok && s == s2 {
  1115. return &eqExpr{
  1116. left: &callExpr{
  1117. object: xCall.args[1],
  1118. name: "find",
  1119. args: []starlarkExpr{xCall.args[0]},
  1120. returnType: starlarkTypeInt,
  1121. },
  1122. right: &intLiteralExpr{-1},
  1123. isEq: negate,
  1124. }
  1125. }
  1126. }
  1127. return ctx.newBadExpr(directive, "$(findstring) can only be compared to nothing or its first argument")
  1128. }
  1129. func (ctx *parseContext) parseCompareStripFuncResult(directive *mkparser.Directive,
  1130. xCall *callExpr, xValue starlarkExpr, negate bool) starlarkExpr {
  1131. if _, ok := xValue.(*stringLiteralExpr); !ok {
  1132. return ctx.newBadExpr(directive, "strip result can be compared only to string: %s", xValue)
  1133. }
  1134. return &eqExpr{
  1135. left: &callExpr{
  1136. name: "strip",
  1137. args: xCall.args,
  1138. returnType: starlarkTypeString,
  1139. },
  1140. right: xValue, isEq: !negate}
  1141. }
  1142. func (ctx *parseContext) maybeParseFunctionCall(node mkparser.Node, ref *mkparser.MakeString) (name string, args *mkparser.MakeString, ok bool) {
  1143. ref.TrimLeftSpaces()
  1144. ref.TrimRightSpaces()
  1145. words := ref.SplitN(" ", 2)
  1146. if !words[0].Const() {
  1147. return "", nil, false
  1148. }
  1149. name = words[0].Dump()
  1150. args = mkparser.SimpleMakeString("", words[0].Pos())
  1151. if len(words) >= 2 {
  1152. args = words[1]
  1153. }
  1154. args.TrimLeftSpaces()
  1155. if name == "call" {
  1156. words = args.SplitN(",", 2)
  1157. if words[0].Empty() || !words[0].Const() {
  1158. return "", nil, false
  1159. }
  1160. name = words[0].Dump()
  1161. if len(words) < 2 {
  1162. args = mkparser.SimpleMakeString("", words[0].Pos())
  1163. } else {
  1164. args = words[1]
  1165. }
  1166. }
  1167. ok = true
  1168. return
  1169. }
  1170. // parses $(...), returning an expression
  1171. func (ctx *parseContext) parseReference(node mkparser.Node, ref *mkparser.MakeString) starlarkExpr {
  1172. ref.TrimLeftSpaces()
  1173. ref.TrimRightSpaces()
  1174. refDump := ref.Dump()
  1175. // Handle only the case where the first (or only) word is constant
  1176. words := ref.SplitN(" ", 2)
  1177. if !words[0].Const() {
  1178. if len(words) == 1 {
  1179. expr := ctx.parseMakeString(node, ref)
  1180. return &callExpr{
  1181. object: &identifierExpr{"cfg"},
  1182. name: "get",
  1183. args: []starlarkExpr{
  1184. expr,
  1185. &callExpr{
  1186. object: &identifierExpr{"g"},
  1187. name: "get",
  1188. args: []starlarkExpr{
  1189. expr,
  1190. &stringLiteralExpr{literal: ""},
  1191. },
  1192. returnType: starlarkTypeUnknown,
  1193. },
  1194. },
  1195. returnType: starlarkTypeUnknown,
  1196. }
  1197. } else {
  1198. return ctx.newBadExpr(node, "reference is too complex: %s", refDump)
  1199. }
  1200. }
  1201. if name, _, ok := ctx.maybeParseFunctionCall(node, ref); ok {
  1202. if _, unsupported := unsupportedFunctions[name]; unsupported {
  1203. return ctx.newBadExpr(node, "%s is not supported", refDump)
  1204. }
  1205. }
  1206. // If it is a single word, it can be a simple variable
  1207. // reference or a function call
  1208. if len(words) == 1 && !isMakeControlFunc(refDump) && refDump != "shell" && refDump != "eval" {
  1209. if strings.HasPrefix(refDump, soongNsPrefix) {
  1210. // TODO (asmundak): if we find many, maybe handle them.
  1211. return ctx.newBadExpr(node, "SOONG_CONFIG_ variables cannot be referenced, use soong_config_get instead: %s", refDump)
  1212. }
  1213. // Handle substitution references: https://www.gnu.org/software/make/manual/html_node/Substitution-Refs.html
  1214. if strings.Contains(refDump, ":") {
  1215. parts := strings.SplitN(refDump, ":", 2)
  1216. substParts := strings.SplitN(parts[1], "=", 2)
  1217. if len(substParts) < 2 || strings.Count(substParts[0], "%") > 1 {
  1218. return ctx.newBadExpr(node, "Invalid substitution reference")
  1219. }
  1220. if !strings.Contains(substParts[0], "%") {
  1221. if strings.Contains(substParts[1], "%") {
  1222. return ctx.newBadExpr(node, "A substitution reference must have a %% in the \"before\" part of the substitution if it has one in the \"after\" part.")
  1223. }
  1224. substParts[0] = "%" + substParts[0]
  1225. substParts[1] = "%" + substParts[1]
  1226. }
  1227. v := ctx.addVariable(parts[0])
  1228. if v == nil {
  1229. return ctx.newBadExpr(node, "unknown variable %s", refDump)
  1230. }
  1231. return &callExpr{
  1232. name: baseName + ".mkpatsubst",
  1233. returnType: starlarkTypeString,
  1234. args: []starlarkExpr{
  1235. &stringLiteralExpr{literal: substParts[0]},
  1236. &stringLiteralExpr{literal: substParts[1]},
  1237. NewVariableRefExpr(v),
  1238. },
  1239. }
  1240. }
  1241. if v := ctx.addVariable(refDump); v != nil {
  1242. return NewVariableRefExpr(v)
  1243. }
  1244. return ctx.newBadExpr(node, "unknown variable %s", refDump)
  1245. }
  1246. if name, args, ok := ctx.maybeParseFunctionCall(node, ref); ok {
  1247. if kf, found := knownFunctions[name]; found {
  1248. return kf.parse(ctx, node, args)
  1249. } else {
  1250. return ctx.newBadExpr(node, "cannot handle invoking %s", name)
  1251. }
  1252. }
  1253. return ctx.newBadExpr(node, "cannot handle %s", refDump)
  1254. }
  1255. type simpleCallParser struct {
  1256. name string
  1257. returnType starlarkType
  1258. addGlobals bool
  1259. addHandle bool
  1260. }
  1261. func (p *simpleCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
  1262. expr := &callExpr{name: p.name, returnType: p.returnType}
  1263. if p.addGlobals {
  1264. expr.args = append(expr.args, &globalsExpr{})
  1265. }
  1266. if p.addHandle {
  1267. expr.args = append(expr.args, &identifierExpr{name: "handle"})
  1268. }
  1269. for _, arg := range args.Split(",") {
  1270. arg.TrimLeftSpaces()
  1271. arg.TrimRightSpaces()
  1272. x := ctx.parseMakeString(node, arg)
  1273. if xBad, ok := x.(*badExpr); ok {
  1274. return xBad
  1275. }
  1276. expr.args = append(expr.args, x)
  1277. }
  1278. return expr
  1279. }
  1280. type makeControlFuncParser struct {
  1281. name string
  1282. }
  1283. func (p *makeControlFuncParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
  1284. // Make control functions need special treatment as everything
  1285. // after the name is a single text argument
  1286. x := ctx.parseMakeString(node, args)
  1287. if xBad, ok := x.(*badExpr); ok {
  1288. return xBad
  1289. }
  1290. return &callExpr{
  1291. name: p.name,
  1292. args: []starlarkExpr{
  1293. &stringLiteralExpr{ctx.script.mkFile},
  1294. x,
  1295. },
  1296. returnType: starlarkTypeUnknown,
  1297. }
  1298. }
  1299. type shellCallParser struct{}
  1300. func (p *shellCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
  1301. // Shell functions need special treatment as everything
  1302. // after the name is a single text argument
  1303. x := ctx.parseMakeString(node, args)
  1304. if xBad, ok := x.(*badExpr); ok {
  1305. return xBad
  1306. }
  1307. return &callExpr{
  1308. name: baseName + ".shell",
  1309. args: []starlarkExpr{x},
  1310. returnType: starlarkTypeUnknown,
  1311. }
  1312. }
  1313. type myDirCallParser struct{}
  1314. func (p *myDirCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
  1315. if !args.Empty() {
  1316. return ctx.newBadExpr(node, "my-dir function cannot have any arguments passed to it.")
  1317. }
  1318. return &stringLiteralExpr{literal: filepath.Dir(ctx.script.mkFile)}
  1319. }
  1320. type andOrParser struct {
  1321. isAnd bool
  1322. }
  1323. func (p *andOrParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
  1324. if args.Empty() {
  1325. return ctx.newBadExpr(node, "and/or function must have at least 1 argument")
  1326. }
  1327. op := "or"
  1328. if p.isAnd {
  1329. op = "and"
  1330. }
  1331. argsParsed := make([]starlarkExpr, 0)
  1332. for _, arg := range args.Split(",") {
  1333. arg.TrimLeftSpaces()
  1334. arg.TrimRightSpaces()
  1335. x := ctx.parseMakeString(node, arg)
  1336. if xBad, ok := x.(*badExpr); ok {
  1337. return xBad
  1338. }
  1339. argsParsed = append(argsParsed, x)
  1340. }
  1341. typ := starlarkTypeUnknown
  1342. for _, arg := range argsParsed {
  1343. if typ != arg.typ() && arg.typ() != starlarkTypeUnknown && typ != starlarkTypeUnknown {
  1344. return ctx.newBadExpr(node, "Expected all arguments to $(or) or $(and) to have the same type, found %q and %q", typ.String(), arg.typ().String())
  1345. }
  1346. if arg.typ() != starlarkTypeUnknown {
  1347. typ = arg.typ()
  1348. }
  1349. }
  1350. result := argsParsed[0]
  1351. for _, arg := range argsParsed[1:] {
  1352. result = &binaryOpExpr{
  1353. left: result,
  1354. right: arg,
  1355. op: op,
  1356. returnType: typ,
  1357. }
  1358. }
  1359. return result
  1360. }
  1361. type isProductInListCallParser struct{}
  1362. func (p *isProductInListCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
  1363. if args.Empty() {
  1364. return ctx.newBadExpr(node, "is-product-in-list requires an argument")
  1365. }
  1366. return &inExpr{
  1367. expr: NewVariableRefExpr(ctx.addVariable("TARGET_PRODUCT")),
  1368. list: maybeConvertToStringList(ctx.parseMakeString(node, args)),
  1369. isNot: false,
  1370. }
  1371. }
  1372. type isVendorBoardPlatformCallParser struct{}
  1373. func (p *isVendorBoardPlatformCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
  1374. if args.Empty() || !identifierFullMatchRegex.MatchString(args.Dump()) {
  1375. return ctx.newBadExpr(node, "cannot handle non-constant argument to is-vendor-board-platform")
  1376. }
  1377. return &inExpr{
  1378. expr: NewVariableRefExpr(ctx.addVariable("TARGET_BOARD_PLATFORM")),
  1379. list: NewVariableRefExpr(ctx.addVariable(args.Dump() + "_BOARD_PLATFORMS")),
  1380. isNot: false,
  1381. }
  1382. }
  1383. type isVendorBoardQcomCallParser struct{}
  1384. func (p *isVendorBoardQcomCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
  1385. if !args.Empty() {
  1386. return ctx.newBadExpr(node, "is-vendor-board-qcom does not accept any arguments")
  1387. }
  1388. return &inExpr{
  1389. expr: NewVariableRefExpr(ctx.addVariable("TARGET_BOARD_PLATFORM")),
  1390. list: NewVariableRefExpr(ctx.addVariable("QCOM_BOARD_PLATFORMS")),
  1391. isNot: false,
  1392. }
  1393. }
  1394. type substCallParser struct {
  1395. fname string
  1396. }
  1397. func (p *substCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
  1398. words := args.Split(",")
  1399. if len(words) != 3 {
  1400. return ctx.newBadExpr(node, "%s function should have 3 arguments", p.fname)
  1401. }
  1402. from := ctx.parseMakeString(node, words[0])
  1403. if xBad, ok := from.(*badExpr); ok {
  1404. return xBad
  1405. }
  1406. to := ctx.parseMakeString(node, words[1])
  1407. if xBad, ok := to.(*badExpr); ok {
  1408. return xBad
  1409. }
  1410. words[2].TrimLeftSpaces()
  1411. words[2].TrimRightSpaces()
  1412. obj := ctx.parseMakeString(node, words[2])
  1413. typ := obj.typ()
  1414. if typ == starlarkTypeString && p.fname == "subst" {
  1415. // Optimization: if it's $(subst from, to, string), emit string.replace(from, to)
  1416. return &callExpr{
  1417. object: obj,
  1418. name: "replace",
  1419. args: []starlarkExpr{from, to},
  1420. returnType: typ,
  1421. }
  1422. }
  1423. return &callExpr{
  1424. name: baseName + ".mk" + p.fname,
  1425. args: []starlarkExpr{from, to, obj},
  1426. returnType: obj.typ(),
  1427. }
  1428. }
  1429. type ifCallParser struct{}
  1430. func (p *ifCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
  1431. words := args.Split(",")
  1432. if len(words) != 2 && len(words) != 3 {
  1433. return ctx.newBadExpr(node, "if function should have 2 or 3 arguments, found "+strconv.Itoa(len(words)))
  1434. }
  1435. condition := ctx.parseMakeString(node, words[0])
  1436. ifTrue := ctx.parseMakeString(node, words[1])
  1437. var ifFalse starlarkExpr
  1438. if len(words) == 3 {
  1439. ifFalse = ctx.parseMakeString(node, words[2])
  1440. } else {
  1441. switch ifTrue.typ() {
  1442. case starlarkTypeList:
  1443. ifFalse = &listExpr{items: []starlarkExpr{}}
  1444. case starlarkTypeInt:
  1445. ifFalse = &intLiteralExpr{literal: 0}
  1446. case starlarkTypeBool:
  1447. ifFalse = &boolLiteralExpr{literal: false}
  1448. default:
  1449. ifFalse = &stringLiteralExpr{literal: ""}
  1450. }
  1451. }
  1452. return &ifExpr{
  1453. condition,
  1454. ifTrue,
  1455. ifFalse,
  1456. }
  1457. }
  1458. type ifCallNodeParser struct{}
  1459. func (p *ifCallNodeParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) []starlarkNode {
  1460. words := args.Split(",")
  1461. if len(words) != 2 && len(words) != 3 {
  1462. return []starlarkNode{ctx.newBadNode(node, "if function should have 2 or 3 arguments, found "+strconv.Itoa(len(words)))}
  1463. }
  1464. ifn := &ifNode{expr: ctx.parseMakeString(node, words[0])}
  1465. cases := []*switchCase{
  1466. {
  1467. gate: ifn,
  1468. nodes: ctx.parseNodeMakeString(node, words[1]),
  1469. },
  1470. }
  1471. if len(words) == 3 {
  1472. cases = append(cases, &switchCase{
  1473. gate: &elseNode{},
  1474. nodes: ctx.parseNodeMakeString(node, words[2]),
  1475. })
  1476. }
  1477. if len(cases) == 2 {
  1478. if len(cases[1].nodes) == 0 {
  1479. // Remove else branch if it has no contents
  1480. cases = cases[:1]
  1481. } else if len(cases[0].nodes) == 0 {
  1482. // If the if branch has no contents but the else does,
  1483. // move them to the if and negate its condition
  1484. ifn.expr = negateExpr(ifn.expr)
  1485. cases[0].nodes = cases[1].nodes
  1486. cases = cases[:1]
  1487. }
  1488. }
  1489. return []starlarkNode{&switchNode{ssCases: cases}}
  1490. }
  1491. type foreachCallParser struct{}
  1492. func (p *foreachCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
  1493. words := args.Split(",")
  1494. if len(words) != 3 {
  1495. return ctx.newBadExpr(node, "foreach function should have 3 arguments, found "+strconv.Itoa(len(words)))
  1496. }
  1497. if !words[0].Const() || words[0].Empty() || !identifierFullMatchRegex.MatchString(words[0].Strings[0]) {
  1498. return ctx.newBadExpr(node, "first argument to foreach function must be a simple string identifier")
  1499. }
  1500. loopVarName := words[0].Strings[0]
  1501. list := ctx.parseMakeString(node, words[1])
  1502. action := ctx.parseMakeString(node, words[2]).transform(func(expr starlarkExpr) starlarkExpr {
  1503. if varRefExpr, ok := expr.(*variableRefExpr); ok && varRefExpr.ref.name() == loopVarName {
  1504. return &identifierExpr{loopVarName}
  1505. }
  1506. return nil
  1507. })
  1508. if list.typ() != starlarkTypeList {
  1509. list = &callExpr{
  1510. name: baseName + ".words",
  1511. returnType: starlarkTypeList,
  1512. args: []starlarkExpr{list},
  1513. }
  1514. }
  1515. var result starlarkExpr = &foreachExpr{
  1516. varName: loopVarName,
  1517. list: list,
  1518. action: action,
  1519. }
  1520. if action.typ() == starlarkTypeList {
  1521. result = &callExpr{
  1522. name: baseName + ".flatten_2d_list",
  1523. args: []starlarkExpr{result},
  1524. returnType: starlarkTypeList,
  1525. }
  1526. }
  1527. return result
  1528. }
  1529. func transformNode(node starlarkNode, transformer func(expr starlarkExpr) starlarkExpr) {
  1530. switch a := node.(type) {
  1531. case *ifNode:
  1532. a.expr = a.expr.transform(transformer)
  1533. case *switchCase:
  1534. transformNode(a.gate, transformer)
  1535. for _, n := range a.nodes {
  1536. transformNode(n, transformer)
  1537. }
  1538. case *switchNode:
  1539. for _, n := range a.ssCases {
  1540. transformNode(n, transformer)
  1541. }
  1542. case *exprNode:
  1543. a.expr = a.expr.transform(transformer)
  1544. case *assignmentNode:
  1545. a.value = a.value.transform(transformer)
  1546. case *foreachNode:
  1547. a.list = a.list.transform(transformer)
  1548. for _, n := range a.actions {
  1549. transformNode(n, transformer)
  1550. }
  1551. case *inheritNode:
  1552. if b, ok := a.module.(inheritedDynamicModule); ok {
  1553. b.path = b.path.transform(transformer)
  1554. a.module = b
  1555. }
  1556. case *includeNode:
  1557. if b, ok := a.module.(inheritedDynamicModule); ok {
  1558. b.path = b.path.transform(transformer)
  1559. a.module = b
  1560. }
  1561. }
  1562. }
  1563. type foreachCallNodeParser struct{}
  1564. func (p *foreachCallNodeParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) []starlarkNode {
  1565. words := args.Split(",")
  1566. if len(words) != 3 {
  1567. return []starlarkNode{ctx.newBadNode(node, "foreach function should have 3 arguments, found "+strconv.Itoa(len(words)))}
  1568. }
  1569. if !words[0].Const() || words[0].Empty() || !identifierFullMatchRegex.MatchString(words[0].Strings[0]) {
  1570. return []starlarkNode{ctx.newBadNode(node, "first argument to foreach function must be a simple string identifier")}
  1571. }
  1572. loopVarName := words[0].Strings[0]
  1573. list := ctx.parseMakeString(node, words[1])
  1574. if list.typ() != starlarkTypeList {
  1575. list = &callExpr{
  1576. name: baseName + ".words",
  1577. returnType: starlarkTypeList,
  1578. args: []starlarkExpr{list},
  1579. }
  1580. }
  1581. actions := ctx.parseNodeMakeString(node, words[2])
  1582. // TODO(colefaust): Replace transforming code with something more elegant
  1583. for _, action := range actions {
  1584. transformNode(action, func(expr starlarkExpr) starlarkExpr {
  1585. if varRefExpr, ok := expr.(*variableRefExpr); ok && varRefExpr.ref.name() == loopVarName {
  1586. return &identifierExpr{loopVarName}
  1587. }
  1588. return nil
  1589. })
  1590. }
  1591. return []starlarkNode{&foreachNode{
  1592. varName: loopVarName,
  1593. list: list,
  1594. actions: actions,
  1595. }}
  1596. }
  1597. type wordCallParser struct{}
  1598. func (p *wordCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
  1599. words := args.Split(",")
  1600. if len(words) != 2 {
  1601. return ctx.newBadExpr(node, "word function should have 2 arguments")
  1602. }
  1603. var index = 0
  1604. if words[0].Const() {
  1605. if i, err := strconv.Atoi(strings.TrimSpace(words[0].Strings[0])); err == nil {
  1606. index = i
  1607. }
  1608. }
  1609. if index < 1 {
  1610. return ctx.newBadExpr(node, "word index should be constant positive integer")
  1611. }
  1612. words[1].TrimLeftSpaces()
  1613. words[1].TrimRightSpaces()
  1614. array := ctx.parseMakeString(node, words[1])
  1615. if bad, ok := array.(*badExpr); ok {
  1616. return bad
  1617. }
  1618. if array.typ() != starlarkTypeList {
  1619. array = &callExpr{
  1620. name: baseName + ".words",
  1621. args: []starlarkExpr{array},
  1622. returnType: starlarkTypeList,
  1623. }
  1624. }
  1625. return &indexExpr{array, &intLiteralExpr{index - 1}}
  1626. }
  1627. type wordsCallParser struct{}
  1628. func (p *wordsCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
  1629. args.TrimLeftSpaces()
  1630. args.TrimRightSpaces()
  1631. array := ctx.parseMakeString(node, args)
  1632. if bad, ok := array.(*badExpr); ok {
  1633. return bad
  1634. }
  1635. if array.typ() != starlarkTypeList {
  1636. array = &callExpr{
  1637. name: baseName + ".words",
  1638. args: []starlarkExpr{array},
  1639. returnType: starlarkTypeList,
  1640. }
  1641. }
  1642. return &callExpr{
  1643. name: "len",
  1644. args: []starlarkExpr{array},
  1645. returnType: starlarkTypeInt,
  1646. }
  1647. }
  1648. func parseIntegerArguments(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString, expectedArgs int) ([]starlarkExpr, error) {
  1649. parsedArgs := make([]starlarkExpr, 0)
  1650. for _, arg := range args.Split(",") {
  1651. expr := ctx.parseMakeString(node, arg)
  1652. if expr.typ() == starlarkTypeList {
  1653. return nil, fmt.Errorf("argument to math argument has type list, which cannot be converted to int")
  1654. }
  1655. if s, ok := maybeString(expr); ok {
  1656. intVal, err := strconv.Atoi(strings.TrimSpace(s))
  1657. if err != nil {
  1658. return nil, err
  1659. }
  1660. expr = &intLiteralExpr{literal: intVal}
  1661. } else if expr.typ() != starlarkTypeInt {
  1662. expr = &callExpr{
  1663. name: "int",
  1664. args: []starlarkExpr{expr},
  1665. returnType: starlarkTypeInt,
  1666. }
  1667. }
  1668. parsedArgs = append(parsedArgs, expr)
  1669. }
  1670. if len(parsedArgs) != expectedArgs {
  1671. return nil, fmt.Errorf("function should have %d arguments", expectedArgs)
  1672. }
  1673. return parsedArgs, nil
  1674. }
  1675. type mathComparisonCallParser struct {
  1676. op string
  1677. }
  1678. func (p *mathComparisonCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
  1679. parsedArgs, err := parseIntegerArguments(ctx, node, args, 2)
  1680. if err != nil {
  1681. return ctx.newBadExpr(node, err.Error())
  1682. }
  1683. return &binaryOpExpr{
  1684. left: parsedArgs[0],
  1685. right: parsedArgs[1],
  1686. op: p.op,
  1687. returnType: starlarkTypeBool,
  1688. }
  1689. }
  1690. type mathMaxOrMinCallParser struct {
  1691. function string
  1692. }
  1693. func (p *mathMaxOrMinCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
  1694. parsedArgs, err := parseIntegerArguments(ctx, node, args, 2)
  1695. if err != nil {
  1696. return ctx.newBadExpr(node, err.Error())
  1697. }
  1698. return &callExpr{
  1699. object: nil,
  1700. name: p.function,
  1701. args: parsedArgs,
  1702. returnType: starlarkTypeInt,
  1703. }
  1704. }
  1705. type evalNodeParser struct{}
  1706. func (p *evalNodeParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) []starlarkNode {
  1707. parser := mkparser.NewParser("Eval expression", strings.NewReader(args.Dump()))
  1708. nodes, errs := parser.Parse()
  1709. if errs != nil {
  1710. return []starlarkNode{ctx.newBadNode(node, "Unable to parse eval statement")}
  1711. }
  1712. if len(nodes) == 0 {
  1713. return []starlarkNode{}
  1714. } else if len(nodes) == 1 {
  1715. // Replace the nodeLocator with one that just returns the location of
  1716. // the $(eval) node. Otherwise, statements inside an $(eval) will show as
  1717. // being on line 1 of the file, because they're on line 1 of
  1718. // strings.NewReader(args.Dump())
  1719. oldNodeLocator := ctx.script.nodeLocator
  1720. ctx.script.nodeLocator = func(pos mkparser.Pos) int {
  1721. return oldNodeLocator(node.Pos())
  1722. }
  1723. defer func() {
  1724. ctx.script.nodeLocator = oldNodeLocator
  1725. }()
  1726. switch n := nodes[0].(type) {
  1727. case *mkparser.Assignment:
  1728. if n.Name.Const() {
  1729. return ctx.handleAssignment(n)
  1730. }
  1731. case *mkparser.Comment:
  1732. return []starlarkNode{&commentNode{strings.TrimSpace("#" + n.Comment)}}
  1733. case *mkparser.Directive:
  1734. if n.Name == "include" || n.Name == "-include" {
  1735. return ctx.handleInclude(n)
  1736. }
  1737. case *mkparser.Variable:
  1738. // Technically inherit-product(-if-exists) don't need to be put inside
  1739. // an eval, but some makefiles do it, presumably because they copy+pasted
  1740. // from a $(eval include ...)
  1741. if name, _, ok := ctx.maybeParseFunctionCall(n, n.Name); ok {
  1742. if name == "inherit-product" || name == "inherit-product-if-exists" {
  1743. return ctx.handleVariable(n)
  1744. }
  1745. }
  1746. }
  1747. }
  1748. return []starlarkNode{ctx.newBadNode(node, "Eval expression too complex; only assignments, comments, includes, and inherit-products are supported")}
  1749. }
  1750. type lowerUpperParser struct {
  1751. isUpper bool
  1752. }
  1753. func (p *lowerUpperParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
  1754. fn := "lower"
  1755. if p.isUpper {
  1756. fn = "upper"
  1757. }
  1758. arg := ctx.parseMakeString(node, args)
  1759. return &callExpr{
  1760. object: arg,
  1761. name: fn,
  1762. returnType: starlarkTypeString,
  1763. }
  1764. }
  1765. func (ctx *parseContext) parseMakeString(node mkparser.Node, mk *mkparser.MakeString) starlarkExpr {
  1766. if mk.Const() {
  1767. return &stringLiteralExpr{mk.Dump()}
  1768. }
  1769. if mkRef, ok := mk.SingleVariable(); ok {
  1770. return ctx.parseReference(node, mkRef)
  1771. }
  1772. // If we reached here, it's neither string literal nor a simple variable,
  1773. // we need a full-blown interpolation node that will generate
  1774. // "a%b%c" % (X, Y) for a$(X)b$(Y)c
  1775. parts := make([]starlarkExpr, len(mk.Variables)+len(mk.Strings))
  1776. for i := 0; i < len(parts); i++ {
  1777. if i%2 == 0 {
  1778. parts[i] = &stringLiteralExpr{literal: mk.Strings[i/2]}
  1779. } else {
  1780. parts[i] = ctx.parseReference(node, mk.Variables[i/2].Name)
  1781. if x, ok := parts[i].(*badExpr); ok {
  1782. return x
  1783. }
  1784. }
  1785. }
  1786. return NewInterpolateExpr(parts)
  1787. }
  1788. func (ctx *parseContext) parseNodeMakeString(node mkparser.Node, mk *mkparser.MakeString) []starlarkNode {
  1789. // Discard any constant values in the make string, as they would be top level
  1790. // string literals and do nothing.
  1791. result := make([]starlarkNode, 0, len(mk.Variables))
  1792. for i := range mk.Variables {
  1793. result = append(result, ctx.handleVariable(&mk.Variables[i])...)
  1794. }
  1795. return result
  1796. }
  1797. // Handles the statements whose treatment is the same in all contexts: comment,
  1798. // assignment, variable (which is a macro call in reality) and all constructs that
  1799. // do not handle in any context ('define directive and any unrecognized stuff).
  1800. func (ctx *parseContext) handleSimpleStatement(node mkparser.Node) []starlarkNode {
  1801. var result []starlarkNode
  1802. switch x := node.(type) {
  1803. case *mkparser.Comment:
  1804. if n, handled := ctx.maybeHandleAnnotation(x); handled && n != nil {
  1805. result = []starlarkNode{n}
  1806. } else if !handled {
  1807. result = []starlarkNode{&commentNode{strings.TrimSpace("#" + x.Comment)}}
  1808. }
  1809. case *mkparser.Assignment:
  1810. result = ctx.handleAssignment(x)
  1811. case *mkparser.Variable:
  1812. result = ctx.handleVariable(x)
  1813. case *mkparser.Directive:
  1814. switch x.Name {
  1815. case "define":
  1816. if res := ctx.maybeHandleDefine(x); res != nil {
  1817. result = []starlarkNode{res}
  1818. }
  1819. case "include", "-include":
  1820. result = ctx.handleInclude(x)
  1821. case "ifeq", "ifneq", "ifdef", "ifndef":
  1822. result = []starlarkNode{ctx.handleIfBlock(x)}
  1823. default:
  1824. result = []starlarkNode{ctx.newBadNode(x, "unexpected directive %s", x.Name)}
  1825. }
  1826. default:
  1827. result = []starlarkNode{ctx.newBadNode(x, "unsupported line %s", strings.ReplaceAll(x.Dump(), "\n", "\n#"))}
  1828. }
  1829. // Clear the includeTops after each non-comment statement
  1830. // so that include annotations placed on certain statements don't apply
  1831. // globally for the rest of the makefile was well.
  1832. if _, wasComment := node.(*mkparser.Comment); !wasComment {
  1833. ctx.atTopOfMakefile = false
  1834. ctx.includeTops = []string{}
  1835. }
  1836. if result == nil {
  1837. result = []starlarkNode{}
  1838. }
  1839. return result
  1840. }
  1841. // The types allowed in a type_hint
  1842. var typeHintMap = map[string]starlarkType{
  1843. "string": starlarkTypeString,
  1844. "list": starlarkTypeList,
  1845. }
  1846. // Processes annotation. An annotation is a comment that starts with #RBC# and provides
  1847. // a conversion hint -- say, where to look for the dynamically calculated inherit/include
  1848. // paths. Returns true if the comment was a successfully-handled annotation.
  1849. func (ctx *parseContext) maybeHandleAnnotation(cnode *mkparser.Comment) (starlarkNode, bool) {
  1850. maybeTrim := func(s, prefix string) (string, bool) {
  1851. if strings.HasPrefix(s, prefix) {
  1852. return strings.TrimSpace(strings.TrimPrefix(s, prefix)), true
  1853. }
  1854. return s, false
  1855. }
  1856. annotation, ok := maybeTrim(cnode.Comment, annotationCommentPrefix)
  1857. if !ok {
  1858. return nil, false
  1859. }
  1860. if p, ok := maybeTrim(annotation, "include_top"); ok {
  1861. // Don't allow duplicate include tops, because then we will generate
  1862. // invalid starlark code. (duplicate keys in the _entry dictionary)
  1863. for _, top := range ctx.includeTops {
  1864. if top == p {
  1865. return nil, true
  1866. }
  1867. }
  1868. ctx.includeTops = append(ctx.includeTops, p)
  1869. return nil, true
  1870. } else if p, ok := maybeTrim(annotation, "type_hint"); ok {
  1871. // Type hints must come at the beginning the file, to avoid confusion
  1872. // if a type hint was specified later and thus only takes effect for half
  1873. // of the file.
  1874. if !ctx.atTopOfMakefile {
  1875. return ctx.newBadNode(cnode, "type_hint annotations must come before the first Makefile statement"), true
  1876. }
  1877. parts := strings.Fields(p)
  1878. if len(parts) <= 1 {
  1879. return ctx.newBadNode(cnode, "Invalid type_hint annotation: %s. Must be a variable type followed by a list of variables of that type", p), true
  1880. }
  1881. var varType starlarkType
  1882. if varType, ok = typeHintMap[parts[0]]; !ok {
  1883. varType = starlarkTypeUnknown
  1884. }
  1885. if varType == starlarkTypeUnknown {
  1886. return ctx.newBadNode(cnode, "Invalid type_hint annotation. Only list/string types are accepted, found %s", parts[0]), true
  1887. }
  1888. for _, name := range parts[1:] {
  1889. // Don't allow duplicate type hints
  1890. if _, ok := ctx.typeHints[name]; ok {
  1891. return ctx.newBadNode(cnode, "Duplicate type hint for variable %s", name), true
  1892. }
  1893. ctx.typeHints[name] = varType
  1894. }
  1895. return nil, true
  1896. }
  1897. return ctx.newBadNode(cnode, "unsupported annotation %s", cnode.Comment), true
  1898. }
  1899. func (ctx *parseContext) loadedModulePath(path string) string {
  1900. // During the transition to Roboleaf some of the product configuration files
  1901. // will be converted and checked in while the others will be generated on the fly
  1902. // and run. The runner (rbcrun application) accommodates this by allowing three
  1903. // different ways to specify the loaded file location:
  1904. // 1) load(":<file>",...) loads <file> from the same directory
  1905. // 2) load("//path/relative/to/source/root:<file>", ...) loads <file> source tree
  1906. // 3) load("/absolute/path/to/<file> absolute path
  1907. // If the file being generated and the file it wants to load are in the same directory,
  1908. // generate option 1.
  1909. // Otherwise, if output directory is not specified, generate 2)
  1910. // Finally, if output directory has been specified and the file being generated and
  1911. // the file it wants to load from are in the different directories, generate 2) or 3):
  1912. // * if the file being loaded exists in the source tree, generate 2)
  1913. // * otherwise, generate 3)
  1914. // Finally, figure out the loaded module path and name and create a node for it
  1915. loadedModuleDir := filepath.Dir(path)
  1916. base := filepath.Base(path)
  1917. loadedModuleName := strings.TrimSuffix(base, filepath.Ext(base)) + ctx.outputSuffix
  1918. if loadedModuleDir == filepath.Dir(ctx.script.mkFile) {
  1919. return ":" + loadedModuleName
  1920. }
  1921. if ctx.outputDir == "" {
  1922. return fmt.Sprintf("//%s:%s", loadedModuleDir, loadedModuleName)
  1923. }
  1924. if _, err := os.Stat(filepath.Join(loadedModuleDir, loadedModuleName)); err == nil {
  1925. return fmt.Sprintf("//%s:%s", loadedModuleDir, loadedModuleName)
  1926. }
  1927. return filepath.Join(ctx.outputDir, loadedModuleDir, loadedModuleName)
  1928. }
  1929. func (ctx *parseContext) addSoongNamespace(ns string) {
  1930. if _, ok := ctx.soongNamespaces[ns]; ok {
  1931. return
  1932. }
  1933. ctx.soongNamespaces[ns] = make(map[string]bool)
  1934. }
  1935. func (ctx *parseContext) hasSoongNamespace(name string) bool {
  1936. _, ok := ctx.soongNamespaces[name]
  1937. return ok
  1938. }
  1939. func (ctx *parseContext) updateSoongNamespace(replace bool, namespaceName string, varNames []string) {
  1940. ctx.addSoongNamespace(namespaceName)
  1941. vars := ctx.soongNamespaces[namespaceName]
  1942. if replace {
  1943. vars = make(map[string]bool)
  1944. ctx.soongNamespaces[namespaceName] = vars
  1945. }
  1946. for _, v := range varNames {
  1947. vars[v] = true
  1948. }
  1949. }
  1950. func (ctx *parseContext) hasNamespaceVar(namespaceName string, varName string) bool {
  1951. vars, ok := ctx.soongNamespaces[namespaceName]
  1952. if ok {
  1953. _, ok = vars[varName]
  1954. }
  1955. return ok
  1956. }
  1957. func (ctx *parseContext) errorLocation(node mkparser.Node) ErrorLocation {
  1958. return ErrorLocation{ctx.script.mkFile, ctx.script.nodeLocator(node.Pos())}
  1959. }
  1960. func (ss *StarlarkScript) String() string {
  1961. return NewGenerateContext(ss).emit()
  1962. }
  1963. func (ss *StarlarkScript) SubConfigFiles() []string {
  1964. var subs []string
  1965. for _, src := range ss.inherited {
  1966. subs = append(subs, src.originalPath)
  1967. }
  1968. return subs
  1969. }
  1970. func (ss *StarlarkScript) HasErrors() bool {
  1971. return ss.hasErrors
  1972. }
  1973. // Convert reads and parses a makefile. If successful, parsed tree
  1974. // is returned and then can be passed to String() to get the generated
  1975. // Starlark file.
  1976. func Convert(req Request) (*StarlarkScript, error) {
  1977. reader := req.Reader
  1978. if reader == nil {
  1979. mkContents, err := ioutil.ReadFile(req.MkFile)
  1980. if err != nil {
  1981. return nil, err
  1982. }
  1983. reader = bytes.NewBuffer(mkContents)
  1984. }
  1985. parser := mkparser.NewParser(req.MkFile, reader)
  1986. nodes, errs := parser.Parse()
  1987. if len(errs) > 0 {
  1988. for _, e := range errs {
  1989. fmt.Fprintln(os.Stderr, "ERROR:", e)
  1990. }
  1991. return nil, fmt.Errorf("bad makefile %s", req.MkFile)
  1992. }
  1993. starScript := &StarlarkScript{
  1994. moduleName: moduleNameForFile(req.MkFile),
  1995. mkFile: req.MkFile,
  1996. traceCalls: req.TraceCalls,
  1997. sourceFS: req.SourceFS,
  1998. makefileFinder: req.MakefileFinder,
  1999. nodeLocator: func(pos mkparser.Pos) int { return parser.Unpack(pos).Line },
  2000. nodes: make([]starlarkNode, 0),
  2001. }
  2002. ctx := newParseContext(starScript, nodes)
  2003. ctx.outputSuffix = req.OutputSuffix
  2004. ctx.outputDir = req.OutputDir
  2005. ctx.errorLogger = req.ErrorLogger
  2006. if len(req.TracedVariables) > 0 {
  2007. ctx.tracedVariables = make(map[string]bool)
  2008. for _, v := range req.TracedVariables {
  2009. ctx.tracedVariables[v] = true
  2010. }
  2011. }
  2012. for ctx.hasNodes() && ctx.fatalError == nil {
  2013. starScript.nodes = append(starScript.nodes, ctx.handleSimpleStatement(ctx.getNode())...)
  2014. }
  2015. if ctx.fatalError != nil {
  2016. return nil, ctx.fatalError
  2017. }
  2018. return starScript, nil
  2019. }
  2020. func Launcher(mainModuleUri, inputVariablesUri, mainModuleName string) string {
  2021. var buf bytes.Buffer
  2022. fmt.Fprintf(&buf, "load(%q, %q)\n", baseUri, baseName)
  2023. fmt.Fprintf(&buf, "load(%q, input_variables_init = \"init\")\n", inputVariablesUri)
  2024. fmt.Fprintf(&buf, "load(%q, \"init\")\n", mainModuleUri)
  2025. fmt.Fprintf(&buf, "%s(%s(%q, init, input_variables_init))\n", cfnPrintVars, cfnMain, mainModuleName)
  2026. return buf.String()
  2027. }
  2028. func BoardLauncher(mainModuleUri string, inputVariablesUri string) string {
  2029. var buf bytes.Buffer
  2030. fmt.Fprintf(&buf, "load(%q, %q)\n", baseUri, baseName)
  2031. fmt.Fprintf(&buf, "load(%q, \"init\")\n", mainModuleUri)
  2032. fmt.Fprintf(&buf, "load(%q, input_variables_init = \"init\")\n", inputVariablesUri)
  2033. fmt.Fprintf(&buf, "%s(%s(init, input_variables_init))\n", cfnPrintVars, cfnBoardMain)
  2034. return buf.String()
  2035. }
  2036. func MakePath2ModuleName(mkPath string) string {
  2037. return strings.TrimSuffix(mkPath, filepath.Ext(mkPath))
  2038. }