Support converting simple $(eval) expressions

While supporting $(eval) in the general case is
impossible, as it would require emitting code at
runtime, it is possible to handle some special cases
that are common throughout the code base.

Specifically, an assignement expression (where the
left hand side is constant) can be converted without
needing to evaluate strings as code, as its whole
right hand side is treated as one string.

However, this eval with an assignemnt can only be
used as a statement, not an expression. So it requires
the eval to be either a top-level expression, or nested
within other expressions that can be converted to
statements such as $(foreach) or $(if).

Bug: 226974242
Test: go test
Change-Id: Ifc52ef9ab7d62a69251918fcde5463f80a98a542
This commit is contained in:
Cole Faust
2022-03-28 14:02:50 -07:00
parent 4242115d59
commit f035d405d8
4 changed files with 301 additions and 78 deletions

View File

@@ -221,11 +221,9 @@ func (xi *interpolateExpr) emitListVarCopy(gctx *generationContext) {
}
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)
for i := range xi.args {
xi.args[i] = xi.args[i].transform(transformer)
}
xi.args = argsCopy
if replacement := transformer(xi); replacement != nil {
return replacement
} else {
@@ -591,11 +589,9 @@ func (cx *callExpr) transform(transformer func(expr 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)
for i := range cx.args {
cx.args[i] = cx.args[i].transform(transformer)
}
cx.args = argsCopy
if replacement := transformer(cx); replacement != nil {
return replacement
} else {
@@ -769,3 +765,35 @@ func isEmptyString(expr starlarkExpr) bool {
x, ok := expr.(*stringLiteralExpr)
return ok && x.literal == ""
}
func negateExpr(expr starlarkExpr) starlarkExpr {
switch typedExpr := expr.(type) {
case *notExpr:
return typedExpr.expr
case *inExpr:
typedExpr.isNot = !typedExpr.isNot
return typedExpr
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}
}
}