Merge "Convert math functions" am: 4cfd37e617 am: dafb404bd6

Original change: https://android-review.googlesource.com/c/platform/build/soong/+/1940098

Change-Id: I9879f7c09b60c6eaac702244e6a287560f7b4889
This commit is contained in:
Treehugger Robot 2022-01-11 04:14:12 +00:00 committed by Automerger Merge Worker
commit 47ae8c856a
3 changed files with 178 additions and 0 deletions

View file

@ -728,6 +728,36 @@ func (f *foreachExpr) transform(transformer func(expr starlarkExpr) starlarkExpr
}
}
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

View file

@ -100,6 +100,11 @@ var knownFunctions = map[string]interface {
"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},
@ -1068,6 +1073,23 @@ func (ctx *parseContext) parseCompare(cond *mkparser.Directive) starlarkExpr {
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 &notExpr{expr: expr}
}
default:
return &notExpr{expr: expr}
}
@ -1090,6 +1112,13 @@ func (ctx *parseContext) parseCompare(cond *mkparser.Directive) starlarkExpr {
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}
@ -1625,6 +1654,68 @@ func (p *firstOrLastwordCallParser) parse(ctx *parseContext, node mkparser.Node,
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()}

View file

@ -1279,6 +1279,63 @@ def init(g, handle):
g["NATIVE_BRIDGE_PRODUCT_PACKAGES"] = "libnative_bridge_vdso.native_bridge native_bridge_guest_app_process.native_bridge native_bridge_guest_linker.native_bridge"
g["NATIVE_BRIDGE_MODIFIED_GUEST_LIBS"] = "libaaudio libamidi libandroid libandroid_runtime"
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
`,
},
}