Merge "Allow generic if statements"
This commit is contained in:
@@ -197,6 +197,51 @@ func (v *variableRefExpr) emitListVarCopy(gctx *generationContext) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type toStringExpr struct {
|
||||||
|
expr starlarkExpr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *toStringExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
|
||||||
|
if x, same := s.expr.eval(valueMap); same {
|
||||||
|
res = s
|
||||||
|
} else {
|
||||||
|
res = &toStringExpr{expr: x}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *toStringExpr) emit(ctx *generationContext) {
|
||||||
|
switch s.expr.typ() {
|
||||||
|
case starlarkTypeString, starlarkTypeUnknown:
|
||||||
|
// Assume unknown types are strings already.
|
||||||
|
s.expr.emit(ctx)
|
||||||
|
case starlarkTypeList:
|
||||||
|
ctx.write(`" ".join(`)
|
||||||
|
s.expr.emit(ctx)
|
||||||
|
ctx.write(")")
|
||||||
|
case starlarkTypeInt:
|
||||||
|
ctx.write(`("%d" % (`)
|
||||||
|
s.expr.emit(ctx)
|
||||||
|
ctx.write("))")
|
||||||
|
case starlarkTypeBool:
|
||||||
|
ctx.write("((")
|
||||||
|
s.expr.emit(ctx)
|
||||||
|
ctx.write(`) ? "true" : "")`)
|
||||||
|
case starlarkTypeVoid:
|
||||||
|
ctx.write(`""`)
|
||||||
|
default:
|
||||||
|
panic("Unknown starlark type!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *toStringExpr) typ() starlarkType {
|
||||||
|
return starlarkTypeString
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *toStringExpr) emitListVarCopy(gctx *generationContext) {
|
||||||
|
s.emit(gctx)
|
||||||
|
}
|
||||||
|
|
||||||
type notExpr struct {
|
type notExpr struct {
|
||||||
expr starlarkExpr
|
expr starlarkExpr
|
||||||
}
|
}
|
||||||
@@ -255,6 +300,12 @@ func (eq *eqExpr) emit(gctx *generationContext) {
|
|||||||
return
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if eq.left.typ() != eq.right.typ() {
|
||||||
|
eq.left = &toStringExpr{expr: eq.left}
|
||||||
|
eq.right = &toStringExpr{expr: eq.right}
|
||||||
|
}
|
||||||
|
|
||||||
// General case
|
// General case
|
||||||
eq.left.emit(gctx)
|
eq.left.emit(gctx)
|
||||||
if eq.isEq {
|
if eq.isEq {
|
||||||
|
135
mk2rbc/mk2rbc.go
135
mk2rbc/mk2rbc.go
@@ -1044,48 +1044,54 @@ func (ctx *parseContext) parseCompare(cond *mkparser.Directive) starlarkExpr {
|
|||||||
args[1].TrimLeftSpaces()
|
args[1].TrimLeftSpaces()
|
||||||
|
|
||||||
isEq := !strings.HasSuffix(cond.Name, "neq")
|
isEq := !strings.HasSuffix(cond.Name, "neq")
|
||||||
switch xLeft := ctx.parseMakeString(cond, args[0]).(type) {
|
xLeft := ctx.parseMakeString(cond, args[0])
|
||||||
case *stringLiteralExpr, *variableRefExpr:
|
xRight := ctx.parseMakeString(cond, args[1])
|
||||||
switch xRight := ctx.parseMakeString(cond, args[1]).(type) {
|
if bad, ok := xLeft.(*badExpr); ok {
|
||||||
case *stringLiteralExpr, *variableRefExpr:
|
return bad
|
||||||
|
}
|
||||||
|
if bad, ok := xRight.(*badExpr); ok {
|
||||||
|
return bad
|
||||||
|
}
|
||||||
|
|
||||||
|
if expr, ok := ctx.parseCompareSpecialCases(cond, xLeft, xRight); ok {
|
||||||
|
return expr
|
||||||
|
}
|
||||||
|
|
||||||
return &eqExpr{left: xLeft, right: xRight, isEq: isEq}
|
return &eqExpr{left: xLeft, right: xRight, isEq: isEq}
|
||||||
case *badExpr:
|
}
|
||||||
return xRight
|
|
||||||
default:
|
// Given an if statement's directive and the left/right starlarkExprs,
|
||||||
expr, ok := ctx.parseCheckFunctionCallResult(cond, xLeft, args[1])
|
// check if the starlarkExprs are one of a few hardcoded special cases
|
||||||
|
// that can be converted to a simpler equalify expression than simply comparing
|
||||||
|
// the two.
|
||||||
|
func (ctx *parseContext) parseCompareSpecialCases(directive *mkparser.Directive, left starlarkExpr,
|
||||||
|
right starlarkExpr) (starlarkExpr, bool) {
|
||||||
|
isEq := !strings.HasSuffix(directive.Name, "neq")
|
||||||
|
|
||||||
|
// All the special cases require a call on one side and a
|
||||||
|
// string literal/variable on the other. Turn the left/right variables into
|
||||||
|
// call/value variables, and return false if that's not possible.
|
||||||
|
var value starlarkExpr = nil
|
||||||
|
call, ok := left.(*callExpr)
|
||||||
if ok {
|
if ok {
|
||||||
return expr
|
switch right.(type) {
|
||||||
}
|
|
||||||
return ctx.newBadExpr(cond, "right operand is too complex: %s", args[1].Dump())
|
|
||||||
}
|
|
||||||
case *badExpr:
|
|
||||||
return xLeft
|
|
||||||
default:
|
|
||||||
switch xRight := ctx.parseMakeString(cond, args[1]).(type) {
|
|
||||||
case *stringLiteralExpr, *variableRefExpr:
|
case *stringLiteralExpr, *variableRefExpr:
|
||||||
expr, ok := ctx.parseCheckFunctionCallResult(cond, xRight, args[0])
|
value = right
|
||||||
if ok {
|
|
||||||
return expr
|
|
||||||
}
|
|
||||||
return ctx.newBadExpr(cond, "left operand is too complex: %s", args[0].Dump())
|
|
||||||
case *badExpr:
|
|
||||||
return xRight
|
|
||||||
default:
|
|
||||||
return ctx.newBadExpr(cond, "operands are too complex: (%s,%s)", args[0].Dump(), args[1].Dump())
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
call, _ = right.(*callExpr)
|
||||||
|
switch left.(type) {
|
||||||
|
case *stringLiteralExpr, *variableRefExpr:
|
||||||
|
value = left
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *parseContext) parseCheckFunctionCallResult(directive *mkparser.Directive, xValue starlarkExpr,
|
if call == nil || value == nil {
|
||||||
varArg *mkparser.MakeString) (starlarkExpr, bool) {
|
|
||||||
mkSingleVar, ok := varArg.SingleVariable()
|
|
||||||
if !ok {
|
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
expr := ctx.parseReference(directive, mkSingleVar)
|
|
||||||
negate := strings.HasSuffix(directive.Name, "neq")
|
|
||||||
checkIsSomethingFunction := func(xCall *callExpr) starlarkExpr {
|
checkIsSomethingFunction := func(xCall *callExpr) starlarkExpr {
|
||||||
s, ok := maybeString(xValue)
|
s, ok := maybeString(value)
|
||||||
if !ok || s != "true" {
|
if !ok || s != "true" {
|
||||||
return ctx.newBadExpr(directive,
|
return ctx.newBadExpr(directive,
|
||||||
fmt.Sprintf("the result of %s can be compared only to 'true'", xCall.name))
|
fmt.Sprintf("the result of %s can be compared only to 'true'", xCall.name))
|
||||||
@@ -1095,98 +1101,91 @@ func (ctx *parseContext) parseCheckFunctionCallResult(directive *mkparser.Direct
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
switch x := expr.(type) {
|
|
||||||
case *callExpr:
|
switch call.name {
|
||||||
switch x.name {
|
|
||||||
case "filter":
|
case "filter":
|
||||||
return ctx.parseCompareFilterFuncResult(directive, x, xValue, !negate), true
|
return ctx.parseCompareFilterFuncResult(directive, call, value, isEq), true
|
||||||
case "filter-out":
|
case "filter-out":
|
||||||
return ctx.parseCompareFilterFuncResult(directive, x, xValue, negate), true
|
return ctx.parseCompareFilterFuncResult(directive, call, value, !isEq), true
|
||||||
case "wildcard":
|
case "wildcard":
|
||||||
return ctx.parseCompareWildcardFuncResult(directive, x, xValue, negate), true
|
return ctx.parseCompareWildcardFuncResult(directive, call, value, !isEq), true
|
||||||
case "findstring":
|
case "findstring":
|
||||||
return ctx.parseCheckFindstringFuncResult(directive, x, xValue, negate), true
|
return ctx.parseCheckFindstringFuncResult(directive, call, value, !isEq), true
|
||||||
case "strip":
|
case "strip":
|
||||||
return ctx.parseCompareStripFuncResult(directive, x, xValue, negate), true
|
return ctx.parseCompareStripFuncResult(directive, call, value, !isEq), true
|
||||||
case "is-board-platform":
|
case "is-board-platform":
|
||||||
if xBad := checkIsSomethingFunction(x); xBad != nil {
|
if xBad := checkIsSomethingFunction(call); xBad != nil {
|
||||||
return xBad, true
|
return xBad, true
|
||||||
}
|
}
|
||||||
return &eqExpr{
|
return &eqExpr{
|
||||||
left: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
|
left: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
|
||||||
right: x.args[0],
|
right: call.args[0],
|
||||||
isEq: !negate,
|
isEq: isEq,
|
||||||
}, true
|
}, true
|
||||||
case "is-board-platform-in-list":
|
case "is-board-platform-in-list":
|
||||||
if xBad := checkIsSomethingFunction(x); xBad != nil {
|
if xBad := checkIsSomethingFunction(call); xBad != nil {
|
||||||
return xBad, true
|
return xBad, true
|
||||||
}
|
}
|
||||||
return &inExpr{
|
return &inExpr{
|
||||||
expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
|
expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
|
||||||
list: maybeConvertToStringList(x.args[0]),
|
list: maybeConvertToStringList(call.args[0]),
|
||||||
isNot: negate,
|
isNot: !isEq,
|
||||||
}, true
|
}, true
|
||||||
case "is-product-in-list":
|
case "is-product-in-list":
|
||||||
if xBad := checkIsSomethingFunction(x); xBad != nil {
|
if xBad := checkIsSomethingFunction(call); xBad != nil {
|
||||||
return xBad, true
|
return xBad, true
|
||||||
}
|
}
|
||||||
return &inExpr{
|
return &inExpr{
|
||||||
expr: &variableRefExpr{ctx.addVariable("TARGET_PRODUCT"), true},
|
expr: &variableRefExpr{ctx.addVariable("TARGET_PRODUCT"), true},
|
||||||
list: maybeConvertToStringList(x.args[0]),
|
list: maybeConvertToStringList(call.args[0]),
|
||||||
isNot: negate,
|
isNot: !isEq,
|
||||||
}, true
|
}, true
|
||||||
case "is-vendor-board-platform":
|
case "is-vendor-board-platform":
|
||||||
if xBad := checkIsSomethingFunction(x); xBad != nil {
|
if xBad := checkIsSomethingFunction(call); xBad != nil {
|
||||||
return xBad, true
|
return xBad, true
|
||||||
}
|
}
|
||||||
s, ok := maybeString(x.args[0])
|
s, ok := maybeString(call.args[0])
|
||||||
if !ok {
|
if !ok {
|
||||||
return ctx.newBadExpr(directive, "cannot handle non-constant argument to is-vendor-board-platform"), true
|
return ctx.newBadExpr(directive, "cannot handle non-constant argument to is-vendor-board-platform"), true
|
||||||
}
|
}
|
||||||
return &inExpr{
|
return &inExpr{
|
||||||
expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
|
expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
|
||||||
list: &variableRefExpr{ctx.addVariable(s + "_BOARD_PLATFORMS"), true},
|
list: &variableRefExpr{ctx.addVariable(s + "_BOARD_PLATFORMS"), true},
|
||||||
isNot: negate,
|
isNot: !isEq,
|
||||||
}, true
|
}, true
|
||||||
|
|
||||||
case "is-board-platform2", "is-board-platform-in-list2":
|
case "is-board-platform2", "is-board-platform-in-list2":
|
||||||
if s, ok := maybeString(xValue); !ok || s != "" {
|
if s, ok := maybeString(value); !ok || s != "" {
|
||||||
return ctx.newBadExpr(directive,
|
return ctx.newBadExpr(directive,
|
||||||
fmt.Sprintf("the result of %s can be compared only to empty", x.name)), true
|
fmt.Sprintf("the result of %s can be compared only to empty", call.name)), true
|
||||||
}
|
}
|
||||||
if len(x.args) != 1 {
|
if len(call.args) != 1 {
|
||||||
return ctx.newBadExpr(directive, "%s requires an argument", x.name), true
|
return ctx.newBadExpr(directive, "%s requires an argument", call.name), true
|
||||||
}
|
}
|
||||||
cc := &callExpr{
|
cc := &callExpr{
|
||||||
name: x.name,
|
name: call.name,
|
||||||
args: []starlarkExpr{x.args[0]},
|
args: []starlarkExpr{call.args[0]},
|
||||||
returnType: starlarkTypeBool,
|
returnType: starlarkTypeBool,
|
||||||
}
|
}
|
||||||
if !negate {
|
if isEq {
|
||||||
return ¬Expr{cc}, true
|
return ¬Expr{cc}, true
|
||||||
}
|
}
|
||||||
return cc, true
|
return cc, true
|
||||||
case "is-vendor-board-qcom":
|
case "is-vendor-board-qcom":
|
||||||
if s, ok := maybeString(xValue); !ok || s != "" {
|
if s, ok := maybeString(value); !ok || s != "" {
|
||||||
return ctx.newBadExpr(directive,
|
return ctx.newBadExpr(directive,
|
||||||
fmt.Sprintf("the result of %s can be compared only to empty", x.name)), true
|
fmt.Sprintf("the result of %s can be compared only to empty", call.name)), true
|
||||||
}
|
}
|
||||||
// if the expression is ifneq (,$(call is-vendor-board-platform,...)), negate==true,
|
// if the expression is ifneq (,$(call is-vendor-board-platform,...)), negate==true,
|
||||||
// so we should set inExpr.isNot to false
|
// so we should set inExpr.isNot to false
|
||||||
return &inExpr{
|
return &inExpr{
|
||||||
expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
|
expr: &variableRefExpr{ctx.addVariable("TARGET_BOARD_PLATFORM"), false},
|
||||||
list: &variableRefExpr{ctx.addVariable("QCOM_BOARD_PLATFORMS"), true},
|
list: &variableRefExpr{ctx.addVariable("QCOM_BOARD_PLATFORMS"), true},
|
||||||
isNot: !negate,
|
isNot: isEq,
|
||||||
}, true
|
}, true
|
||||||
default:
|
|
||||||
return ctx.newBadExpr(directive, "Unknown function in ifeq: %s", x.name), true
|
|
||||||
}
|
}
|
||||||
case *badExpr:
|
|
||||||
return x, true
|
|
||||||
default:
|
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func (ctx *parseContext) parseCompareFilterFuncResult(cond *mkparser.Directive,
|
func (ctx *parseContext) parseCompareFilterFuncResult(cond *mkparser.Directive,
|
||||||
filterFuncCall *callExpr, xValue starlarkExpr, negate bool) starlarkExpr {
|
filterFuncCall *callExpr, xValue starlarkExpr, negate bool) starlarkExpr {
|
||||||
|
@@ -350,6 +350,21 @@ def init(g, handle):
|
|||||||
cfg["PRODUCT_MODEL"] = "pix21"
|
cfg["PRODUCT_MODEL"] = "pix21"
|
||||||
if "aosp_x86" != g["TARGET_PRODUCT"]:
|
if "aosp_x86" != g["TARGET_PRODUCT"]:
|
||||||
cfg["PRODUCT_MODEL"] = "pix3"
|
cfg["PRODUCT_MODEL"] = "pix3"
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "ifeq with soong_config_get",
|
||||||
|
mkname: "product.mk",
|
||||||
|
in: `
|
||||||
|
ifeq (true,$(call soong_config_get,art_module,source_build))
|
||||||
|
endif
|
||||||
|
`,
|
||||||
|
expected: `load("//build/make/core:product_config.rbc", "rblf")
|
||||||
|
|
||||||
|
def init(g, handle):
|
||||||
|
cfg = rblf.cfg(handle)
|
||||||
|
if "true" == rblf.soong_config_get(g, "art_module", "source_build"):
|
||||||
|
pass
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -512,6 +527,21 @@ def init(g, handle):
|
|||||||
pass
|
pass
|
||||||
if rblf.file_wildcard_exists("foo*.mk"):
|
if rblf.file_wildcard_exists("foo*.mk"):
|
||||||
pass
|
pass
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "if with interpolation",
|
||||||
|
mkname: "product.mk",
|
||||||
|
in: `
|
||||||
|
ifeq ($(VARIABLE1)text$(VARIABLE2),true)
|
||||||
|
endif
|
||||||
|
`,
|
||||||
|
expected: `load("//build/make/core:product_config.rbc", "rblf")
|
||||||
|
|
||||||
|
def init(g, handle):
|
||||||
|
cfg = rblf.cfg(handle)
|
||||||
|
if "%stext%s" % (g.get("VARIABLE1", ""), g.get("VARIABLE2", "")) == "true":
|
||||||
|
pass
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user