Emit mkpatsubst call for $(patsubst ...)

Bug: 172923994
Test: internal
Change-Id: I19f0e104d253230e603a098605736ac36e65818e
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index abfd082..0e9e6fe 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -93,6 +93,7 @@
 	"is-vendor-board-platform":            {"!is-vendor-board-platform", starlarkTypeBool},
 	callLoadAlways:                        {"!inherit-product", starlarkTypeVoid},
 	callLoadIf:                            {"!inherit-product-if-exists", starlarkTypeVoid},
+	"patsubst":                            {baseName + ".mkpatsubst", starlarkTypeString},
 	"produce_copy_files":                  {baseName + ".produce_copy_files", starlarkTypeList},
 	"require-artifacts-in-path":           {baseName + ".require_artifacts_in_path", starlarkTypeVoid},
 	"require-artifacts-in-path-relaxed":   {baseName + ".require_artifacts_in_path_relaxed", starlarkTypeVoid},
@@ -1079,8 +1080,8 @@
 	switch expr.name {
 	case "word":
 		return ctx.parseWordFunc(node, args)
-	case "subst":
-		return ctx.parseSubstFunc(node, args)
+	case "subst", "patsubst":
+		return ctx.parseSubstFunc(node, expr.name, args)
 	default:
 		for _, arg := range args.Split(",") {
 			arg.TrimLeftSpaces()
@@ -1095,13 +1096,13 @@
 	return expr
 }
 
-func (ctx *parseContext) parseSubstFunc(node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
+func (ctx *parseContext) parseSubstFunc(node mkparser.Node, fname string, args *mkparser.MakeString) starlarkExpr {
 	words := args.Split(",")
 	if len(words) != 3 {
-		return ctx.newBadExpr(node, "subst function should have 3 arguments")
+		return ctx.newBadExpr(node, "%s function should have 3 arguments", fname)
 	}
 	if !words[0].Const() || !words[1].Const() {
-		return ctx.newBadExpr(node, "subst function's from and to arguments should be constant")
+		return ctx.newBadExpr(node, "%s function's from and to arguments should be constant", fname)
 	}
 	from := words[0].Strings[0]
 	to := words[1].Strings[0]
@@ -1109,7 +1110,8 @@
 	words[2].TrimRightSpaces()
 	obj := ctx.parseMakeString(node, words[2])
 	typ := obj.typ()
-	if typ == starlarkTypeString {
+	if typ == starlarkTypeString && fname == "subst" {
+		// Optimization: if it's $(subst from, to, string), emit string.replace(from, to)
 		return &callExpr{
 			object:     obj,
 			name:       "replace",
@@ -1118,7 +1120,7 @@
 		}
 	}
 	return &callExpr{
-		name:       "subst",
+		name:       fname,
 		args:       []starlarkExpr{&stringLiteralExpr{from}, &stringLiteralExpr{to}, obj},
 		returnType: obj.typ(),
 	}
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index bb6484b..240d0b8 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -628,6 +628,7 @@
 PRODUCT_COPY_FILES := $(addprefix pfx-,a b c)
 PRODUCT_COPY_FILES := $(addsuffix .sff, a b c)
 PRODUCT_NAME := $(word 1, $(subst ., ,$(TARGET_BOARD_PLATFORM)))
+$(info $(patsubst %.pub,%,$(PRODUCT_ADB_KEYS)))
 
 `,
 		expected: `load("//build/make/core:product_config.rbc", "rblf")
@@ -637,6 +638,7 @@
   cfg["PRODUCT_COPY_FILES"] = rblf.addprefix("pfx-", "a b c")
   cfg["PRODUCT_COPY_FILES"] = rblf.addsuffix(".sff", "a b c")
   cfg["PRODUCT_NAME"] = ((g.get("TARGET_BOARD_PLATFORM", "")).replace(".", " ")).split()[0]
+  rblf.mkinfo("product.mk", rblf.mkpatsubst("%.pub", "%", g.get("PRODUCT_ADB_KEYS", "")))
 `,
 	},
 	{