123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798 |
- // Copyright 2021 Google LLC
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package mk2rbc
- import (
- "fmt"
- "strings"
- )
- // Represents an expression in the Starlark code. An expression has a type.
- type starlarkExpr interface {
- starlarkNode
- typ() starlarkType
- // 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) {
- if x, ok := expr.(*stringLiteralExpr); ok {
- return x.literal, true
- }
- return "", false
- }
- type stringLiteralExpr struct {
- literal string
- }
- func (s *stringLiteralExpr) emit(gctx *generationContext) {
- gctx.writef("%q", s.literal)
- }
- func (_ *stringLiteralExpr) typ() starlarkType {
- return starlarkTypeString
- }
- 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
- }
- func (s *intLiteralExpr) emit(gctx *generationContext) {
- gctx.writef("%d", s.literal)
- }
- func (_ *intLiteralExpr) typ() starlarkType {
- return starlarkTypeInt
- }
- 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
- }
- 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)
- }
- func (b *boolLiteralExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
- if replacement := transformer(b); replacement != nil {
- return replacement
- } else {
- return b
- }
- }
- type globalsExpr struct {
- }
- func (g *globalsExpr) emit(gctx *generationContext) {
- gctx.write("g")
- }
- func (g *globalsExpr) typ() starlarkType {
- return starlarkTypeUnknown
- }
- func (g *globalsExpr) emitListVarCopy(gctx *generationContext) {
- g.emit(gctx)
- }
- func (g *globalsExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
- if replacement := transformer(g); replacement != nil {
- return replacement
- } else {
- return g
- }
- }
- // 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]
- type interpolateExpr struct {
- chunks []string // string chunks, separated by '%'
- args []starlarkExpr
- }
- func NewInterpolateExpr(parts []starlarkExpr) starlarkExpr {
- result := &interpolateExpr{}
- needString := true
- for _, part := range parts {
- if needString {
- if strLit, ok := part.(*stringLiteralExpr); ok {
- result.chunks = append(result.chunks, strLit.literal)
- } else {
- result.chunks = append(result.chunks, "")
- }
- needString = false
- } else {
- if strLit, ok := part.(*stringLiteralExpr); ok {
- result.chunks[len(result.chunks)-1] += strLit.literal
- } else {
- result.args = append(result.args, part)
- needString = true
- }
- }
- }
- if len(result.chunks) == len(result.args) {
- result.chunks = append(result.chunks, "")
- }
- if len(result.args) == 0 {
- return &stringLiteralExpr{literal: strings.Join(result.chunks, "")}
- }
- return result
- }
- func (xi *interpolateExpr) emit(gctx *generationContext) {
- if len(xi.chunks) != len(xi.args)+1 {
- panic(fmt.Errorf("malformed interpolateExpr: #chunks(%d) != #args(%d)+1",
- len(xi.chunks), len(xi.args)))
- }
- // Generate format as join of chunks, but first escape '%' in them
- format := strings.ReplaceAll(xi.chunks[0], "%", "%%")
- for _, chunk := range xi.chunks[1:] {
- format += "%s" + strings.ReplaceAll(chunk, "%", "%%")
- }
- gctx.writef("%q %% ", format)
- emitArg := func(arg starlarkExpr) {
- if arg.typ() == starlarkTypeList {
- gctx.write(`" ".join(`)
- arg.emit(gctx)
- gctx.write(`)`)
- } else {
- arg.emit(gctx)
- }
- }
- if len(xi.args) == 1 {
- emitArg(xi.args[0])
- } else {
- sep := "("
- for _, arg := range xi.args {
- gctx.write(sep)
- emitArg(arg)
- sep = ", "
- }
- gctx.write(")")
- }
- }
- func (_ *interpolateExpr) typ() starlarkType {
- return starlarkTypeString
- }
- func (xi *interpolateExpr) emitListVarCopy(gctx *generationContext) {
- xi.emit(gctx)
- }
- func (xi *interpolateExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
- for i := range xi.args {
- xi.args[i] = xi.args[i].transform(transformer)
- }
- if replacement := transformer(xi); replacement != nil {
- return replacement
- } else {
- return xi
- }
- }
- type variableRefExpr struct {
- ref variable
- }
- func NewVariableRefExpr(ref variable) starlarkExpr {
- if predefined, ok := ref.(*predefinedVariable); ok {
- return predefined.value
- }
- return &variableRefExpr{ref}
- }
- func (v *variableRefExpr) emit(gctx *generationContext) {
- v.ref.emitGet(gctx)
- }
- func (v *variableRefExpr) typ() starlarkType {
- return v.ref.valueType()
- }
- func (v *variableRefExpr) emitListVarCopy(gctx *generationContext) {
- v.emit(gctx)
- if v.typ() == starlarkTypeList {
- gctx.write("[:]") // this will copy the list
- }
- }
- 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
- }
- func (s *toStringExpr) emit(ctx *generationContext) {
- switch s.expr.typ() {
- case starlarkTypeString, starlarkTypeUnknown:
- // Assume unknown types are strings already.
- s.expr.emit(ctx)
- case starlarkTypeList:
- ctx.write(`" ".join(`)
- s.expr.emit(ctx)
- ctx.write(")")
- case starlarkTypeInt:
- ctx.write(`("%d" % (`)
- s.expr.emit(ctx)
- ctx.write("))")
- case starlarkTypeBool:
- ctx.write(`("true" if (`)
- s.expr.emit(ctx)
- ctx.write(`) else "")`)
- case starlarkTypeVoid:
- ctx.write(`""`)
- default:
- panic("Unknown starlark type!")
- }
- }
- func (s *toStringExpr) typ() starlarkType {
- return starlarkTypeString
- }
- 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
- }
- func (n *notExpr) emit(ctx *generationContext) {
- ctx.write("not ")
- n.expr.emit(ctx)
- }
- func (_ *notExpr) typ() starlarkType {
- return starlarkTypeBool
- }
- 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 !=
- }
- func (eq *eqExpr) emit(gctx *generationContext) {
- if eq.left.typ() != eq.right.typ() {
- eq.left = &toStringExpr{expr: eq.left}
- eq.right = &toStringExpr{expr: eq.right}
- }
- // General case
- eq.left.emit(gctx)
- if eq.isEq {
- gctx.write(" == ")
- } else {
- gctx.write(" != ")
- }
- eq.right.emit(gctx)
- }
- func (_ *eqExpr) typ() starlarkType {
- return starlarkTypeBool
- }
- 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
- }
- }
- type listExpr struct {
- items []starlarkExpr
- }
- func (l *listExpr) emit(gctx *generationContext) {
- if !gctx.inAssignment || len(l.items) < 2 {
- gctx.write("[")
- sep := ""
- for _, item := range l.items {
- gctx.write(sep)
- item.emit(gctx)
- sep = ", "
- }
- gctx.write("]")
- return
- }
- gctx.write("[")
- gctx.indentLevel += 2
- for _, item := range l.items {
- gctx.newLine()
- item.emit(gctx)
- gctx.write(",")
- }
- gctx.indentLevel -= 2
- gctx.newLine()
- gctx.write("]")
- }
- func (_ *listExpr) typ() starlarkType {
- return starlarkTypeList
- }
- 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 {
- v.items = append(v.items, &stringLiteralExpr{item})
- }
- return &v
- }
- // concatExpr generates expr1 + expr2 + ... + exprN in Starlark.
- type concatExpr struct {
- items []starlarkExpr
- }
- func (c *concatExpr) emit(gctx *generationContext) {
- if len(c.items) == 1 {
- c.items[0].emit(gctx)
- return
- }
- if !gctx.inAssignment {
- c.items[0].emit(gctx)
- for _, item := range c.items[1:] {
- gctx.write(" + ")
- item.emit(gctx)
- }
- return
- }
- gctx.write("(")
- c.items[0].emit(gctx)
- gctx.indentLevel += 2
- for _, item := range c.items[1:] {
- gctx.write(" +")
- gctx.newLine()
- item.emit(gctx)
- }
- gctx.write(")")
- gctx.indentLevel -= 2
- }
- func (_ *concatExpr) typ() starlarkType {
- return starlarkTypeList
- }
- 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
- list starlarkExpr
- isNot bool
- }
- func (i *inExpr) emit(gctx *generationContext) {
- i.expr.emit(gctx)
- if i.isNot {
- gctx.write(" not in ")
- } else {
- gctx.write(" in ")
- }
- i.list.emit(gctx)
- }
- func (_ *inExpr) typ() starlarkType {
- return starlarkTypeBool
- }
- 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) {
- ix.array.emit(gctx)
- gctx.write("[")
- ix.index.emit(gctx)
- gctx.write("]")
- }
- func (ix *indexExpr) typ() starlarkType {
- return starlarkTypeString
- }
- 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
- args []starlarkExpr
- returnType starlarkType
- }
- func (cx *callExpr) emit(gctx *generationContext) {
- if cx.object != nil {
- gctx.write("(")
- cx.object.emit(gctx)
- gctx.write(")")
- gctx.write(".", cx.name, "(")
- } else {
- gctx.write(cx.name, "(")
- }
- sep := ""
- for _, arg := range cx.args {
- gctx.write(sep)
- arg.emit(gctx)
- sep = ", "
- }
- gctx.write(")")
- }
- func (cx *callExpr) typ() starlarkType {
- return cx.returnType
- }
- 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)
- }
- for i := range cx.args {
- cx.args[i] = cx.args[i].transform(transformer)
- }
- if replacement := transformer(cx); replacement != nil {
- return replacement
- } else {
- return cx
- }
- }
- type ifExpr struct {
- condition starlarkExpr
- ifTrue starlarkExpr
- ifFalse starlarkExpr
- }
- 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)
- }
- 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) 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) 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 binaryOpExpr struct {
- left, right starlarkExpr
- op string
- returnType starlarkType
- }
- func (b *binaryOpExpr) emit(gctx *generationContext) {
- b.left.emit(gctx)
- gctx.write(" " + b.op + " ")
- b.right.emit(gctx)
- }
- func (b *binaryOpExpr) typ() starlarkType {
- return b.returnType
- }
- func (b *binaryOpExpr) emitListVarCopy(gctx *generationContext) {
- b.emit(gctx)
- }
- func (b *binaryOpExpr) transform(transformer func(expr starlarkExpr) starlarkExpr) starlarkExpr {
- b.left = b.left.transform(transformer)
- b.right = b.right.transform(transformer)
- if replacement := transformer(b); replacement != nil {
- return replacement
- } else {
- return b
- }
- }
- type badExpr struct {
- errorLocation ErrorLocation
- message string
- }
- func (b *badExpr) emit(gctx *generationContext) {
- gctx.emitConversionError(b.errorLocation, b.message)
- }
- func (_ *badExpr) typ() starlarkType {
- return starlarkTypeUnknown
- }
- func (b *badExpr) emitListVarCopy(gctx *generationContext) {
- b.emit(gctx)
- }
- 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))
- }
- return expr
- }
- 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 ¬Expr{expr: expr}
- }
- default:
- return ¬Expr{expr: expr}
- }
- }
|