Handle foreach expressions in mk2rbc
Bug: 201700692 Test: go test Change-Id: Ia23494a63567a1fe2d4bb797a2d4dd5925b3431d
This commit is contained in:
247
mk2rbc/expr.go
247
mk2rbc/expr.go
@@ -31,6 +31,12 @@ type starlarkExpr interface {
|
||||
// Emit the code to copy the expression, otherwise we will end up
|
||||
// with source and target pointing to the same list.
|
||||
emitListVarCopy(gctx *generationContext)
|
||||
// Return the expression, calling the transformer func for
|
||||
// every expression in the tree. If the transformer func returns non-nil,
|
||||
// its result is used in place of the expression it was called with in the
|
||||
// resulting expression. The resulting starlarkExpr will contain as many
|
||||
// of the same objects from the original expression as possible.
|
||||
transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr
|
||||
}
|
||||
|
||||
func maybeString(expr starlarkExpr) (string, bool) {
|
||||
@@ -62,6 +68,14 @@ func (s *stringLiteralExpr) emitListVarCopy(gctx *generationContext) {
|
||||
s.emit(gctx)
|
||||
}
|
||||
|
||||
func (s *stringLiteralExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
if replacement := transformer(s); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
// Integer literal
|
||||
type intLiteralExpr struct {
|
||||
literal int
|
||||
@@ -85,6 +99,14 @@ func (s *intLiteralExpr) emitListVarCopy(gctx *generationContext) {
|
||||
s.emit(gctx)
|
||||
}
|
||||
|
||||
func (s *intLiteralExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
if replacement := transformer(s); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
// Boolean literal
|
||||
type boolLiteralExpr struct {
|
||||
literal bool
|
||||
@@ -110,6 +132,14 @@ func (b *boolLiteralExpr) emitListVarCopy(gctx *generationContext) {
|
||||
b.emit(gctx)
|
||||
}
|
||||
|
||||
func (b *boolLiteralExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
if replacement := transformer(b); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return b
|
||||
}
|
||||
}
|
||||
|
||||
// interpolateExpr represents Starlark's interpolation operator <string> % list
|
||||
// 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]
|
||||
@@ -190,6 +220,19 @@ func (xi *interpolateExpr) emitListVarCopy(gctx *generationContext) {
|
||||
xi.emit(gctx)
|
||||
}
|
||||
|
||||
func (xi *interpolateExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
argsCopy := make([]starlarkExpr, len(xi.args))
|
||||
for i, arg := range xi.args {
|
||||
argsCopy[i] = arg.transform(transformer)
|
||||
}
|
||||
xi.args = argsCopy
|
||||
if replacement := transformer(xi); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return xi
|
||||
}
|
||||
}
|
||||
|
||||
type variableRefExpr struct {
|
||||
ref variable
|
||||
isDefined bool
|
||||
@@ -220,6 +263,14 @@ func (v *variableRefExpr) emitListVarCopy(gctx *generationContext) {
|
||||
}
|
||||
}
|
||||
|
||||
func (v *variableRefExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
if replacement := transformer(v); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
type toStringExpr struct {
|
||||
expr starlarkExpr
|
||||
}
|
||||
@@ -265,6 +316,15 @@ func (s *toStringExpr) emitListVarCopy(gctx *generationContext) {
|
||||
s.emit(gctx)
|
||||
}
|
||||
|
||||
func (s *toStringExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
s.expr = s.expr.transform(transformer)
|
||||
if replacement := transformer(s); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
type notExpr struct {
|
||||
expr starlarkExpr
|
||||
}
|
||||
@@ -291,6 +351,15 @@ func (n *notExpr) emitListVarCopy(gctx *generationContext) {
|
||||
n.emit(gctx)
|
||||
}
|
||||
|
||||
func (n *notExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
n.expr = n.expr.transform(transformer)
|
||||
if replacement := transformer(n); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return n
|
||||
}
|
||||
}
|
||||
|
||||
type eqExpr struct {
|
||||
left, right starlarkExpr
|
||||
isEq bool // if false, it's !=
|
||||
@@ -360,6 +429,16 @@ func (eq *eqExpr) emitListVarCopy(gctx *generationContext) {
|
||||
eq.emit(gctx)
|
||||
}
|
||||
|
||||
func (eq *eqExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
eq.left = eq.left.transform(transformer)
|
||||
eq.right = eq.right.transform(transformer)
|
||||
if replacement := transformer(eq); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return eq
|
||||
}
|
||||
}
|
||||
|
||||
// variableDefinedExpr corresponds to Make's ifdef VAR
|
||||
type variableDefinedExpr struct {
|
||||
v variable
|
||||
@@ -388,6 +467,11 @@ func (v *variableDefinedExpr) emitListVarCopy(gctx *generationContext) {
|
||||
v.emit(gctx)
|
||||
}
|
||||
|
||||
func (v *variableDefinedExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
// TODO: VariableDefinedExpr isn't really an expression?
|
||||
return v
|
||||
}
|
||||
|
||||
type listExpr struct {
|
||||
items []starlarkExpr
|
||||
}
|
||||
@@ -442,6 +526,19 @@ func (l *listExpr) emitListVarCopy(gctx *generationContext) {
|
||||
l.emit(gctx)
|
||||
}
|
||||
|
||||
func (l *listExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
itemsCopy := make([]starlarkExpr, len(l.items))
|
||||
for i, item := range l.items {
|
||||
itemsCopy[i] = item.transform(transformer)
|
||||
}
|
||||
l.items = itemsCopy
|
||||
if replacement := transformer(l); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return l
|
||||
}
|
||||
}
|
||||
|
||||
func newStringListExpr(items []string) *listExpr {
|
||||
v := listExpr{}
|
||||
for _, item := range items {
|
||||
@@ -505,6 +602,19 @@ func (c *concatExpr) emitListVarCopy(gctx *generationContext) {
|
||||
c.emit(gctx)
|
||||
}
|
||||
|
||||
func (c *concatExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
itemsCopy := make([]starlarkExpr, len(c.items))
|
||||
for i, item := range c.items {
|
||||
itemsCopy[i] = item.transform(transformer)
|
||||
}
|
||||
c.items = itemsCopy
|
||||
if replacement := transformer(c); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return c
|
||||
}
|
||||
}
|
||||
|
||||
// inExpr generates <expr> [not] in <list>
|
||||
type inExpr struct {
|
||||
expr starlarkExpr
|
||||
@@ -543,23 +653,33 @@ func (i *inExpr) emitListVarCopy(gctx *generationContext) {
|
||||
i.emit(gctx)
|
||||
}
|
||||
|
||||
func (i *inExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
i.expr = i.expr.transform(transformer)
|
||||
i.list = i.list.transform(transformer)
|
||||
if replacement := transformer(i); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
type indexExpr struct {
|
||||
array starlarkExpr
|
||||
index starlarkExpr
|
||||
}
|
||||
|
||||
func (ix indexExpr) emit(gctx *generationContext) {
|
||||
func (ix *indexExpr) emit(gctx *generationContext) {
|
||||
ix.array.emit(gctx)
|
||||
gctx.write("[")
|
||||
ix.index.emit(gctx)
|
||||
gctx.write("]")
|
||||
}
|
||||
|
||||
func (ix indexExpr) typ() starlarkType {
|
||||
func (ix *indexExpr) typ() starlarkType {
|
||||
return starlarkTypeString
|
||||
}
|
||||
|
||||
func (ix indexExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
|
||||
func (ix *indexExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
|
||||
newArray, isSameArray := ix.array.eval(valueMap)
|
||||
newIndex, isSameIndex := ix.index.eval(valueMap)
|
||||
if same = isSameArray && isSameIndex; same {
|
||||
@@ -570,10 +690,20 @@ func (ix indexExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, sa
|
||||
return
|
||||
}
|
||||
|
||||
func (ix indexExpr) emitListVarCopy(gctx *generationContext) {
|
||||
func (ix *indexExpr) emitListVarCopy(gctx *generationContext) {
|
||||
ix.emit(gctx)
|
||||
}
|
||||
|
||||
func (ix *indexExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
ix.array = ix.array.transform(transformer)
|
||||
ix.index = ix.index.transform(transformer)
|
||||
if replacement := transformer(ix); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return ix
|
||||
}
|
||||
}
|
||||
|
||||
type callExpr struct {
|
||||
object starlarkExpr // nil if static call
|
||||
name string
|
||||
@@ -642,6 +772,21 @@ func (cx *callExpr) emitListVarCopy(gctx *generationContext) {
|
||||
cx.emit(gctx)
|
||||
}
|
||||
|
||||
func (cx *callExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
if cx.object != nil {
|
||||
cx.object = cx.object.transform(transformer)
|
||||
}
|
||||
argsCopy := make([]starlarkExpr, len(cx.args))
|
||||
for i, arg := range cx.args {
|
||||
argsCopy[i] = arg.transform(transformer)
|
||||
}
|
||||
if replacement := transformer(cx); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return cx
|
||||
}
|
||||
}
|
||||
|
||||
type ifExpr struct {
|
||||
condition starlarkExpr
|
||||
ifTrue starlarkExpr
|
||||
@@ -691,6 +836,92 @@ func (i *ifExpr) emitListVarCopy(gctx *generationContext) {
|
||||
i.emit(gctx)
|
||||
}
|
||||
|
||||
func (i *ifExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
i.condition = i.condition.transform(transformer)
|
||||
i.ifTrue = i.ifTrue.transform(transformer)
|
||||
i.ifFalse = i.ifFalse.transform(transformer)
|
||||
if replacement := transformer(i); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
type identifierExpr struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (i *identifierExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
|
||||
return i, true
|
||||
}
|
||||
|
||||
func (i *identifierExpr) emit(gctx *generationContext) {
|
||||
gctx.write(i.name)
|
||||
}
|
||||
|
||||
func (i *identifierExpr) typ() starlarkType {
|
||||
return starlarkTypeUnknown
|
||||
}
|
||||
|
||||
func (i *identifierExpr) emitListVarCopy(gctx *generationContext) {
|
||||
i.emit(gctx)
|
||||
}
|
||||
|
||||
func (i *identifierExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
if replacement := transformer(i); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
type foreachExpr struct {
|
||||
varName string
|
||||
list starlarkExpr
|
||||
action starlarkExpr
|
||||
}
|
||||
|
||||
func (f *foreachExpr) eval(valueMap map[string]starlarkExpr) (res starlarkExpr, same bool) {
|
||||
list, listSame := f.list.eval(valueMap)
|
||||
action, actionSame := f.action.eval(valueMap)
|
||||
same = listSame && actionSame
|
||||
if same {
|
||||
return f, same
|
||||
} else {
|
||||
return &foreachExpr{
|
||||
varName: f.varName,
|
||||
list: list,
|
||||
action: action,
|
||||
}, same
|
||||
}
|
||||
}
|
||||
|
||||
func (f *foreachExpr) emit(gctx *generationContext) {
|
||||
gctx.write("[")
|
||||
f.action.emit(gctx)
|
||||
gctx.write(" for " + f.varName + " in ")
|
||||
f.list.emit(gctx)
|
||||
gctx.write("]")
|
||||
}
|
||||
|
||||
func (f *foreachExpr) typ() starlarkType {
|
||||
return starlarkTypeList
|
||||
}
|
||||
|
||||
func (f *foreachExpr) emitListVarCopy(gctx *generationContext) {
|
||||
f.emit(gctx)
|
||||
}
|
||||
|
||||
func (f *foreachExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
f.list = f.list.transform(transformer)
|
||||
f.action = f.action.transform(transformer)
|
||||
if replacement := transformer(f); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return f
|
||||
}
|
||||
}
|
||||
|
||||
type badExpr struct {
|
||||
errorLocation ErrorLocation
|
||||
message string
|
||||
@@ -714,6 +945,14 @@ func (_ *badExpr) emitListVarCopy(_ *generationContext) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (b *badExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
|
||||
if replacement := transformer(b); replacement != nil {
|
||||
return replacement
|
||||
} else {
|
||||
return b
|
||||
}
|
||||
}
|
||||
|
||||
func maybeConvertToStringList(expr starlarkExpr) starlarkExpr {
|
||||
if xString, ok := expr.(*stringLiteralExpr); ok {
|
||||
return newStringListExpr(strings.Fields(xString.literal))
|
||||
|
Reference in New Issue
Block a user