Support if expressions in mk2rbc
Bug: 201700692 Test: go test Change-Id: Icdf30c4d625d81974db946bd91660a29a0373ac7
This commit is contained in:
@@ -85,6 +85,31 @@ func (s *intLiteralExpr) emitListVarCopy(gctx *generationContext) {
|
|||||||
s.emit(gctx)
|
s.emit(gctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Boolean literal
|
||||||
|
type boolLiteralExpr struct {
|
||||||
|
literal bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *boolLiteralExpr) eval(_ map[string]starlarkExpr) (res starlarkExpr, same bool) {
|
||||||
|
return b, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *boolLiteralExpr) emit(gctx *generationContext) {
|
||||||
|
if b.literal {
|
||||||
|
gctx.write("True")
|
||||||
|
} else {
|
||||||
|
gctx.write("False")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ *boolLiteralExpr) typ() starlarkType {
|
||||||
|
return starlarkTypeBool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *boolLiteralExpr) emitListVarCopy(gctx *generationContext) {
|
||||||
|
b.emit(gctx)
|
||||||
|
}
|
||||||
|
|
||||||
// interpolateExpr represents Starlark's interpolation operator <string> % list
|
// interpolateExpr represents Starlark's interpolation operator <string> % list
|
||||||
// we break <string> into a list of chunks, i.e., "first%second%third" % (X, Y)
|
// we break <string> into a list of chunks, i.e., "first%second%third" % (X, Y)
|
||||||
// will have chunks = ["first", "second", "third"] and args = [X, Y]
|
// will have chunks = ["first", "second", "third"] and args = [X, Y]
|
||||||
@@ -617,6 +642,55 @@ func (cx *callExpr) emitListVarCopy(gctx *generationContext) {
|
|||||||
cx.emit(gctx)
|
cx.emit(gctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ifExpr struct {
|
||||||
|
condition starlarkExpr
|
||||||
|
ifTrue starlarkExpr
|
||||||
|
ifFalse starlarkExpr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ifExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
|
||||||
|
cond, condSame := i.condition.eval(valueMap)
|
||||||
|
t, tSame := i.ifTrue.eval(valueMap)
|
||||||
|
f, fSame := i.ifFalse.eval(valueMap)
|
||||||
|
same = condSame && tSame && fSame
|
||||||
|
if same {
|
||||||
|
return i, same
|
||||||
|
} else {
|
||||||
|
return &ifExpr{
|
||||||
|
condition: cond,
|
||||||
|
ifTrue: t,
|
||||||
|
ifFalse: f,
|
||||||
|
}, same
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ifExpr) emit(gctx *generationContext) {
|
||||||
|
gctx.write("(")
|
||||||
|
i.ifTrue.emit(gctx)
|
||||||
|
gctx.write(" if ")
|
||||||
|
i.condition.emit(gctx)
|
||||||
|
gctx.write(" else ")
|
||||||
|
i.ifFalse.emit(gctx)
|
||||||
|
gctx.write(")")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ifExpr) typ() starlarkType {
|
||||||
|
tType := i.ifTrue.typ()
|
||||||
|
fType := i.ifFalse.typ()
|
||||||
|
if tType != fType && tType != starlarkTypeUnknown && fType != starlarkTypeUnknown {
|
||||||
|
panic("Conflicting types in if expression")
|
||||||
|
}
|
||||||
|
if tType != starlarkTypeUnknown {
|
||||||
|
return tType
|
||||||
|
} else {
|
||||||
|
return fType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ifExpr) emitListVarCopy(gctx *generationContext) {
|
||||||
|
i.emit(gctx)
|
||||||
|
}
|
||||||
|
|
||||||
type badExpr struct {
|
type badExpr struct {
|
||||||
errorLocation ErrorLocation
|
errorLocation ErrorLocation
|
||||||
message string
|
message string
|
||||||
|
@@ -112,6 +112,7 @@ var knownFunctions = map[string]struct {
|
|||||||
"filter-out": {baseName + ".filter_out", starlarkTypeList, hiddenArgNone},
|
"filter-out": {baseName + ".filter_out", starlarkTypeList, hiddenArgNone},
|
||||||
"firstword": {"!firstword", starlarkTypeString, hiddenArgNone},
|
"firstword": {"!firstword", starlarkTypeString, hiddenArgNone},
|
||||||
"get-vendor-board-platforms": {"!get-vendor-board-platforms", starlarkTypeList, hiddenArgNone}, // internal macro, used by is-board-platform, etc.
|
"get-vendor-board-platforms": {"!get-vendor-board-platforms", starlarkTypeList, hiddenArgNone}, // internal macro, used by is-board-platform, etc.
|
||||||
|
"if": {"!if", starlarkTypeUnknown, hiddenArgNone},
|
||||||
"info": {baseName + ".mkinfo", starlarkTypeVoid, hiddenArgNone},
|
"info": {baseName + ".mkinfo", starlarkTypeVoid, hiddenArgNone},
|
||||||
"is-android-codename": {"!is-android-codename", starlarkTypeBool, hiddenArgNone}, // unused by product config
|
"is-android-codename": {"!is-android-codename", starlarkTypeBool, hiddenArgNone}, // unused by product config
|
||||||
"is-android-codename-in-list": {"!is-android-codename-in-list", starlarkTypeBool, hiddenArgNone}, // unused by product config
|
"is-android-codename-in-list": {"!is-android-codename-in-list", starlarkTypeBool, hiddenArgNone}, // unused by product config
|
||||||
@@ -1368,6 +1369,8 @@ func (ctx *parseContext) parseReference(node mkparser.Node, ref *mkparser.MakeSt
|
|||||||
return ctx.newBadExpr(node, "cannot handle invoking %s", expr.name)
|
return ctx.newBadExpr(node, "cannot handle invoking %s", expr.name)
|
||||||
}
|
}
|
||||||
switch expr.name {
|
switch expr.name {
|
||||||
|
case "if":
|
||||||
|
return ctx.parseIfFunc(node, args)
|
||||||
case "word":
|
case "word":
|
||||||
return ctx.parseWordFunc(node, args)
|
return ctx.parseWordFunc(node, args)
|
||||||
case "firstword", "lastword":
|
case "firstword", "lastword":
|
||||||
@@ -1423,6 +1426,35 @@ func (ctx *parseContext) parseSubstFunc(node mkparser.Node, fname string, args *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctx *parseContext) parseIfFunc(node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
|
||||||
|
words := args.Split(",")
|
||||||
|
if len(words) != 2 && len(words) != 3 {
|
||||||
|
return ctx.newBadExpr(node, "if function should have 2 or 3 arguments, found "+strconv.Itoa(len(words)))
|
||||||
|
}
|
||||||
|
condition := ctx.parseMakeString(node, words[0])
|
||||||
|
ifTrue := ctx.parseMakeString(node, words[1])
|
||||||
|
var ifFalse starlarkExpr
|
||||||
|
if len(words) == 3 {
|
||||||
|
ifFalse = ctx.parseMakeString(node, words[2])
|
||||||
|
} else {
|
||||||
|
switch ifTrue.typ() {
|
||||||
|
case starlarkTypeList:
|
||||||
|
ifFalse = &listExpr{items: []starlarkExpr{}}
|
||||||
|
case starlarkTypeInt:
|
||||||
|
ifFalse = &intLiteralExpr{literal: 0}
|
||||||
|
case starlarkTypeBool:
|
||||||
|
ifFalse = &boolLiteralExpr{literal: false}
|
||||||
|
default:
|
||||||
|
ifFalse = &stringLiteralExpr{literal: ""}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &ifExpr{
|
||||||
|
condition,
|
||||||
|
ifTrue,
|
||||||
|
ifFalse,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (ctx *parseContext) parseWordFunc(node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
|
func (ctx *parseContext) parseWordFunc(node mkparser.Node, args *mkparser.MakeString) starlarkExpr {
|
||||||
words := args.Split(",")
|
words := args.Split(",")
|
||||||
if len(words) != 2 {
|
if len(words) != 2 {
|
||||||
|
@@ -1089,6 +1089,29 @@ def init(g, handle):
|
|||||||
cfg = rblf.cfg(handle)
|
cfg = rblf.cfg(handle)
|
||||||
if rblf.mk2rbc_error("build/product.mk:2", "cannot handle invoking foobar"):
|
if rblf.mk2rbc_error("build/product.mk:2", "cannot handle invoking foobar"):
|
||||||
pass
|
pass
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "if expression",
|
||||||
|
mkname: "product.mk",
|
||||||
|
in: `
|
||||||
|
TEST_VAR := foo
|
||||||
|
TEST_VAR_LIST := foo
|
||||||
|
TEST_VAR_LIST += bar
|
||||||
|
TEST_VAR_2 := $(if $(TEST_VAR),bar)
|
||||||
|
TEST_VAR_3 := $(if $(TEST_VAR),bar,baz)
|
||||||
|
TEST_VAR_3 := $(if $(TEST_VAR),$(TEST_VAR_LIST))
|
||||||
|
`,
|
||||||
|
expected: `load("//build/make/core:product_config.rbc", "rblf")
|
||||||
|
|
||||||
|
def init(g, handle):
|
||||||
|
cfg = rblf.cfg(handle)
|
||||||
|
g["TEST_VAR"] = "foo"
|
||||||
|
g["TEST_VAR_LIST"] = ["foo"]
|
||||||
|
g["TEST_VAR_LIST"] += ["bar"]
|
||||||
|
g["TEST_VAR_2"] = ("bar" if g["TEST_VAR"] else "")
|
||||||
|
g["TEST_VAR_3"] = ("bar" if g["TEST_VAR"] else "baz")
|
||||||
|
g["TEST_VAR_3"] = (g["TEST_VAR_LIST"] if g["TEST_VAR"] else [])
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user