Return starlarkNodes from the functions that parse them
Currently, mk2rbc is structured around having a global "receiver" object that accepts all starlarkNodes. As soon as they are parsed they are added to the receiver. Returning the parsed nodes to the calling function is more flexible, as it allows the calling function to restructure them as necessary. This is the first step to supporting complicated statements involving $(eval), such as `$(foreach v,$(MY_LIST),$(eval MY_LIST_2 += $(v)))` Test: go test Change-Id: Ia194123cf090d2b9559a25b975ccbc5749357cc0
This commit is contained in:
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)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user