Convert math functions
Converts the following functions from build/make/common/math.mk:
- math_max
- math_min
- math_gt_or_eq
- math_gt
- math_lt
Fixes: 213497955
Test: go test
Change-Id: I8c4e8fee321f03b813428fa10038fa8f06188cef
diff --git a/mk2rbc/expr.go b/mk2rbc/expr.go
index e78f492..3f355ac 100644
--- a/mk2rbc/expr.go
+++ b/mk2rbc/expr.go
@@ -728,6 +728,36 @@
}
}
+type binaryOpExpr struct {
+ left, right starlarkExpr
+ op string
+ returnType starlarkType
+}
+
+func (b *binaryOpExpr) emit(gctx *generationContext) {
+ b.left.emit(gctx)
+ gctx.write(" " + b.op + " ")
+ b.right.emit(gctx)
+}
+
+func (b *binaryOpExpr) typ() starlarkType {
+ return b.returnType
+}
+
+func (b *binaryOpExpr) emitListVarCopy(gctx *generationContext) {
+ b.emit(gctx)
+}
+
+func (b *binaryOpExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
+ b.left = b.left.transform(transformer)
+ b.right = b.right.transform(transformer)
+ if replacement := transformer(b); replacement != nil {
+ return replacement
+ } else {
+ return b
+ }
+}
+
type badExpr struct {
errorLocation ErrorLocation
message string
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 04038e4..28c4f7b 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -100,6 +100,11 @@
"is-vendor-board-qcom": &isVendorBoardQcomCallParser{},
"lastword": &firstOrLastwordCallParser{isLastWord: true},
"notdir": &simpleCallParser{name: baseName + ".notdir", returnType: starlarkTypeString, addGlobals: false},
+ "math_max": &mathMaxOrMinCallParser{function: "max"},
+ "math_min": &mathMaxOrMinCallParser{function: "min"},
+ "math_gt_or_eq": &mathComparisonCallParser{op: ">="},
+ "math_gt": &mathComparisonCallParser{op: ">"},
+ "math_lt": &mathComparisonCallParser{op: "<"},
"my-dir": &myDirCallParser{},
"patsubst": &substCallParser{fname: "patsubst"},
"product-copy-files-by-pattern": &simpleCallParser{name: baseName + ".product_copy_files_by_pattern", returnType: starlarkTypeList, addGlobals: false},
@@ -1064,6 +1069,23 @@
case *eqExpr:
typedExpr.isEq = !typedExpr.isEq
return typedExpr
+ case *binaryOpExpr:
+ switch typedExpr.op {
+ case ">":
+ typedExpr.op = "<="
+ return typedExpr
+ case "<":
+ typedExpr.op = ">="
+ return typedExpr
+ case ">=":
+ typedExpr.op = "<"
+ return typedExpr
+ case "<=":
+ typedExpr.op = ">"
+ return typedExpr
+ default:
+ return ¬Expr{expr: expr}
+ }
default:
return ¬Expr{expr: expr}
}
@@ -1086,6 +1108,13 @@
return otherOperand
}
}
+ if intOperand, err := strconv.Atoi(strings.TrimSpace(stringOperand)); err == nil && otherOperand.typ() == starlarkTypeInt {
+ return &eqExpr{
+ left: otherOperand,
+ right: &intLiteralExpr{literal: intOperand},
+ isEq: isEq,
+ }
+ }
}
return &eqExpr{left: xLeft, right: xRight, isEq: isEq}
@@ -1621,6 +1650,68 @@
return &indexExpr{&callExpr{object: arg, name: "split", returnType: starlarkTypeList}, index}
}
+func parseIntegerArguments(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString, expectedArgs int) ([]starlarkExpr, error) {
+ parsedArgs := make([]starlarkExpr, 0)
+ for _, arg := range args.Split(",") {
+ expr := ctx.parseMakeString(node, arg)
+ if expr.typ() == starlarkTypeList {
+ return nil, fmt.Errorf("argument to math argument has type list, which cannot be converted to int")
+ }
+ if s, ok := maybeString(expr); ok {
+ intVal, err := strconv.Atoi(strings.TrimSpace(s))
+ if err != nil {
+ return nil, err
+ }
+ expr = &intLiteralExpr{literal: intVal}
+ } else if expr.typ() != starlarkTypeInt {
+ expr = &callExpr{
+ name: "int",
+ args: []starlarkExpr{expr},
+ returnType: starlarkTypeInt,
+ }
+ }
+ parsedArgs = append(parsedArgs, expr)
+ }
+ if len(parsedArgs) != expectedArgs {
+ return nil, fmt.Errorf("function should have %d arguments", expectedArgs)
+ }
+ return parsedArgs, nil
+}
+
+type mathComparisonCallParser struct {
+ op string
+}
+
+func (p *mathComparisonCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+ parsedArgs, err := parseIntegerArguments(ctx, node, args, 2)
+ if err != nil {
+ return ctx.newBadExpr(node, err.Error())
+ }
+ return &binaryOpExpr{
+ left: parsedArgs[0],
+ right: parsedArgs[1],
+ op: p.op,
+ returnType: starlarkTypeBool,
+ }
+}
+
+type mathMaxOrMinCallParser struct {
+ function string
+}
+
+func (p *mathMaxOrMinCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+ parsedArgs, err := parseIntegerArguments(ctx, node, args, 2)
+ if err != nil {
+ return ctx.newBadExpr(node, err.Error())
+ }
+ return &callExpr{
+ object: nil,
+ name: p.function,
+ args: parsedArgs,
+ returnType: starlarkTypeInt,
+ }
+}
+
func (ctx *parseContext) parseMakeString(node mkparser.Node, mk *mkparser.MakeString) starlarkExpr {
if mk.Const() {
return &stringLiteralExpr{mk.Dump()}
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index 1ba273b..7f4de80 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -1241,6 +1241,63 @@
g["NATIVE_BRIDGE_PRODUCT_PACKAGES"] += " " + " ".join(rblf.addsuffix(".native_bridge", g.get("NATIVE_BRIDGE_ORIG_GUEST_LIBS", "")))
`,
},
+ {
+ desc: "Math functions",
+ mkname: "product.mk",
+ in: `
+# Test the math functions defined in build/make/common/math.mk
+ifeq ($(call math_max,2,5),5)
+endif
+ifeq ($(call math_min,2,5),2)
+endif
+ifeq ($(call math_gt_or_eq,2,5),true)
+endif
+ifeq ($(call math_gt,2,5),true)
+endif
+ifeq ($(call math_lt,2,5),true)
+endif
+ifeq ($(call math_gt_or_eq,2,5),)
+endif
+ifeq ($(call math_gt,2,5),)
+endif
+ifeq ($(call math_lt,2,5),)
+endif
+ifeq ($(call math_gt_or_eq,$(MY_VAR), 5),true)
+endif
+ifeq ($(call math_gt_or_eq,$(MY_VAR),$(MY_OTHER_VAR)),true)
+endif
+ifeq ($(call math_gt_or_eq,100$(MY_VAR),10),true)
+endif
+`,
+ expected: `# Test the math functions defined in build/make/common/math.mk
+load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+ cfg = rblf.cfg(handle)
+ if max(2, 5) == 5:
+ pass
+ if min(2, 5) == 2:
+ pass
+ if 2 >= 5:
+ pass
+ if 2 > 5:
+ pass
+ if 2 < 5:
+ pass
+ if 2 < 5:
+ pass
+ if 2 <= 5:
+ pass
+ if 2 >= 5:
+ pass
+ if int(g.get("MY_VAR", "")) >= 5:
+ pass
+ if int(g.get("MY_VAR", "")) >= int(g.get("MY_OTHER_VAR", "")):
+ pass
+ if int("100%s" % g.get("MY_VAR", "")) >= 10:
+ pass
+`,
+ },
}
var known_variables = []struct {