Loading mk2rbc/mk2rbc.go +47 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ var knownFunctions = map[string]interface { "add-to-product-copy-files-if-exists": &simpleCallParser{name: baseName + ".copy_if_exists", returnType: starlarkTypeList}, "addprefix": &simpleCallParser{name: baseName + ".addprefix", returnType: starlarkTypeList}, "addsuffix": &simpleCallParser{name: baseName + ".addsuffix", returnType: starlarkTypeList}, "and": &andOrParser{isAnd: true}, "copy-files": &simpleCallParser{name: baseName + ".copy_files", returnType: starlarkTypeList}, "dir": &simpleCallParser{name: baseName + ".dir", returnType: starlarkTypeString}, "dist-for-goals": &simpleCallParser{name: baseName + ".mkdist_for_goals", returnType: starlarkTypeVoid, addGlobals: true}, Loading Loading @@ -105,6 +106,7 @@ var knownFunctions = map[string]interface { "math_gt": &mathComparisonCallParser{op: ">"}, "math_lt": &mathComparisonCallParser{op: "<"}, "my-dir": &myDirCallParser{}, "or": &andOrParser{isAnd: false}, "patsubst": &substCallParser{fname: "patsubst"}, "product-copy-files-by-pattern": &simpleCallParser{name: baseName + ".product_copy_files_by_pattern", returnType: starlarkTypeList}, "require-artifacts-in-path": &simpleCallParser{name: baseName + ".require_artifacts_in_path", returnType: starlarkTypeVoid, addHandle: true}, Loading Loading @@ -1430,6 +1432,51 @@ func (p *myDirCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkp return &stringLiteralExpr{literal: filepath.Dir(ctx.script.mkFile)} } type andOrParser struct { isAnd bool } func (p *andOrParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr { if args.Empty() { return ctx.newBadExpr(node, "and/or function must have at least 1 argument") } op := "or" if p.isAnd { op = "and" } argsParsed := make([]starlarkExpr, 0) for _, arg := range args.Split(",") { arg.TrimLeftSpaces() arg.TrimRightSpaces() x := ctx.parseMakeString(node, arg) if xBad, ok := x.(*badExpr); ok { return xBad } argsParsed = append(argsParsed, x) } typ := starlarkTypeUnknown for _, arg := range argsParsed { if typ != arg.typ() && arg.typ() != starlarkTypeUnknown && typ != starlarkTypeUnknown { return ctx.newBadExpr(node, "Expected all arguments to $(or) or $(and) to have the same type, found %q and %q", typ.String(), arg.typ().String()) } if arg.typ() != starlarkTypeUnknown { typ = arg.typ() } } result := argsParsed[0] for _, arg := range argsParsed[1:] { result = &binaryOpExpr{ left: result, right: arg, op: op, returnType: typ, } } return result } type isProductInListCallParser struct{} func (p *isProductInListCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr { Loading mk2rbc/mk2rbc_test.go +32 −0 Original line number Diff line number Diff line Loading @@ -1627,6 +1627,38 @@ def init(g, handle): g["MY_VAR_3"] = (cfg).get(g["MY_VAR_2"], (g).get(g["MY_VAR_2"], "")) g["MY_VAR_4"] = rblf.mk2rbc_error("product.mk:5", "cannot handle invoking foo") g["MY_VAR_5"] = rblf.mk2rbc_error("product.mk:6", "reference is too complex: $(MY_VAR_2) bar") `, }, { desc: "Conditional functions", mkname: "product.mk", in: ` B := foo X := $(or $(A)) X := $(or $(A),$(B)) X := $(or $(A),$(B),$(C)) X := $(and $(A)) X := $(and $(A),$(B)) X := $(and $(A),$(B),$(C)) X := $(or $(A),$(B)) Y D := $(wildcard *.mk) X := $(or $(B),$(D)) `, expected: `load("//build/make/core:product_config.rbc", "rblf") def init(g, handle): cfg = rblf.cfg(handle) g["B"] = "foo" g["X"] = g.get("A", "") g["X"] = g.get("A", "") or g["B"] g["X"] = g.get("A", "") or g["B"] or g.get("C", "") g["X"] = g.get("A", "") g["X"] = g.get("A", "") and g["B"] g["X"] = g.get("A", "") and g["B"] and g.get("C", "") g["X"] = "%s Y" % g.get("A", "") or g["B"] g["D"] = rblf.expand_wildcard("*.mk") g["X"] = rblf.mk2rbc_error("product.mk:12", "Expected all arguments to $(or) or $(and) to have the same type, found \"string\" and \"list\"") `, }, } Loading mk2rbc/types.go +21 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ package mk2rbc import "fmt" // Starlark expression types we use type starlarkType int Loading @@ -31,6 +33,25 @@ const ( starlarkTypeVoid starlarkType = iota ) func (t starlarkType) String() string { switch t { case starlarkTypeList: return "list" case starlarkTypeString: return "string" case starlarkTypeInt: return "int" case starlarkTypeBool: return "bool" case starlarkTypeVoid: return "void" case starlarkTypeUnknown: return "unknown" default: panic(fmt.Sprintf("Unknown starlark type %d", t)) } } type hiddenArgType int const ( Loading Loading
mk2rbc/mk2rbc.go +47 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,7 @@ var knownFunctions = map[string]interface { "add-to-product-copy-files-if-exists": &simpleCallParser{name: baseName + ".copy_if_exists", returnType: starlarkTypeList}, "addprefix": &simpleCallParser{name: baseName + ".addprefix", returnType: starlarkTypeList}, "addsuffix": &simpleCallParser{name: baseName + ".addsuffix", returnType: starlarkTypeList}, "and": &andOrParser{isAnd: true}, "copy-files": &simpleCallParser{name: baseName + ".copy_files", returnType: starlarkTypeList}, "dir": &simpleCallParser{name: baseName + ".dir", returnType: starlarkTypeString}, "dist-for-goals": &simpleCallParser{name: baseName + ".mkdist_for_goals", returnType: starlarkTypeVoid, addGlobals: true}, Loading Loading @@ -105,6 +106,7 @@ var knownFunctions = map[string]interface { "math_gt": &mathComparisonCallParser{op: ">"}, "math_lt": &mathComparisonCallParser{op: "<"}, "my-dir": &myDirCallParser{}, "or": &andOrParser{isAnd: false}, "patsubst": &substCallParser{fname: "patsubst"}, "product-copy-files-by-pattern": &simpleCallParser{name: baseName + ".product_copy_files_by_pattern", returnType: starlarkTypeList}, "require-artifacts-in-path": &simpleCallParser{name: baseName + ".require_artifacts_in_path", returnType: starlarkTypeVoid, addHandle: true}, Loading Loading @@ -1430,6 +1432,51 @@ func (p *myDirCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkp return &stringLiteralExpr{literal: filepath.Dir(ctx.script.mkFile)} } type andOrParser struct { isAnd bool } func (p *andOrParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr { if args.Empty() { return ctx.newBadExpr(node, "and/or function must have at least 1 argument") } op := "or" if p.isAnd { op = "and" } argsParsed := make([]starlarkExpr, 0) for _, arg := range args.Split(",") { arg.TrimLeftSpaces() arg.TrimRightSpaces() x := ctx.parseMakeString(node, arg) if xBad, ok := x.(*badExpr); ok { return xBad } argsParsed = append(argsParsed, x) } typ := starlarkTypeUnknown for _, arg := range argsParsed { if typ != arg.typ() && arg.typ() != starlarkTypeUnknown && typ != starlarkTypeUnknown { return ctx.newBadExpr(node, "Expected all arguments to $(or) or $(and) to have the same type, found %q and %q", typ.String(), arg.typ().String()) } if arg.typ() != starlarkTypeUnknown { typ = arg.typ() } } result := argsParsed[0] for _, arg := range argsParsed[1:] { result = &binaryOpExpr{ left: result, right: arg, op: op, returnType: typ, } } return result } type isProductInListCallParser struct{} func (p *isProductInListCallParser) parse(ctx *parseContext, node mkparser.Node, args *mkparser.MakeString) starlarkExpr { Loading
mk2rbc/mk2rbc_test.go +32 −0 Original line number Diff line number Diff line Loading @@ -1627,6 +1627,38 @@ def init(g, handle): g["MY_VAR_3"] = (cfg).get(g["MY_VAR_2"], (g).get(g["MY_VAR_2"], "")) g["MY_VAR_4"] = rblf.mk2rbc_error("product.mk:5", "cannot handle invoking foo") g["MY_VAR_5"] = rblf.mk2rbc_error("product.mk:6", "reference is too complex: $(MY_VAR_2) bar") `, }, { desc: "Conditional functions", mkname: "product.mk", in: ` B := foo X := $(or $(A)) X := $(or $(A),$(B)) X := $(or $(A),$(B),$(C)) X := $(and $(A)) X := $(and $(A),$(B)) X := $(and $(A),$(B),$(C)) X := $(or $(A),$(B)) Y D := $(wildcard *.mk) X := $(or $(B),$(D)) `, expected: `load("//build/make/core:product_config.rbc", "rblf") def init(g, handle): cfg = rblf.cfg(handle) g["B"] = "foo" g["X"] = g.get("A", "") g["X"] = g.get("A", "") or g["B"] g["X"] = g.get("A", "") or g["B"] or g.get("C", "") g["X"] = g.get("A", "") g["X"] = g.get("A", "") and g["B"] g["X"] = g.get("A", "") and g["B"] and g.get("C", "") g["X"] = "%s Y" % g.get("A", "") or g["B"] g["D"] = rblf.expand_wildcard("*.mk") g["X"] = rblf.mk2rbc_error("product.mk:12", "Expected all arguments to $(or) or $(and) to have the same type, found \"string\" and \"list\"") `, }, } Loading
mk2rbc/types.go +21 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ package mk2rbc import "fmt" // Starlark expression types we use type starlarkType int Loading @@ -31,6 +33,25 @@ const ( starlarkTypeVoid starlarkType = iota ) func (t starlarkType) String() string { switch t { case starlarkTypeList: return "list" case starlarkTypeString: return "string" case starlarkTypeInt: return "int" case starlarkTypeBool: return "bool" case starlarkTypeVoid: return "void" case starlarkTypeUnknown: return "unknown" default: panic(fmt.Sprintf("Unknown starlark type %d", t)) } } type hiddenArgType int const ( Loading