Merge "Return starlarkNodes from the functions that parse them" am: 5a95bcac4a
Original change: https://android-review.googlesource.com/c/platform/build/soong/+/1965727 Change-Id: Idfca1a28faf2e6bacdb00c769ec8afca8f0e296a
This commit is contained in:
commit
06f61753ac
3 changed files with 104 additions and 189 deletions
258
mk2rbc/mk2rbc.go
258
mk2rbc/mk2rbc.go
|
@ -370,10 +370,6 @@ func init() {
|
|||
}
|
||||
}
|
||||
|
||||
type nodeReceiver interface {
|
||||
newNode(node starlarkNode)
|
||||
}
|
||||
|
||||
// Information about the generated Starlark script.
|
||||
type StarlarkScript struct {
|
||||
mkFile string
|
||||
|
@ -389,10 +385,6 @@ type StarlarkScript struct {
|
|||
nodeLocator func(pos mkparser.Pos) int
|
||||
}
|
||||
|
||||
func (ss *StarlarkScript) newNode(node starlarkNode) {
|
||||
ss.nodes = append(ss.nodes, node)
|
||||
}
|
||||
|
||||
// varAssignmentScope points to the last assignment for each variable
|
||||
// in the current block. It is used during the parsing to chain
|
||||
// the assignments to a variable together.
|
||||
|
@ -415,8 +407,6 @@ type parseContext struct {
|
|||
tracedVariables map[string]bool // variables to be traced in the generated script
|
||||
variables map[string]variable
|
||||
varAssignments *varAssignmentScope
|
||||
receiver nodeReceiver // receptacle for the generated starlarkNode's
|
||||
receiverStack []nodeReceiver
|
||||
outputDir string
|
||||
dependentModules map[string]*moduleInfo
|
||||
soongNamespaces map[string]map[string]bool
|
||||
|
@ -503,20 +493,6 @@ func (ctx *parseContext) popVarAssignments() {
|
|||
ctx.varAssignments = ctx.varAssignments.outer
|
||||
}
|
||||
|
||||
func (ctx *parseContext) pushReceiver(rcv nodeReceiver) {
|
||||
ctx.receiverStack = append(ctx.receiverStack, ctx.receiver)
|
||||
ctx.receiver = rcv
|
||||
}
|
||||
|
||||
func (ctx *parseContext) popReceiver() {
|
||||
last := len(ctx.receiverStack) - 1
|
||||
if last < 0 {
|
||||
panic(fmt.Errorf("popReceiver: receiver stack empty"))
|
||||
}
|
||||
ctx.receiver = ctx.receiverStack[last]
|
||||
ctx.receiverStack = ctx.receiverStack[0:last]
|
||||
}
|
||||
|
||||
func (ctx *parseContext) hasNodes() bool {
|
||||
return ctx.currentNodeIndex < len(ctx.nodes)
|
||||
}
|
||||
|
@ -537,11 +513,10 @@ func (ctx *parseContext) backNode() {
|
|||
ctx.currentNodeIndex--
|
||||
}
|
||||
|
||||
func (ctx *parseContext) handleAssignment(a *mkparser.Assignment) {
|
||||
func (ctx *parseContext) handleAssignment(a *mkparser.Assignment) []starlarkNode {
|
||||
// Handle only simple variables
|
||||
if !a.Name.Const() {
|
||||
ctx.errorf(a, "Only simple variables are handled")
|
||||
return
|
||||
return []starlarkNode{ctx.newBadNode(a, "Only simple variables are handled")}
|
||||
}
|
||||
name := a.Name.Strings[0]
|
||||
// The `override` directive
|
||||
|
@ -549,18 +524,16 @@ func (ctx *parseContext) handleAssignment(a *mkparser.Assignment) {
|
|||
// is parsed as an assignment to a variable named `override FOO`.
|
||||
// There are very few places where `override` is used, just flag it.
|
||||
if strings.HasPrefix(name, "override ") {
|
||||
ctx.errorf(a, "cannot handle override directive")
|
||||
return []starlarkNode{ctx.newBadNode(a, "cannot handle override directive")}
|
||||
}
|
||||
|
||||
// Soong configuration
|
||||
if strings.HasPrefix(name, soongNsPrefix) {
|
||||
ctx.handleSoongNsAssignment(strings.TrimPrefix(name, soongNsPrefix), a)
|
||||
return
|
||||
return ctx.handleSoongNsAssignment(strings.TrimPrefix(name, soongNsPrefix), a)
|
||||
}
|
||||
lhs := ctx.addVariable(name)
|
||||
if lhs == nil {
|
||||
ctx.errorf(a, "unknown variable %s", name)
|
||||
return
|
||||
return []starlarkNode{ctx.newBadNode(a, "unknown variable %s", name)}
|
||||
}
|
||||
_, isTraced := ctx.tracedVariables[name]
|
||||
asgn := &assignmentNode{lhs: lhs, mkValue: a.Value, isTraced: isTraced, location: ctx.errorLocation(a)}
|
||||
|
@ -568,8 +541,7 @@ func (ctx *parseContext) handleAssignment(a *mkparser.Assignment) {
|
|||
// Try to divine variable type from the RHS
|
||||
asgn.value = ctx.parseMakeString(a, a.Value)
|
||||
if xBad, ok := asgn.value.(*badExpr); ok {
|
||||
ctx.wrapBadExpr(xBad)
|
||||
return
|
||||
return []starlarkNode{&exprNode{xBad}}
|
||||
}
|
||||
inferred_type := asgn.value.typ()
|
||||
if inferred_type != starlarkTypeUnknown {
|
||||
|
@ -577,9 +549,9 @@ func (ctx *parseContext) handleAssignment(a *mkparser.Assignment) {
|
|||
}
|
||||
}
|
||||
if lhs.valueType() == starlarkTypeList {
|
||||
xConcat := ctx.buildConcatExpr(a)
|
||||
if xConcat == nil {
|
||||
return
|
||||
xConcat, xBad := ctx.buildConcatExpr(a)
|
||||
if xBad != nil {
|
||||
return []starlarkNode{&exprNode{expr: xBad}}
|
||||
}
|
||||
switch len(xConcat.items) {
|
||||
case 0:
|
||||
|
@ -592,8 +564,7 @@ func (ctx *parseContext) handleAssignment(a *mkparser.Assignment) {
|
|||
} else {
|
||||
asgn.value = ctx.parseMakeString(a, a.Value)
|
||||
if xBad, ok := asgn.value.(*badExpr); ok {
|
||||
ctx.wrapBadExpr(xBad)
|
||||
return
|
||||
return []starlarkNode{&exprNode{expr: xBad}}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -614,14 +585,13 @@ func (ctx *parseContext) handleAssignment(a *mkparser.Assignment) {
|
|||
panic(fmt.Errorf("unexpected assignment type %s", a.Type))
|
||||
}
|
||||
|
||||
ctx.receiver.newNode(asgn)
|
||||
return []starlarkNode{asgn}
|
||||
}
|
||||
|
||||
func (ctx *parseContext) handleSoongNsAssignment(name string, asgn *mkparser.Assignment) {
|
||||
func (ctx *parseContext) handleSoongNsAssignment(name string, asgn *mkparser.Assignment) []starlarkNode {
|
||||
val := ctx.parseMakeString(asgn, asgn.Value)
|
||||
if xBad, ok := val.(*badExpr); ok {
|
||||
ctx.wrapBadExpr(xBad)
|
||||
return
|
||||
return []starlarkNode{&exprNode{expr: xBad}}
|
||||
}
|
||||
|
||||
// Unfortunately, Soong namespaces can be set up by directly setting corresponding Make
|
||||
|
@ -634,17 +604,18 @@ func (ctx *parseContext) handleSoongNsAssignment(name string, asgn *mkparser.Ass
|
|||
// $(call add_soong_config_namespace,foo)
|
||||
s, ok := maybeString(val)
|
||||
if !ok {
|
||||
ctx.errorf(asgn, "cannot handle variables in SOONG_CONFIG_NAMESPACES assignment, please use add_soong_config_namespace instead")
|
||||
return
|
||||
return []starlarkNode{ctx.newBadNode(asgn, "cannot handle variables in SOONG_CONFIG_NAMESPACES assignment, please use add_soong_config_namespace instead")}
|
||||
}
|
||||
result := make([]starlarkNode, 0)
|
||||
for _, ns := range strings.Fields(s) {
|
||||
ctx.addSoongNamespace(ns)
|
||||
ctx.receiver.newNode(&exprNode{&callExpr{
|
||||
result = append(result, &exprNode{&callExpr{
|
||||
name: baseName + ".soong_config_namespace",
|
||||
args: []starlarkExpr{&globalsExpr{}, &stringLiteralExpr{ns}},
|
||||
returnType: starlarkTypeVoid,
|
||||
}})
|
||||
}
|
||||
return result
|
||||
} else {
|
||||
// Upon seeing
|
||||
// SOONG_CONFIG_x_y = v
|
||||
|
@ -664,45 +635,41 @@ func (ctx *parseContext) handleSoongNsAssignment(name string, asgn *mkparser.Ass
|
|||
continue
|
||||
}
|
||||
if namespaceName != "" {
|
||||
ctx.errorf(asgn, "ambiguous soong namespace (may be either `%s` or `%s`)", namespaceName, name[0:pos])
|
||||
return
|
||||
return []starlarkNode{ctx.newBadNode(asgn, "ambiguous soong namespace (may be either `%s` or `%s`)", namespaceName, name[0:pos])}
|
||||
}
|
||||
namespaceName = name[0:pos]
|
||||
varName = name[pos+1:]
|
||||
}
|
||||
if namespaceName == "" {
|
||||
ctx.errorf(asgn, "cannot figure out Soong namespace, please use add_soong_config_var_value macro instead")
|
||||
return
|
||||
return []starlarkNode{ctx.newBadNode(asgn, "cannot figure out Soong namespace, please use add_soong_config_var_value macro instead")}
|
||||
}
|
||||
if varName == "" {
|
||||
// Remember variables in this namespace
|
||||
s, ok := maybeString(val)
|
||||
if !ok {
|
||||
ctx.errorf(asgn, "cannot handle variables in SOONG_CONFIG_ assignment, please use add_soong_config_var_value instead")
|
||||
return
|
||||
return []starlarkNode{ctx.newBadNode(asgn, "cannot handle variables in SOONG_CONFIG_ assignment, please use add_soong_config_var_value instead")}
|
||||
}
|
||||
ctx.updateSoongNamespace(asgn.Type != "+=", namespaceName, strings.Fields(s))
|
||||
return
|
||||
return []starlarkNode{}
|
||||
}
|
||||
|
||||
// Finally, handle assignment to a namespace variable
|
||||
if !ctx.hasNamespaceVar(namespaceName, varName) {
|
||||
ctx.errorf(asgn, "no %s variable in %s namespace, please use add_soong_config_var_value instead", varName, namespaceName)
|
||||
return
|
||||
return []starlarkNode{ctx.newBadNode(asgn, "no %s variable in %s namespace, please use add_soong_config_var_value instead", varName, namespaceName)}
|
||||
}
|
||||
fname := baseName + "." + soongConfigAssign
|
||||
if asgn.Type == "+=" {
|
||||
fname = baseName + "." + soongConfigAppend
|
||||
}
|
||||
ctx.receiver.newNode(&exprNode{&callExpr{
|
||||
return []starlarkNode{&exprNode{&callExpr{
|
||||
name: fname,
|
||||
args: []starlarkExpr{&globalsExpr{}, &stringLiteralExpr{namespaceName}, &stringLiteralExpr{varName}, val},
|
||||
returnType: starlarkTypeVoid,
|
||||
}})
|
||||
}}}
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx *parseContext) buildConcatExpr(a *mkparser.Assignment) *concatExpr {
|
||||
func (ctx *parseContext) buildConcatExpr(a *mkparser.Assignment) (*concatExpr, *badExpr) {
|
||||
xConcat := &concatExpr{}
|
||||
var xItemList *listExpr
|
||||
addToItemList := func(x ...starlarkExpr) {
|
||||
|
@ -724,8 +691,7 @@ func (ctx *parseContext) buildConcatExpr(a *mkparser.Assignment) *concatExpr {
|
|||
// expressions return individual elements.
|
||||
switch x := ctx.parseMakeString(a, item).(type) {
|
||||
case *badExpr:
|
||||
ctx.wrapBadExpr(x)
|
||||
return nil
|
||||
return nil, x
|
||||
case *stringLiteralExpr:
|
||||
addToItemList(maybeConvertToStringList(x).(*listExpr).items...)
|
||||
default:
|
||||
|
@ -749,7 +715,7 @@ func (ctx *parseContext) buildConcatExpr(a *mkparser.Assignment) *concatExpr {
|
|||
if xItemList != nil {
|
||||
xConcat.items = append(xConcat.items, xItemList)
|
||||
}
|
||||
return xConcat
|
||||
return xConcat, nil
|
||||
}
|
||||
|
||||
func (ctx *parseContext) newDependentModule(path string, optional bool) *moduleInfo {
|
||||
|
@ -779,7 +745,7 @@ func (ctx *parseContext) newDependentModule(path string, optional bool) *moduleI
|
|||
}
|
||||
|
||||
func (ctx *parseContext) handleSubConfig(
|
||||
v mkparser.Node, pathExpr starlarkExpr, loadAlways bool, processModule func(inheritedModule)) {
|
||||
v mkparser.Node, pathExpr starlarkExpr, loadAlways bool, processModule func(inheritedModule) starlarkNode) []starlarkNode {
|
||||
|
||||
// In a simple case, the name of a module to inherit/include is known statically.
|
||||
if path, ok := maybeString(pathExpr); ok {
|
||||
|
@ -788,18 +754,19 @@ func (ctx *parseContext) handleSubConfig(
|
|||
moduleShouldExist := loadAlways && ctx.ifNestLevel == 0
|
||||
if strings.Contains(path, "*") {
|
||||
if paths, err := fs.Glob(ctx.script.sourceFS, path); err == nil {
|
||||
result := make([]starlarkNode, 0)
|
||||
for _, p := range paths {
|
||||
mi := ctx.newDependentModule(p, !moduleShouldExist)
|
||||
processModule(inheritedStaticModule{mi, loadAlways})
|
||||
result = append(result, processModule(inheritedStaticModule{mi, loadAlways}))
|
||||
}
|
||||
return result
|
||||
} else {
|
||||
ctx.errorf(v, "cannot glob wildcard argument")
|
||||
return []starlarkNode{ctx.newBadNode(v, "cannot glob wildcard argument")}
|
||||
}
|
||||
} else {
|
||||
mi := ctx.newDependentModule(path, !moduleShouldExist)
|
||||
processModule(inheritedStaticModule{mi, loadAlways})
|
||||
return []starlarkNode{processModule(inheritedStaticModule{mi, loadAlways})}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// If module path references variables (e.g., $(v1)/foo/$(v2)/device-config.mk), find all the paths in the
|
||||
|
@ -819,8 +786,7 @@ func (ctx *parseContext) handleSubConfig(
|
|||
var matchingPaths []string
|
||||
varPath, ok := pathExpr.(*interpolateExpr)
|
||||
if !ok {
|
||||
ctx.errorf(v, "inherit-product/include argument is too complex")
|
||||
return
|
||||
return []starlarkNode{ctx.newBadNode(v, "inherit-product/include argument is too complex")}
|
||||
}
|
||||
|
||||
pathPattern := []string{varPath.chunks[0]}
|
||||
|
@ -842,12 +808,11 @@ func (ctx *parseContext) handleSubConfig(
|
|||
// Safeguard against $(call inherit-product,$(PRODUCT_PATH))
|
||||
const maxMatchingFiles = 150
|
||||
if len(matchingPaths) > maxMatchingFiles {
|
||||
ctx.errorf(v, "there are >%d files matching the pattern, please rewrite it", maxMatchingFiles)
|
||||
return
|
||||
return []starlarkNode{ctx.newBadNode(v, "there are >%d files matching the pattern, please rewrite it", maxMatchingFiles)}
|
||||
}
|
||||
if len(matchingPaths) == 1 {
|
||||
res := inheritedStaticModule{ctx.newDependentModule(matchingPaths[0], loadAlways && ctx.ifNestLevel == 0), loadAlways}
|
||||
processModule(res)
|
||||
return []starlarkNode{processModule(res)}
|
||||
} else {
|
||||
needsWarning := pathPattern[0] == "" && len(ctx.includeTops) == 0
|
||||
res := inheritedDynamicModule{*varPath, []*moduleInfo{}, loadAlways, ctx.errorLocation(v), needsWarning}
|
||||
|
@ -857,7 +822,7 @@ func (ctx *parseContext) handleSubConfig(
|
|||
// by always loading the dynamic files as optional.
|
||||
res.candidateModules = append(res.candidateModules, ctx.newDependentModule(p, true))
|
||||
}
|
||||
processModule(res)
|
||||
return []starlarkNode{processModule(res)}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -885,25 +850,25 @@ func (ctx *parseContext) findMatchingPaths(pattern []string) []string {
|
|||
return res
|
||||
}
|
||||
|
||||
func (ctx *parseContext) handleInheritModule(v mkparser.Node, args *mkparser.MakeString, loadAlways bool) {
|
||||
func (ctx *parseContext) handleInheritModule(v mkparser.Node, args *mkparser.MakeString, loadAlways bool) []starlarkNode {
|
||||
args.TrimLeftSpaces()
|
||||
args.TrimRightSpaces()
|
||||
pathExpr := ctx.parseMakeString(v, args)
|
||||
if _, ok := pathExpr.(*badExpr); ok {
|
||||
ctx.errorf(v, "Unable to parse argument to inherit")
|
||||
return []starlarkNode{ctx.newBadNode(v, "Unable to parse argument to inherit")}
|
||||
}
|
||||
ctx.handleSubConfig(v, pathExpr, loadAlways, func(im inheritedModule) {
|
||||
ctx.receiver.newNode(&inheritNode{im, loadAlways})
|
||||
return ctx.handleSubConfig(v, pathExpr, loadAlways, func(im inheritedModule) starlarkNode {
|
||||
return &inheritNode{im, loadAlways}
|
||||
})
|
||||
}
|
||||
|
||||
func (ctx *parseContext) handleInclude(v mkparser.Node, pathExpr starlarkExpr, loadAlways bool) {
|
||||
ctx.handleSubConfig(v, pathExpr, loadAlways, func(im inheritedModule) {
|
||||
ctx.receiver.newNode(&includeNode{im, loadAlways})
|
||||
func (ctx *parseContext) handleInclude(v mkparser.Node, pathExpr starlarkExpr, loadAlways bool) []starlarkNode {
|
||||
return ctx.handleSubConfig(v, pathExpr, loadAlways, func(im inheritedModule) starlarkNode {
|
||||
return &includeNode{im, loadAlways}
|
||||
})
|
||||
}
|
||||
|
||||
func (ctx *parseContext) handleVariable(v *mkparser.Variable) {
|
||||
func (ctx *parseContext) handleVariable(v *mkparser.Variable) []starlarkNode {
|
||||
// Handle:
|
||||
// $(call inherit-product,...)
|
||||
// $(call inherit-product-if-exists,...)
|
||||
|
@ -918,67 +883,57 @@ func (ctx *parseContext) handleVariable(v *mkparser.Variable) {
|
|||
if strings.HasPrefix(v.Name.Dump(), "call inherit-product,") {
|
||||
args := v.Name.Clone()
|
||||
args.ReplaceLiteral("call inherit-product,", "")
|
||||
ctx.handleInheritModule(v, args, true)
|
||||
return
|
||||
return ctx.handleInheritModule(v, args, true)
|
||||
}
|
||||
if strings.HasPrefix(v.Name.Dump(), "call inherit-product-if-exists,") {
|
||||
args := v.Name.Clone()
|
||||
args.ReplaceLiteral("call inherit-product-if-exists,", "")
|
||||
ctx.handleInheritModule(v, args, false)
|
||||
return
|
||||
}
|
||||
expr := ctx.parseReference(v, v.Name)
|
||||
switch x := expr.(type) {
|
||||
case *callExpr:
|
||||
ctx.receiver.newNode(&exprNode{expr})
|
||||
case *badExpr:
|
||||
ctx.wrapBadExpr(x)
|
||||
default:
|
||||
ctx.errorf(v, "cannot handle %s", v.Dump())
|
||||
return ctx.handleInheritModule(v, args, false)
|
||||
}
|
||||
return []starlarkNode{&exprNode{expr: ctx.parseReference(v, v.Name)}}
|
||||
}
|
||||
|
||||
func (ctx *parseContext) handleDefine(directive *mkparser.Directive) {
|
||||
func (ctx *parseContext) maybeHandleDefine(directive *mkparser.Directive) starlarkNode {
|
||||
macro_name := strings.Fields(directive.Args.Strings[0])[0]
|
||||
// Ignore the macros that we handle
|
||||
_, ignored := ignoredDefines[macro_name]
|
||||
_, known := knownFunctions[macro_name]
|
||||
if !ignored && !known {
|
||||
ctx.errorf(directive, "define is not supported: %s", macro_name)
|
||||
return ctx.newBadNode(directive, "define is not supported: %s", macro_name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctx *parseContext) handleIfBlock(ifDirective *mkparser.Directive) {
|
||||
ssSwitch := &switchNode{}
|
||||
ctx.pushReceiver(ssSwitch)
|
||||
for ctx.processBranch(ifDirective); ctx.hasNodes() && ctx.fatalError == nil; {
|
||||
func (ctx *parseContext) handleIfBlock(ifDirective *mkparser.Directive) starlarkNode {
|
||||
ssSwitch := &switchNode{
|
||||
ssCases: []*switchCase{ctx.processBranch(ifDirective)},
|
||||
}
|
||||
for ctx.hasNodes() && ctx.fatalError == nil {
|
||||
node := ctx.getNode()
|
||||
switch x := node.(type) {
|
||||
case *mkparser.Directive:
|
||||
switch x.Name {
|
||||
case "else", "elifdef", "elifndef", "elifeq", "elifneq":
|
||||
ctx.processBranch(x)
|
||||
ssSwitch.ssCases = append(ssSwitch.ssCases, ctx.processBranch(x))
|
||||
case "endif":
|
||||
ctx.popReceiver()
|
||||
ctx.receiver.newNode(ssSwitch)
|
||||
return
|
||||
return ssSwitch
|
||||
default:
|
||||
ctx.errorf(node, "unexpected directive %s", x.Name)
|
||||
return ctx.newBadNode(node, "unexpected directive %s", x.Name)
|
||||
}
|
||||
default:
|
||||
ctx.errorf(ifDirective, "unexpected statement")
|
||||
return ctx.newBadNode(ifDirective, "unexpected statement")
|
||||
}
|
||||
}
|
||||
if ctx.fatalError == nil {
|
||||
ctx.fatalError = fmt.Errorf("no matching endif for %s", ifDirective.Dump())
|
||||
}
|
||||
ctx.popReceiver()
|
||||
return ctx.newBadNode(ifDirective, "no matching endif for %s", ifDirective.Dump())
|
||||
}
|
||||
|
||||
// processBranch processes a single branch (if/elseif/else) until the next directive
|
||||
// on the same level.
|
||||
func (ctx *parseContext) processBranch(check *mkparser.Directive) {
|
||||
block := switchCase{gate: ctx.parseCondition(check)}
|
||||
func (ctx *parseContext) processBranch(check *mkparser.Directive) *switchCase {
|
||||
block := &switchCase{gate: ctx.parseCondition(check)}
|
||||
defer func() {
|
||||
ctx.popVarAssignments()
|
||||
ctx.ifNestLevel--
|
||||
|
@ -987,29 +942,26 @@ func (ctx *parseContext) processBranch(check *mkparser.Directive) {
|
|||
ctx.pushVarAssignments()
|
||||
ctx.ifNestLevel++
|
||||
|
||||
ctx.pushReceiver(&block)
|
||||
for ctx.hasNodes() {
|
||||
node := ctx.getNode()
|
||||
if d, ok := node.(*mkparser.Directive); ok {
|
||||
switch d.Name {
|
||||
case "else", "elifdef", "elifndef", "elifeq", "elifneq", "endif":
|
||||
ctx.popReceiver()
|
||||
ctx.receiver.newNode(&block)
|
||||
ctx.backNode()
|
||||
return
|
||||
return block
|
||||
}
|
||||
}
|
||||
ctx.handleSimpleStatement(node)
|
||||
block.nodes = append(block.nodes, ctx.handleSimpleStatement(node)...)
|
||||
}
|
||||
ctx.fatalError = fmt.Errorf("no matching endif for %s", check.Dump())
|
||||
ctx.popReceiver()
|
||||
return block
|
||||
}
|
||||
|
||||
func (ctx *parseContext) parseCondition(check *mkparser.Directive) starlarkNode {
|
||||
switch check.Name {
|
||||
case "ifdef", "ifndef", "elifdef", "elifndef":
|
||||
if !check.Args.Const() {
|
||||
return &exprNode{expr: ctx.newBadExpr(check, "ifdef variable ref too complex: %s", check.Args.Dump())}
|
||||
return ctx.newBadNode(check, "ifdef variable ref too complex: %s", check.Args.Dump())
|
||||
}
|
||||
v := NewVariableRefExpr(ctx.addVariable(check.Args.Strings[0]), false)
|
||||
if strings.HasSuffix(check.Name, "ndef") {
|
||||
|
@ -1032,12 +984,16 @@ func (ctx *parseContext) parseCondition(check *mkparser.Directive) starlarkNode
|
|||
}
|
||||
|
||||
func (ctx *parseContext) newBadExpr(node mkparser.Node, text string, args ...interface{}) starlarkExpr {
|
||||
message := fmt.Sprintf(text, args...)
|
||||
if ctx.errorLogger != nil {
|
||||
ctx.errorLogger.NewError(ctx.errorLocation(node), node, text, args...)
|
||||
}
|
||||
ctx.script.hasErrors = true
|
||||
return &badExpr{errorLocation: ctx.errorLocation(node), message: message}
|
||||
return &badExpr{errorLocation: ctx.errorLocation(node), message: fmt.Sprintf(text, args...)}
|
||||
}
|
||||
|
||||
// records that the given node failed to be converted and includes an explanatory message
|
||||
func (ctx *parseContext) newBadNode(failedNode mkparser.Node, message string, args ...interface{}) starlarkNode {
|
||||
return &exprNode{ctx.newBadExpr(failedNode, message, args...)}
|
||||
}
|
||||
|
||||
func (ctx *parseContext) parseCompare(cond *mkparser.Directive) starlarkExpr {
|
||||
|
@ -1730,29 +1686,34 @@ func (ctx *parseContext) parseMakeString(node mkparser.Node, mk *mkparser.MakeSt
|
|||
// Handles the statements whose treatment is the same in all contexts: comment,
|
||||
// assignment, variable (which is a macro call in reality) and all constructs that
|
||||
// do not handle in any context ('define directive and any unrecognized stuff).
|
||||
func (ctx *parseContext) handleSimpleStatement(node mkparser.Node) {
|
||||
func (ctx *parseContext) handleSimpleStatement(node mkparser.Node) []starlarkNode {
|
||||
var result []starlarkNode
|
||||
switch x := node.(type) {
|
||||
case *mkparser.Comment:
|
||||
if !ctx.maybeHandleAnnotation(x) {
|
||||
ctx.insertComment("#" + x.Comment)
|
||||
if n, handled := ctx.maybeHandleAnnotation(x); handled && n != nil {
|
||||
result = []starlarkNode{n}
|
||||
} else if !handled {
|
||||
result = []starlarkNode{&commentNode{strings.TrimSpace("#" + x.Comment)}}
|
||||
}
|
||||
case *mkparser.Assignment:
|
||||
ctx.handleAssignment(x)
|
||||
result = ctx.handleAssignment(x)
|
||||
case *mkparser.Variable:
|
||||
ctx.handleVariable(x)
|
||||
result = ctx.handleVariable(x)
|
||||
case *mkparser.Directive:
|
||||
switch x.Name {
|
||||
case "define":
|
||||
ctx.handleDefine(x)
|
||||
if res := ctx.maybeHandleDefine(x); res != nil {
|
||||
result = []starlarkNode{res}
|
||||
}
|
||||
case "include", "-include":
|
||||
ctx.handleInclude(node, ctx.parseMakeString(node, x.Args), x.Name[0] != '-')
|
||||
result = ctx.handleInclude(node, ctx.parseMakeString(node, x.Args), x.Name[0] != '-')
|
||||
case "ifeq", "ifneq", "ifdef", "ifndef":
|
||||
ctx.handleIfBlock(x)
|
||||
result = []starlarkNode{ctx.handleIfBlock(x)}
|
||||
default:
|
||||
ctx.errorf(x, "unexpected directive %s", x.Name)
|
||||
result = []starlarkNode{ctx.newBadNode(x, "unexpected directive %s", x.Name)}
|
||||
}
|
||||
default:
|
||||
ctx.errorf(x, "unsupported line %s", strings.ReplaceAll(x.Dump(), "\n", "\n#"))
|
||||
result = []starlarkNode{ctx.newBadNode(x, "unsupported line %s", strings.ReplaceAll(x.Dump(), "\n", "\n#"))}
|
||||
}
|
||||
|
||||
// Clear the includeTops after each non-comment statement
|
||||
|
@ -1761,12 +1722,17 @@ func (ctx *parseContext) handleSimpleStatement(node mkparser.Node) {
|
|||
if _, wasComment := node.(*mkparser.Comment); !wasComment && len(ctx.includeTops) > 0 {
|
||||
ctx.includeTops = []string{}
|
||||
}
|
||||
|
||||
if result == nil {
|
||||
result = []starlarkNode{}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Processes annotation. An annotation is a comment that starts with #RBC# and provides
|
||||
// a conversion hint -- say, where to look for the dynamically calculated inherit/include
|
||||
// paths. Returns true if the comment was a successfully-handled annotation.
|
||||
func (ctx *parseContext) maybeHandleAnnotation(cnode *mkparser.Comment) bool {
|
||||
func (ctx *parseContext) maybeHandleAnnotation(cnode *mkparser.Comment) (starlarkNode, bool) {
|
||||
maybeTrim := func(s, prefix string) (string, bool) {
|
||||
if strings.HasPrefix(s, prefix) {
|
||||
return strings.TrimSpace(strings.TrimPrefix(s, prefix)), true
|
||||
|
@ -1775,44 +1741,20 @@ func (ctx *parseContext) maybeHandleAnnotation(cnode *mkparser.Comment) bool {
|
|||
}
|
||||
annotation, ok := maybeTrim(cnode.Comment, annotationCommentPrefix)
|
||||
if !ok {
|
||||
return false
|
||||
return nil, false
|
||||
}
|
||||
if p, ok := maybeTrim(annotation, "include_top"); ok {
|
||||
// Don't allow duplicate include tops, because then we will generate
|
||||
// invalid starlark code. (duplicate keys in the _entry dictionary)
|
||||
for _, top := range ctx.includeTops {
|
||||
if top == p {
|
||||
return true
|
||||
return nil, true
|
||||
}
|
||||
}
|
||||
ctx.includeTops = append(ctx.includeTops, p)
|
||||
return true
|
||||
return nil, true
|
||||
}
|
||||
ctx.errorf(cnode, "unsupported annotation %s", cnode.Comment)
|
||||
return true
|
||||
}
|
||||
|
||||
func (ctx *parseContext) insertComment(s string) {
|
||||
ctx.receiver.newNode(&commentNode{strings.TrimSpace(s)})
|
||||
}
|
||||
|
||||
func (ctx *parseContext) carryAsComment(failedNode mkparser.Node) {
|
||||
for _, line := range strings.Split(failedNode.Dump(), "\n") {
|
||||
ctx.insertComment("# " + line)
|
||||
}
|
||||
}
|
||||
|
||||
// records that the given node failed to be converted and includes an explanatory message
|
||||
func (ctx *parseContext) errorf(failedNode mkparser.Node, message string, args ...interface{}) {
|
||||
if ctx.errorLogger != nil {
|
||||
ctx.errorLogger.NewError(ctx.errorLocation(failedNode), failedNode, message, args...)
|
||||
}
|
||||
ctx.receiver.newNode(&exprNode{ctx.newBadExpr(failedNode, message, args...)})
|
||||
ctx.script.hasErrors = true
|
||||
}
|
||||
|
||||
func (ctx *parseContext) wrapBadExpr(xBad *badExpr) {
|
||||
ctx.receiver.newNode(&exprNode{xBad})
|
||||
return ctx.newBadNode(cnode, "unsupported annotation %s", cnode.Comment), true
|
||||
}
|
||||
|
||||
func (ctx *parseContext) loadedModulePath(path string) string {
|
||||
|
@ -1927,6 +1869,7 @@ func Convert(req Request) (*StarlarkScript, error) {
|
|||
sourceFS: req.SourceFS,
|
||||
makefileFinder: req.MakefileFinder,
|
||||
nodeLocator: func(pos mkparser.Pos) int { return parser.Unpack(pos).Line },
|
||||
nodes: make([]starlarkNode, 0),
|
||||
}
|
||||
ctx := newParseContext(starScript, nodes)
|
||||
ctx.outputSuffix = req.OutputSuffix
|
||||
|
@ -1938,9 +1881,8 @@ func Convert(req Request) (*StarlarkScript, error) {
|
|||
ctx.tracedVariables[v] = true
|
||||
}
|
||||
}
|
||||
ctx.pushReceiver(starScript)
|
||||
for ctx.hasNodes() && ctx.fatalError == nil {
|
||||
ctx.handleSimpleStatement(ctx.getNode())
|
||||
starScript.nodes = append(starScript.nodes, ctx.handleSimpleStatement(ctx.getNode())...)
|
||||
}
|
||||
if ctx.fatalError != nil {
|
||||
return nil, ctx.fatalError
|
||||
|
|
|
@ -1153,7 +1153,6 @@ override FOO:=`,
|
|||
def init(g, handle):
|
||||
cfg = rblf.cfg(handle)
|
||||
rblf.mk2rbc_error("product.mk:2", "cannot handle override directive")
|
||||
g["override FOO"] = ""
|
||||
`,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -255,29 +255,17 @@ type switchCase struct {
|
|||
nodes []starlarkNode
|
||||
}
|
||||
|
||||
func (cb *switchCase) newNode(node starlarkNode) {
|
||||
cb.nodes = append(cb.nodes, node)
|
||||
}
|
||||
|
||||
func (cb *switchCase) emit(gctx *generationContext) {
|
||||
cb.gate.emit(gctx)
|
||||
gctx.indentLevel++
|
||||
hasStatements := false
|
||||
emitNode := func(node starlarkNode) {
|
||||
for _, node := range cb.nodes {
|
||||
if _, ok := node.(*commentNode); !ok {
|
||||
hasStatements = true
|
||||
}
|
||||
node.emit(gctx)
|
||||
}
|
||||
if len(cb.nodes) > 0 {
|
||||
emitNode(cb.nodes[0])
|
||||
for _, node := range cb.nodes[1:] {
|
||||
emitNode(node)
|
||||
}
|
||||
if !hasStatements {
|
||||
gctx.emitPass()
|
||||
}
|
||||
} else {
|
||||
if !hasStatements {
|
||||
gctx.emitPass()
|
||||
}
|
||||
gctx.indentLevel--
|
||||
|
@ -288,22 +276,8 @@ type switchNode struct {
|
|||
ssCases []*switchCase
|
||||
}
|
||||
|
||||
func (ssw *switchNode) newNode(node starlarkNode) {
|
||||
switch br := node.(type) {
|
||||
case *switchCase:
|
||||
ssw.ssCases = append(ssw.ssCases, br)
|
||||
default:
|
||||
panic(fmt.Errorf("expected switchCase node, got %t", br))
|
||||
}
|
||||
}
|
||||
|
||||
func (ssw *switchNode) emit(gctx *generationContext) {
|
||||
if len(ssw.ssCases) == 0 {
|
||||
gctx.emitPass()
|
||||
} else {
|
||||
ssw.ssCases[0].emit(gctx)
|
||||
for _, ssCase := range ssw.ssCases[1:] {
|
||||
ssCase.emit(gctx)
|
||||
}
|
||||
for _, ssCase := range ssw.ssCases {
|
||||
ssCase.emit(gctx)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue