From 4bd9dcb8559fa1c905d9cb268a74f40d038e03be Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Fri, 5 Apr 2019 10:33:56 -0400 Subject: [PATCH] github.com/bazelbuild/buildtools v0.0.0-20180226164855-80c7f0d45d7e Used only by github.com/bazelbuild/bazel-gazelle, expecting 80c7f0d45d7e --- go.mod | 2 +- go.sum | 4 +- .../buildtools/api_proto/api.gen.pb.go | 7 +- .../buildtools/build/build_defs.bzl | 2 +- .../bazelbuild/buildtools/build/lex.go | 328 ++++--- .../bazelbuild/buildtools/build/parse.y | 430 +++++--- .../bazelbuild/buildtools/build/parse.y.go | 923 +++++++++++------- .../bazelbuild/buildtools/build/print.go | 147 ++- .../bazelbuild/buildtools/build/rule.go | 71 +- .../bazelbuild/buildtools/build/syntax.go | 100 +- .../bazelbuild/buildtools/build/walk.go | 11 +- .../buildtools/build_proto/build.gen.pb.go | 3 +- .../bazelbuild/buildtools/buildozer/README.md | 11 + .../bazelbuild/buildtools/buildozer/main.go | 12 +- .../bazelbuild/buildtools/edit/BUILD | 1 + .../bazelbuild/buildtools/edit/buildozer.go | 153 +-- .../bazelbuild/buildtools/edit/edit.go | 95 +- .../bazelbuild/buildtools/edit/types.go | 10 + .../buildtools/tables/jsonparser.go | 5 +- .../bazelbuild/buildtools/tables/tables.go | 15 +- vendor/modules.txt | 2 +- 21 files changed, 1566 insertions(+), 766 deletions(-) diff --git a/go.mod b/go.mod index a1a5a691c51..8b925f63dfc 100644 --- a/go.mod +++ b/go.mod @@ -234,7 +234,7 @@ replace ( github.com/auth0/go-jwt-middleware => github.com/auth0/go-jwt-middleware v0.0.0-20170425171159-5493cabe49f7 github.com/aws/aws-sdk-go => github.com/aws/aws-sdk-go v1.16.26 github.com/bazelbuild/bazel-gazelle => github.com/bazelbuild/bazel-gazelle v0.0.0-20181012220611-c728ce9f663e - github.com/bazelbuild/buildtools => github.com/bazelbuild/buildtools v0.0.0-20171220125010-1a9c38e0df93 + github.com/bazelbuild/buildtools => github.com/bazelbuild/buildtools v0.0.0-20180226164855-80c7f0d45d7e github.com/beorn7/perks => github.com/beorn7/perks v0.0.0-20160229213445-3ac7bf7a47d1 github.com/blang/semver => github.com/blang/semver v3.5.0+incompatible github.com/boltdb/bolt => github.com/boltdb/bolt v1.3.1 diff --git a/go.sum b/go.sum index 4be74c072d0..3d5b63ae111 100644 --- a/go.sum +++ b/go.sum @@ -44,8 +44,8 @@ github.com/aws/aws-sdk-go v1.16.26 h1:GWkl3rkRO/JGRTWoLLIqwf7AWC4/W/1hMOUZqmX0js github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/bazelbuild/bazel-gazelle v0.0.0-20181012220611-c728ce9f663e h1:k7E/Rdb9kYVDDrdCX46/GLgHhbxBs4BQz7+FDRf8lcg= github.com/bazelbuild/bazel-gazelle v0.0.0-20181012220611-c728ce9f663e/go.mod h1:uHBSeeATKpVazAACZBDPL/Nk/UhQDDsJWDlqYJo8/Us= -github.com/bazelbuild/buildtools v0.0.0-20171220125010-1a9c38e0df93 h1:HOcA9ovaT+3lN0RGVE8NpLHLU2poukBPujkIQOGI40U= -github.com/bazelbuild/buildtools v0.0.0-20171220125010-1a9c38e0df93/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU= +github.com/bazelbuild/buildtools v0.0.0-20180226164855-80c7f0d45d7e h1:VuTBHPJNCQ88Okm9ld5SyLCvU50soWJYQYjQFdcDxew= +github.com/bazelbuild/buildtools v0.0.0-20180226164855-80c7f0d45d7e/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU= github.com/beorn7/perks v0.0.0-20160229213445-3ac7bf7a47d1 h1:OnJHjoVbY69GG4gclp0ngXfywigLhR6rrgUxmxQRWO4= github.com/beorn7/perks v0.0.0-20160229213445-3ac7bf7a47d1/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs= diff --git a/vendor/github.com/bazelbuild/buildtools/api_proto/api.gen.pb.go b/vendor/github.com/bazelbuild/buildtools/api_proto/api.gen.pb.go index d060daca5a7..1befa695ef7 100644 --- a/vendor/github.com/bazelbuild/buildtools/api_proto/api.gen.pb.go +++ b/vendor/github.com/bazelbuild/buildtools/api_proto/api.gen.pb.go @@ -1,6 +1,5 @@ -// Code generated by protoc-gen-go. +// Code generated by protoc-gen-go. DO NOT EDIT. // source: api_proto/api.proto -// DO NOT EDIT! /* Package devtools_buildozer is a generated protocol buffer package. @@ -101,9 +100,7 @@ func (m *Output_Record_Field) String() string { return proto.CompactT func (*Output_Record_Field) ProtoMessage() {} func (*Output_Record_Field) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0, 0} } -type isOutput_Record_Field_Value interface { - isOutput_Record_Field_Value() -} +type isOutput_Record_Field_Value interface{ isOutput_Record_Field_Value() } type Output_Record_Field_Text struct { Text string `protobuf:"bytes,1,opt,name=text,oneof"` diff --git a/vendor/github.com/bazelbuild/buildtools/build/build_defs.bzl b/vendor/github.com/bazelbuild/buildtools/build/build_defs.bzl index e4b5aacdd47..a906ab9d577 100644 --- a/vendor/github.com/bazelbuild/buildtools/build/build_defs.bzl +++ b/vendor/github.com/bazelbuild/buildtools/build/build_defs.bzl @@ -49,4 +49,4 @@ def genfile_check_test(src, gen): data = [src, gen], args = ["$(location " + src + ")", "$(location " + gen + ")"], ) - + diff --git a/vendor/github.com/bazelbuild/buildtools/build/lex.go b/vendor/github.com/bazelbuild/buildtools/build/lex.go index 9df2cf706ac..adc9e1dfc9d 100644 --- a/vendor/github.com/bazelbuild/buildtools/build/lex.go +++ b/vendor/github.com/bazelbuild/buildtools/build/lex.go @@ -22,6 +22,8 @@ import ( "fmt" "strings" "unicode/utf8" + + "github.com/bazelbuild/buildtools/tables" ) // Parse parses the input data and returns the corresponding parse tree. @@ -35,15 +37,19 @@ func Parse(filename string, data []byte) (*File, error) { // An input represents a single input file being parsed. type input struct { // Lexing state. - filename string // name of input file, for errors - complete []byte // entire input - remaining []byte // remaining input - token []byte // token being scanned - lastToken string // most recently returned token, for error messages - pos Position // current input position - comments []Comment // accumulated comments - endRule int // position of end of current rule - depth int // nesting of [ ] { } ( ) + filename string // name of input file, for errors + complete []byte // entire input + remaining []byte // remaining input + token []byte // token being scanned + lastToken string // most recently returned token, for error messages + pos Position // current input position + lineComments []Comment // accumulated line comments + suffixComments []Comment // accumulated suffix comments + endStmt int // position of the end of the current statement + depth int // nesting of [ ] { } ( ) + cleanLine bool // true if the current line only contains whitespace before the current position + indent int // current line indentation in spaces + indents []int // stack of indentation levels in spaces // Parser state. file *File // returned top-level syntax tree @@ -55,14 +61,26 @@ type input struct { } func newInput(filename string, data []byte) *input { + // The syntax requires that each simple statement ends with '\n', however it's optional at EOF. + // If `data` doesn't end with '\n' we add it here to keep parser simple. + // It shouldn't affect neither the parsed tree nor its formatting. + data = append(data, '\n') + return &input{ filename: filename, complete: data, remaining: data, pos: Position{Line: 1, LineRune: 1, Byte: 0}, + cleanLine: true, + indents: []int{0}, + endStmt: -1, // -1 denotes it's not inside a statement } } +func (in *input) currentIndent() int { + return in.indents[len(in.indents)-1] +} + // parse parses the input file. func (in *input) parse() (f *File, err error) { // The parser panics for both routine errors like syntax errors @@ -169,29 +187,23 @@ func (in *input) Lex(val *yySymType) int { // Skip past spaces, stopping at non-space or EOF. countNL := 0 // number of newlines we've skipped past for !in.eof() { - // The parser does not track indentation, because for the most part - // BUILD expressions don't care about how they are indented. - // However, we do need to be able to distinguish + // If a single statement is split into multiple lines, we don't need + // to track indentations and unindentations within these lines. For example: // - // x = y[0] + // def f( + // # This indentation should be ignored + // x): + // # This unindentation should be ignored + // # Actual indentation is from 0 to 2 spaces here + // return x // - // from the occasional + // To handle this case, when we reach the beginning of a statement we scan forward to see where + // it should end and record the number of input bytes remaining at that endpoint. // - // x = y - // [0] - // - // To handle this one case, when we reach the beginning of a - // top-level BUILD expression, we scan forward to see where - // it should end and record the number of input bytes remaining - // at that endpoint. When we reach that point in the input, we - // insert an implicit semicolon to force the two expressions - // to stay separate. - // - if in.endRule != 0 && len(in.remaining) == in.endRule { - in.endRule = 0 - in.lastToken = "implicit ;" - val.tok = ";" - return ';' + // If --format_bzl is set to false, top level blocks (e.g. an entire function definition) + // is considered as a single statement. + if in.endStmt != -1 && len(in.remaining) == in.endStmt { + in.endStmt = -1 } // Skip over spaces. Count newlines so we can give the parser @@ -199,15 +211,19 @@ func (in *input) Lex(val *yySymType) int { // for top-level comment assignment. c := in.peekRune() if c == ' ' || c == '\t' || c == '\r' || c == '\n' { - if c == '\n' && in.endRule == 0 { - // Not in a rule. Tell parser about top-level blank line. - in.startToken(val) - in.readRune() - in.endToken(val) - return '\n' - } if c == '\n' { + in.indent = 0 + in.cleanLine = true + if in.endStmt == -1 { + // Not in a statememt. Tell parser about top-level blank line. + in.startToken(val) + in.readRune() + in.endToken(val) + return '\n' + } countNL++ + } else if c == ' ' && in.cleanLine { + in.indent++ } in.readRune() continue @@ -215,6 +231,11 @@ func (in *input) Lex(val *yySymType) int { // Comment runs to end of line. if c == '#' { + // If a line contains just a comment its indentation level doesn't matter. + // Reset it to zero. + in.indent = 0 + in.cleanLine = true + // Is this comment the only thing on its line? // Find the last \n before this # and see if it's all // spaces from there to here. @@ -231,10 +252,12 @@ func (in *input) Lex(val *yySymType) int { isSuffix = false } - // Consume comment. + // Consume comment without the \n it ends with. in.startToken(val) - for len(in.remaining) > 0 && in.readRune() != '\n' { + for len(in.remaining) > 0 && in.peekRune() != '\n' { + in.readRune() } + in.endToken(val) val.tok = strings.TrimRight(val.tok, "\n") @@ -243,22 +266,27 @@ func (in *input) Lex(val *yySymType) int { // If we are at top level (not in a rule), hand the comment to // the parser as a _COMMENT token. The grammar is written // to handle top-level comments itself. - if in.endRule == 0 { - // Not in a rule. Tell parser about top-level comment. + if in.endStmt == -1 { + // Not in a statement. Tell parser about top-level comment. return _COMMENT } // Otherwise, save comment for later attachment to syntax tree. if countNL > 1 { - in.comments = append(in.comments, Comment{val.pos, "", false}) + in.lineComments = append(in.lineComments, Comment{val.pos, ""}) } - in.comments = append(in.comments, Comment{val.pos, val.tok, isSuffix}) - countNL = 1 + if isSuffix { + in.suffixComments = append(in.suffixComments, Comment{val.pos, val.tok}) + } else { + in.lineComments = append(in.lineComments, Comment{val.pos, val.tok}) + } + countNL = 0 continue } if c == '\\' && len(in.remaining) >= 2 && in.remaining[1] == '\n' { - // We can ignore a trailing \ at end of line. + // We can ignore a trailing \ at end of line together with the \n. + in.readRune() in.readRune() continue } @@ -267,6 +295,41 @@ func (in *input) Lex(val *yySymType) int { break } + // Check for changes in indentation + // Skip if --format_bzl is set to false, if we're inside a statement, or if there were non-space + // characters before in the current line. + if tables.FormatBzlFiles && in.endStmt == -1 && in.cleanLine { + if in.indent > in.currentIndent() { + // A new indentation block starts + in.indents = append(in.indents, in.indent) + in.lastToken = "indent" + in.cleanLine = false + return _INDENT + } else if in.indent < in.currentIndent() { + // An indentation block ends + in.indents = in.indents[:len(in.indents)-1] + + // It's a syntax error if the current line indentation level in now greater than + // currentIndent(), should be either equal (a parent block continues) or still less + // (need to unindent more). + if in.indent > in.currentIndent() { + in.pos = val.pos + in.Error("unexpected indentation") + } + in.lastToken = "unindent" + return _UNINDENT + } + } + + in.cleanLine = false + + // If the file ends with an indented block, return the corresponding amounts of unindents. + if in.eof() && in.currentIndent() > 0 { + in.indents = in.indents[:len(in.indents)-1] + in.lastToken = "unindent" + return _UNINDENT + } + // Found the beginning of the next token. in.startToken(val) defer in.endToken(val) @@ -277,16 +340,9 @@ func (in *input) Lex(val *yySymType) int { return _EOF } - // If endRule is 0, we need to recompute where the end - // of the next rule (Python expression) is, so that we can - // generate a virtual end-of-rule semicolon (see above). - if in.endRule == 0 { - in.endRule = len(in.skipPython(in.remaining)) - if in.endRule == 0 { - // skipPython got confused. - // No more virtual semicolons. - in.endRule = -1 - } + // If endStmt is 0, we need to recompute where the end of the next statement is. + if in.endStmt == -1 { + in.endStmt = len(in.skipStmt(in.remaining)) } // Punctuation tokens. @@ -301,12 +357,17 @@ func (in *input) Lex(val *yySymType) int { in.readRune() return c - case '.', '-', '%', ':', ';', ',', '/', '*': // single-char tokens + case '.', ':', ';', ',': // single-char tokens in.readRune() return c - case '<', '>', '=', '!', '+': // possibly followed by = + case '<', '>', '=', '!', '+', '-', '*', '/', '%': // possibly followed by = in.readRune() + if c == '/' && in.peekRune() == '/' { + // integer division + in.readRune() + } + if in.peekRune() == '=' { in.readRune() switch c { @@ -318,8 +379,8 @@ func (in *input) Lex(val *yySymType) int { return _EQ case '!': return _NE - case '+': - return _ADDEQ + default: + return _AUGM } } return c @@ -395,15 +456,17 @@ func (in *input) Lex(val *yySymType) int { in.Error(fmt.Sprintf("unexpected input character %#q", c)) } - // Look for raw Python block (class, def, if, etc at beginning of line) and pass through. - if in.depth == 0 && in.pos.LineRune == 1 && hasPythonPrefix(in.remaining) { - // Find end of Python block and advance input beyond it. - // Have to loop calling readRune in order to maintain line number info. - rest := in.skipPython(in.remaining) - for len(in.remaining) > len(rest) { - in.readRune() + if !tables.FormatBzlFiles { + // Look for raw Python block (class, def, if, etc at beginning of line) and pass through. + if in.depth == 0 && in.pos.LineRune == 1 && hasPythonPrefix(in.remaining) { + // Find end of Python block and advance input beyond it. + // Have to loop calling readRune in order to maintain line number info. + rest := in.skipStmt(in.remaining) + for len(in.remaining) > len(rest) { + in.readRune() + } + return _PYTHON } - return _PYTHON } // Scan over alphanumeric identifier. @@ -442,11 +505,15 @@ var keywordToken = map[string]int{ "for": _FOR, "if": _IF, "else": _ELSE, + "elif": _ELIF, "in": _IN, "is": _IS, "lambda": _LAMBDA, + "load": _LOAD, "not": _NOT, "or": _OR, + "def": _DEF, + "return": _RETURN, } // Python scanning. @@ -457,6 +524,10 @@ var keywordToken = map[string]int{ // hasPythonPrefix reports whether p begins with a keyword that would // introduce an uninterpreted Python block. func hasPythonPrefix(p []byte) bool { + if tables.FormatBzlFiles { + return false + } + for _, pre := range prefixes { if hasPrefixSpace(p, pre) { return true @@ -474,10 +545,14 @@ var prefixes = []string{ "for", "if", "try", + "else", + "elif", + "except", } // hasPrefixSpace reports whether p begins with pre followed by a space or colon. func hasPrefixSpace(p []byte, pre string) bool { + if len(p) <= len(pre) || p[len(pre)] != ' ' && p[len(pre)] != '\t' && p[len(pre)] != ':' { return false } @@ -489,44 +564,46 @@ func hasPrefixSpace(p []byte, pre string) bool { return true } -func isBlankOrComment(b []byte) bool { +// A utility function for the legacy formatter. +// Returns whether a given code starts with a top-level statement (maybe with some preceeding +// comments and blank lines) +func isOutsideBlock(b []byte) bool { + isBlankLine := true + isComment := false for _, c := range b { - if c == '#' || c == '\n' { - return true - } - if c != ' ' && c != '\t' && c != '\r' { - return false + switch { + case c == ' ' || c == '\t' || c == '\r': + isBlankLine = false + case c == '#': + isBlankLine = false + isComment = true + case c == '\n': + isBlankLine = true + isComment = false + default: + if !isComment { + return isBlankLine + } } } return true } -// hasPythonContinuation reports whether p begins with a keyword that -// continues an uninterpreted Python block. -func hasPythonContinuation(p []byte) bool { - for _, pre := range continuations { - if hasPrefixSpace(p, pre) { - return true - } - } - return false -} - -// These keywords continue uninterpreted Python blocks. -var continuations = []string{ - "except", - "else", -} - -// skipPython returns the data remaining after the uninterpreted -// Python block beginning at p. It does not advance the input position. +// skipStmt returns the data remaining after the statement beginning at p. +// It does not advance the input position. // (The only reason for the input receiver is to be able to call in.Error.) -func (in *input) skipPython(p []byte) []byte { +func (in *input) skipStmt(p []byte) []byte { quote := byte(0) // if non-zero, the kind of quote we're in tripleQuote := false // if true, the quote is a triple quote depth := 0 // nesting depth for ( ) [ ] { } var rest []byte // data after the Python block + defer func() { + if quote != 0 { + in.Error("EOF scanning Python quoted string") + } + }() + // Scan over input one byte at a time until we find // an unindented, non-blank, non-comment line // outside quoted strings and brackets. @@ -559,20 +636,23 @@ func (in *input) skipPython(p []byte) []byte { continue } - if depth == 0 && i > 0 && p[i-1] == '\n' && (i < 2 || p[i-2] != '\\') { + if depth == 0 && i > 0 && p[i] == '\n' && p[i-1] != '\\' { // Possible stopping point. Save the earliest one we find. if rest == nil { rest = p[i:] } - if !isBlankOrComment(p[i:]) { - if !hasPythonContinuation(p[i:]) && c != ' ' && c != '\t' { - // Yes, stop here. - break - } - // Not a stopping point after all. - rest = nil + if tables.FormatBzlFiles { + // In the bzl files mode we only care about the end of the statement, we've found it. + return rest } + // In the legacy mode we need to find where the current block ends + if isOutsideBlock(p[i+1:]) { + return rest + } + // Not a stopping point after all. + rest = nil + } switch c { @@ -581,6 +661,8 @@ func (in *input) skipPython(p []byte) []byte { for i < len(p) && p[i] != '\n' { i++ } + // Rewind 1 position back because \n should be handled at the next iteration + i-- case '(', '[', '{': depth++ @@ -589,9 +671,6 @@ func (in *input) skipPython(p []byte) []byte { depth-- } } - if quote != 0 { - in.Error("EOF scanning Python quoted string") - } return rest } @@ -691,8 +770,9 @@ func (in *input) order(v Expr) { in.order(&v.End) case *SliceExpr: in.order(v.X) - in.order(v.Y) - in.order(v.Z) + in.order(v.From) + in.order(v.To) + in.order(v.Step) case *IndexExpr: in.order(v.X) in.order(v.Y) @@ -701,6 +781,32 @@ func (in *input) order(v Expr) { in.order(name) } in.order(v.Expr) + case *ReturnExpr: + if v.X != nil { + in.order(v.X) + } + case *FuncDef: + for _, x := range v.Args { + in.order(x) + } + for _, x := range v.Body.Statements { + in.order(x) + } + case *ForLoop: + for _, x := range v.LoopVars { + in.order(x) + } + in.order(v.Iterable) + for _, x := range v.Body.Statements { + in.order(x) + } + case *IfElse: + for _, condition := range v.Conditions { + in.order(condition.If) + for _, x := range condition.Then.Statements { + in.order(x) + } + } } if v != nil { in.post = append(in.post, v) @@ -712,17 +818,8 @@ func (in *input) assignComments() { // Generate preorder and postorder lists. in.order(in.file) - // Split into whole-line comments and suffix comments. - var line, suffix []Comment - for _, com := range in.comments { - if com.Suffix { - suffix = append(suffix, com) - } else { - line = append(line, com) - } - } - // Assign line comments to syntax immediately following. + line := in.lineComments for _, x := range in.pre { start, _ := x.Span() xcom := x.Comment() @@ -736,6 +833,7 @@ func (in *input) assignComments() { in.file.After = append(in.file.After, line...) // Assign suffix comments to syntax immediately before. + suffix := in.suffixComments for i := len(in.post) - 1; i >= 0; i-- { x := in.post[i] diff --git a/vendor/github.com/bazelbuild/buildtools/build/parse.y b/vendor/github.com/bazelbuild/buildtools/build/parse.y index b6b30434a42..3f2b05b4ca5 100644 --- a/vendor/github.com/bazelbuild/buildtools/build/parse.y +++ b/vendor/github.com/bazelbuild/buildtools/build/parse.y @@ -31,6 +31,7 @@ package build forsifs []*ForClauseWithIfClausesOpt string *StringExpr strings []*StringExpr + block CodeBlock // supporting information comma Position // position of trailing comma in list, if present @@ -69,7 +70,7 @@ package build // However, we do not want to export them from the Go package // we are creating, so prefix them all with underscores. -%token _ADDEQ // operator += +%token _AUGM // augmented assignment %token _AND // keyword and %token _COMMENT // top-level # comment %token _EOF // end of file @@ -79,34 +80,47 @@ package build %token _IDENT // non-keyword identifier or number %token _IF // keyword if %token _ELSE // keyword else +%token _ELIF // keyword elif %token _IN // keyword in %token _IS // keyword is %token _LAMBDA // keyword lambda +%token _LOAD // keyword load %token _LE // operator <= %token _NE // operator != %token _NOT // keyword not %token _OR // keyword or %token _PYTHON // uninterpreted Python block %token _STRING // quoted string +%token _DEF // keyword def +%token _RETURN // keyword return +%token _INDENT // indentation +%token _UNINDENT // unindentation %type comma_opt %type expr %type expr_opt +%type primary_expr %type exprs %type exprs_opt +%type primary_exprs %type for_clause %type for_clause_with_if_clauses_opt %type for_clauses_with_if_clauses_opt %type ident -%type idents %type if_clauses_opt %type stmts -%type stmt +%type stmt // a simple_stmt or a for/if/def block +%type block_stmt // a single for/if/def statement +%type if_else_block // a single if-else statement +%type simple_stmt // One or many small_stmts on one line, e.g. 'a = f(x); return str(a)' +%type small_stmt // A single statement, e.g. 'a = f(x)' +%type small_stmts_continuation // A sequence of `';' small_stmt` %type keyvalue %type keyvalues %type keyvalues_no_comma %type string %type strings +%type suite // Operator precedence. // Operators listed lower in the table bind tighter. @@ -120,25 +134,25 @@ package build %left '\n' %left _ASSERT -// '=' and '+=' have the lowest precedence +// '=' and augmented assignments have the lowest precedence // e.g. "x = a if c > 0 else 'bar'" // followed by // 'if' and 'else' which have lower precedence than all other operators. // e.g. "a, b if c > 0 else 'foo'" is either a tuple of (a,b) or 'foo' // and not a tuple of "(a, (b if ... ))" -%left '=' _ADDEQ -%left _IF _ELSE -%left ',' -%left ':' -%left _IN _NOT _IS -%left _OR -%left _AND -%left '<' '>' _EQ _NE _LE _GE -%left '+' '-' -%left '*' '/' '%' -%left '.' '[' '(' -%right _UNARY -%left _STRING +%left '=' _AUGM +%left _IF _ELSE _ELIF +%left ',' +%left ':' +%left _IN _NOT _IS +%left _OR +%left _AND +%left '<' '>' _EQ _NE _LE _GE +%left '+' '-' +%left '*' '/' '%' +%left '.' '[' '(' +%right _UNARY +%left _STRING %% @@ -155,26 +169,46 @@ file: return 0 } +suite: + '\n' _INDENT stmts _UNINDENT + { + $$ = CodeBlock{ + Start: $2, + Statements: $3, + End: End{Pos: $4}, + } + } +| simple_stmt + { + // simple_stmt is never empty + start, _ := $1[0].Span() + _, end := $1[len($1)-1].Span() + $$ = CodeBlock{ + Start: start, + Statements: $1, + End: End{Pos: end}, + } + } + stmts: { $$ = nil $$ = nil } -| stmts stmt comma_opt semi_opt +| stmts stmt { // If this statement follows a comment block, // attach the comments to the statement. if cb, ok := $1.(*CommentBlock); ok { - $$ = $1 - $$[len($1)-1] = $2 - $2.Comment().Before = cb.After - $$ = $2 + $$ = append($1[:len($1)-1], $2...) + $2[0].Comment().Before = cb.After + $$ = $2[len($2)-1] break } // Otherwise add to list. - $$ = append($1, $2) - $$ = $2 + $$ = append($1, $2...) + $$ = $2[len($2)-1] // Consider this input: // @@ -187,7 +221,8 @@ stmts: // for baz() instead. if x := $1; x != nil { com := x.Comment() - $2.Comment().Before = com.After + // stmt is never empty + $2[0].Comment().Before = com.After com.After = nil } } @@ -197,7 +232,7 @@ stmts: $$ = $1 $$ = nil } -| stmts _COMMENT +| stmts _COMMENT '\n' { $$ = $1 $$ = $1 @@ -211,24 +246,209 @@ stmts: } stmt: + simple_stmt + { + $$ = $1 + } +| block_stmt + { + $$ = []Expr{$1} + } + +block_stmt: + _DEF _IDENT '(' exprs_opt ')' ':' suite + { + $$ = &FuncDef{ + Start: $1, + Name: $2, + ListStart: $3, + Args: $4, + Body: $7, + End: $7.End, + ForceCompact: forceCompact($3, $4, $5), + ForceMultiLine: forceMultiLine($3, $4, $5), + } + } +| _FOR primary_exprs _IN expr ':' suite + { + $$ = &ForLoop{ + Start: $1, + LoopVars: $2, + Iterable: $4, + Body: $6, + End: $6.End, + } + } +| if_else_block + { + $$ = $1 + } + +if_else_block: + _IF expr ':' suite + { + $$ = &IfElse{ + Start: $1, + Conditions: []Condition{ + Condition{ + If: $2, + Then: $4, + }, + }, + End: $4.End, + } + } +| if_else_block elif expr ':' suite + { + block := $1.(*IfElse) + block.Conditions = append(block.Conditions, Condition{ + If: $3, + Then: $5, + }) + block.End = $5.End + $$ = block + } +| if_else_block _ELSE ':' suite + { + block := $1.(*IfElse) + block.Conditions = append(block.Conditions, Condition{ + Then: $4, + }) + block.End = $4.End + $$ = block + } + +elif: + _ELSE _IF +| _ELIF + +simple_stmt: + small_stmt small_stmts_continuation semi_opt '\n' + { + $$ = append([]Expr{$1}, $2...) + $$ = $$[len($$)-1] + } + +small_stmts_continuation: + { + $$ = []Expr{} + } +| small_stmts_continuation ';' small_stmt + { + $$ = append($1, $3) + } + +small_stmt: expr %prec ShiftInstead +| _RETURN expr + { + _, end := $2.Span() + $$ = &ReturnExpr{ + X: $2, + End: end, + } + } +| _RETURN + { + $$ = &ReturnExpr{End: $1} + } | _PYTHON { $$ = &PythonBlock{Start: $1, Token: $1} } semi_opt: -| semi_opt ';' +| ';' -expr: +primary_expr: ident +| primary_expr '.' _IDENT + { + $$ = &DotExpr{ + X: $1, + Dot: $2, + NamePos: $3, + Name: $3, + } + } +| _LOAD '(' exprs_opt ')' + { + $$ = &CallExpr{ + X: &LiteralExpr{Start: $1, Token: "load"}, + ListStart: $2, + List: $3, + End: End{Pos: $4}, + ForceCompact: forceCompact($2, $3, $4), + ForceMultiLine: forceMultiLine($2, $3, $4), + } + } +| primary_expr '(' exprs_opt ')' + { + $$ = &CallExpr{ + X: $1, + ListStart: $2, + List: $3, + End: End{Pos: $4}, + ForceCompact: forceCompact($2, $3, $4), + ForceMultiLine: forceMultiLine($2, $3, $4), + } + } +| primary_expr '[' expr ']' + { + $$ = &IndexExpr{ + X: $1, + IndexStart: $2, + Y: $3, + End: $4, + } + } +| primary_expr '[' expr_opt ':' expr_opt ']' + { + $$ = &SliceExpr{ + X: $1, + SliceStart: $2, + From: $3, + FirstColon: $4, + To: $5, + End: $6, + } + } +| primary_expr '[' expr_opt ':' expr_opt ':' expr_opt ']' + { + $$ = &SliceExpr{ + X: $1, + SliceStart: $2, + From: $3, + FirstColon: $4, + To: $5, + SecondColon: $6, + Step: $7, + End: $8, + } + } +| primary_expr '(' expr for_clauses_with_if_clauses_opt ')' + { + $$ = &CallExpr{ + X: $1, + ListStart: $2, + List: []Expr{ + &ListForExpr{ + Brack: "", + Start: $2, + X: $3, + For: $4, + End: End{Pos: $5}, + }, + }, + End: End{Pos: $5}, + } + } | strings %prec ShiftInstead { if len($1) == 1 { $$ = $1[0] break } - $$ = $1[0] for _, x := range $1[1:] { _, end := $$.Span() @@ -322,63 +542,10 @@ expr: } } } -| expr '.' _IDENT - { - $$ = &DotExpr{ - X: $1, - Dot: $2, - NamePos: $3, - Name: $3, - } - } -| expr '(' exprs_opt ')' - { - $$ = &CallExpr{ - X: $1, - ListStart: $2, - List: $3, - End: End{Pos: $4}, - ForceCompact: forceCompact($2, $3, $4), - ForceMultiLine: forceMultiLine($2, $3, $4), - } - } -| expr '(' expr for_clauses_with_if_clauses_opt ')' - { - $$ = &CallExpr{ - X: $1, - ListStart: $2, - List: []Expr{ - &ListForExpr{ - Brack: "", - Start: $2, - X: $3, - For: $4, - End: End{Pos: $5}, - }, - }, - End: End{Pos: $5}, - } - } -| expr '[' expr ']' - { - $$ = &IndexExpr{ - X: $1, - IndexStart: $2, - Y: $3, - End: $4, - } - } -| expr '[' expr_opt ':' expr_opt ']' - { - $$ = &SliceExpr{ - X: $1, - SliceStart: $2, - Y: $3, - Colon: $4, - Z: $5, - End: $6, - } - } +| '-' primary_expr %prec _UNARY { $$ = unary($1, $1, $2) } + +expr: + primary_expr | _LAMBDA exprs ':' expr { $$ = &LambdaExpr{ @@ -388,7 +555,6 @@ expr: Expr: $4, } } -| '-' expr %prec _UNARY { $$ = unary($1, $1, $2) } | _NOT expr %prec _UNARY { $$ = unary($1, $1, $2) } | '*' expr %prec _UNARY { $$ = unary($1, $1, $2) } | expr '*' expr { $$ = binary($1, $2, $2, $3) } @@ -403,7 +569,7 @@ expr: | expr _NE expr { $$ = binary($1, $2, $2, $3) } | expr _GE expr { $$ = binary($1, $2, $2, $3) } | expr '=' expr { $$ = binary($1, $2, $2, $3) } -| expr _ADDEQ expr { $$ = binary($1, $2, $2, $3) } +| expr _AUGM expr { $$ = binary($1, $2, $2, $3) } | expr _IN expr { $$ = binary($1, $2, $2, $3) } | expr _NOT _IN expr { $$ = binary($1, $2, "not in", $4) } | expr _OR expr { $$ = binary($1, $2, $2, $3) } @@ -416,15 +582,15 @@ expr: $$ = binary($1, $2, $2, $3) } } -| expr _IF expr _ELSE expr +| expr _IF expr _ELSE expr { - $$ = &ConditionalExpr{ - Then: $1, - IfStart: $2, - Test: $3, - ElseStart: $4, - Else: $5, - } + $$ = &ConditionalExpr{ + Then: $1, + IfStart: $2, + Test: $3, + ElseStart: $4, + Else: $5, + } } expr_opt: @@ -491,6 +657,16 @@ exprs_opt: $$, $$ = $1, $2 } +primary_exprs: + primary_expr + { + $$ = []Expr{$1} + } +| primary_exprs ',' primary_expr + { + $$ = append($1, $3) + } + string: _STRING { @@ -519,18 +695,8 @@ ident: $$ = &LiteralExpr{Start: $1, Token: $1} } -idents: - ident - { - $$ = []Expr{$1} - } -| idents ',' ident - { - $$ = append($1, $3) - } - for_clause: - _FOR idents _IN expr + _FOR primary_exprs _IN expr { $$ = &ForClause{ For: $1, @@ -539,15 +705,6 @@ for_clause: Expr: $4, } } -| _FOR '(' idents ')' _IN expr - { - $$ = &ForClause{ - For: $1, - Var: $3, - In: $5, - Expr: $6, - } - } for_clause_with_if_clauses_opt: for_clause if_clauses_opt { @@ -558,13 +715,13 @@ for_clause_with_if_clauses_opt: } for_clauses_with_if_clauses_opt: - for_clause_with_if_clauses_opt - { - $$ = []*ForClauseWithIfClausesOpt{$1} - } + for_clause_with_if_clauses_opt + { + $$ = []*ForClauseWithIfClausesOpt{$1} + } | for_clauses_with_if_clauses_opt for_clause_with_if_clauses_opt { - $$ = append($1, $2) - } + $$ = append($1, $2) + } if_clauses_opt: { @@ -606,6 +763,30 @@ func binary(x Expr, pos Position, op string, y Expr) Expr { } } +// isSimpleExpression returns whether an expression is simple and allowed to exist in +// compact forms of sequences. +// The formal criteria are the following: an expression is considered simple if it's +// a literal (variable, string or a number), a literal with a unary operator or an empty sequence. +func isSimpleExpression(expr *Expr) bool { + switch x := (*expr).(type) { + case *LiteralExpr, *StringExpr: + return true + case *UnaryExpr: + _, ok := x.X.(*LiteralExpr) + return ok + case *ListExpr: + return len(x.List) == 0 + case *TupleExpr: + return len(x.List) == 0 + case *DictExpr: + return len(x.List) == 0 + case *SetExpr: + return len(x.List) == 0 + default: + return false + } +} + // forceCompact returns the setting for the ForceCompact field for a call or tuple. // // NOTE 1: The field is called ForceCompact, not ForceSingleLine, @@ -654,10 +835,7 @@ func forceCompact(start Position, list []Expr, end Position) bool { return false } line = end.Line - switch x.(type) { - case *LiteralExpr, *StringExpr, *UnaryExpr: - // ok - default: + if !isSimpleExpression(&x) { return false } } diff --git a/vendor/github.com/bazelbuild/buildtools/build/parse.y.go b/vendor/github.com/bazelbuild/buildtools/build/parse.y.go index d392b2c60bb..55a59ea80d1 100644 --- a/vendor/github.com/bazelbuild/buildtools/build/parse.y.go +++ b/vendor/github.com/bazelbuild/buildtools/build/parse.y.go @@ -22,13 +22,14 @@ type yySymType struct { forsifs []*ForClauseWithIfClausesOpt string *StringExpr strings []*StringExpr + block CodeBlock // supporting information comma Position // position of trailing comma in list, if present lastRule Expr // most recent rule, to attach line comments to } -const _ADDEQ = 57346 +const _AUGM = 57346 const _AND = 57347 const _COMMENT = 57348 const _EOF = 57349 @@ -38,18 +39,24 @@ const _GE = 57352 const _IDENT = 57353 const _IF = 57354 const _ELSE = 57355 -const _IN = 57356 -const _IS = 57357 -const _LAMBDA = 57358 -const _LE = 57359 -const _NE = 57360 -const _NOT = 57361 -const _OR = 57362 -const _PYTHON = 57363 -const _STRING = 57364 -const ShiftInstead = 57365 -const _ASSERT = 57366 -const _UNARY = 57367 +const _ELIF = 57356 +const _IN = 57357 +const _IS = 57358 +const _LAMBDA = 57359 +const _LOAD = 57360 +const _LE = 57361 +const _NE = 57362 +const _NOT = 57363 +const _OR = 57364 +const _PYTHON = 57365 +const _STRING = 57366 +const _DEF = 57367 +const _RETURN = 57368 +const _INDENT = 57369 +const _UNINDENT = 57370 +const ShiftInstead = 57371 +const _ASSERT = 57372 +const _UNARY = 57373 var yyToknames = [...]string{ "$end", @@ -72,7 +79,7 @@ var yyToknames = [...]string{ "']'", "'{'", "'}'", - "_ADDEQ", + "_AUGM", "_AND", "_COMMENT", "_EOF", @@ -82,15 +89,21 @@ var yyToknames = [...]string{ "_IDENT", "_IF", "_ELSE", + "_ELIF", "_IN", "_IS", "_LAMBDA", + "_LOAD", "_LE", "_NE", "_NOT", "_OR", "_PYTHON", "_STRING", + "_DEF", + "_RETURN", + "_INDENT", + "_UNINDENT", "ShiftInstead", "'\\n'", "_ASSERT", @@ -103,7 +116,7 @@ const yyEofCode = 1 const yyErrCode = 2 const yyInitialStackSize = 16 -//line build/parse.y:581 +//line build/parse.y:738 // Go helper code. @@ -131,6 +144,30 @@ func binary(x Expr, pos Position, op string, y Expr) Expr { } } +// isSimpleExpression returns whether an expression is simple and allowed to exist in +// compact forms of sequences. +// The formal criteria are the following: an expression is considered simple if it's +// a literal (variable, string or a number), a literal with a unary operator or an empty sequence. +func isSimpleExpression(expr *Expr) bool { + switch x := (*expr).(type) { + case *LiteralExpr, *StringExpr: + return true + case *UnaryExpr: + _, ok := x.X.(*LiteralExpr) + return ok + case *ListExpr: + return len(x.List) == 0 + case *TupleExpr: + return len(x.List) == 0 + case *DictExpr: + return len(x.List) == 0 + case *SetExpr: + return len(x.List) == 0 + default: + return false + } +} + // forceCompact returns the setting for the ForceCompact field for a call or tuple. // // NOTE 1: The field is called ForceCompact, not ForceSingleLine, @@ -179,10 +216,7 @@ func forceCompact(start Position, list []Expr, end Position) bool { return false } line = end.Line - switch x.(type) { - case *LiteralExpr, *StringExpr, *UnaryExpr: - // ok - default: + if !isSimpleExpression(&x) { return false } } @@ -215,156 +249,190 @@ var yyExca = [...]int{ -2, 0, } -const yyNprod = 73 const yyPrivate = 57344 -var yyTokenNames []string -var yyStates []string - -const yyLast = 519 +const yyLast = 739 var yyAct = [...]int{ - 115, 112, 9, 7, 66, 51, 87, 102, 88, 20, - 135, 81, 47, 49, 54, 57, 58, 59, 60, 127, - 21, 126, 18, 113, 62, 64, 65, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 128, 82, 83, 84, 85, 18, 27, 24, 90, - 26, 29, 97, 30, 23, 28, 93, 31, 95, 32, - 25, 122, 96, 116, 130, 42, 86, 117, 33, 92, - 36, 104, 44, 90, 39, 43, 109, 34, 35, 40, - 41, 90, 107, 90, 90, 24, 101, 106, 48, 134, - 100, 23, 127, 114, 99, 19, 110, 25, 91, 118, - 120, 121, 110, 56, 110, 119, 45, 124, 46, 125, - 22, 123, 103, 110, 94, 129, 114, 61, 1, 10, - 55, 50, 53, 52, 4, 2, 111, 131, 89, 133, - 132, 27, 24, 63, 26, 29, 136, 30, 23, 28, - 98, 31, 37, 32, 25, 0, 0, 0, 38, 42, - 0, 0, 33, 0, 36, 0, 44, 0, 39, 43, - 0, 34, 35, 40, 41, 27, 24, 0, 26, 29, - 0, 30, 23, 28, 0, 31, 37, 32, 25, 0, - 0, 0, 38, 42, 0, 0, 33, 0, 36, 0, - 44, 108, 39, 43, 0, 34, 35, 40, 41, 27, - 24, 0, 26, 29, 0, 30, 23, 28, 0, 31, - 37, 32, 25, 105, 0, 0, 38, 42, 0, 0, - 33, 0, 36, 0, 44, 0, 39, 43, 0, 34, - 35, 40, 41, 27, 24, 0, 26, 29, 0, 30, - 23, 28, 0, 31, 37, 32, 25, 0, 0, 0, - 38, 42, 0, 0, 33, 90, 36, 0, 44, 0, - 39, 43, 0, 34, 35, 40, 41, 27, 24, 0, - 26, 29, 0, 30, 23, 28, 0, 31, 37, 32, - 25, 0, 0, 0, 38, 42, 0, 0, 33, 0, - 36, 0, 44, 0, 39, 43, 0, 34, 35, 40, - 41, 27, 24, 0, 26, 29, 0, 30, 23, 28, - 0, 31, 37, 32, 25, 0, 0, 0, 38, 42, - 0, 0, 33, 0, 36, 0, 0, 0, 39, 43, - 0, 34, 35, 40, 41, 27, 24, 0, 26, 29, - 0, 30, 23, 28, 0, 31, 0, 32, 25, 0, - 0, 0, 0, 42, 0, 0, 33, 0, 36, 12, - 0, 17, 39, 43, 15, 34, 35, 40, 41, 0, - 0, 11, 0, 13, 0, 0, 0, 6, 3, 0, - 0, 0, 18, 0, 0, 0, 0, 14, 0, 0, - 16, 0, 8, 20, 0, 5, 27, 24, 0, 26, - 29, 0, 30, 23, 28, 0, 31, 0, 32, 25, - 0, 0, 0, 0, 42, 27, 24, 33, 26, 36, - 0, 0, 23, 28, 0, 0, 34, 35, 25, 41, - 27, 24, 0, 26, 29, 0, 30, 23, 28, 0, - 31, 0, 32, 25, 0, 0, 0, 0, 42, 0, - 0, 33, 0, 36, 0, 0, 0, 0, 0, 0, - 34, 35, 27, 24, 0, 26, 29, 0, 30, 23, - 28, 0, 31, 0, 32, 25, 12, 0, 17, 0, - 0, 15, 0, 33, 0, 36, 0, 0, 11, 0, - 13, 0, 34, 35, 0, 0, 0, 0, 0, 18, - 0, 0, 0, 0, 14, 27, 24, 16, 26, 29, - 20, 30, 23, 28, 0, 0, 0, 0, 25, + 13, 112, 136, 2, 138, 74, 17, 7, 118, 69, + 34, 9, 117, 81, 130, 58, 31, 59, 35, 64, + 65, 66, 161, 30, 102, 70, 72, 77, 37, 38, + 166, 84, 108, 33, 79, 73, 76, 85, 84, 120, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 167, 103, 104, 105, 106, 86, + 163, 83, 110, 111, 154, 149, 153, 129, 64, 127, + 120, 109, 29, 120, 178, 87, 25, 115, 20, 126, + 120, 27, 116, 64, 133, 123, 120, 125, 24, 172, + 26, 134, 132, 131, 171, 61, 68, 71, 114, 28, + 168, 60, 113, 139, 145, 18, 22, 62, 121, 19, + 141, 158, 30, 148, 146, 147, 63, 40, 142, 82, + 39, 124, 147, 143, 67, 41, 150, 35, 80, 155, + 157, 152, 150, 36, 150, 156, 40, 1, 160, 39, + 42, 162, 43, 23, 41, 78, 165, 164, 75, 32, + 12, 8, 150, 4, 151, 21, 119, 122, 25, 0, + 20, 0, 169, 27, 0, 170, 0, 173, 174, 0, + 24, 175, 26, 165, 177, 7, 6, 0, 25, 11, + 0, 28, 16, 27, 0, 0, 0, 18, 22, 0, + 24, 19, 26, 15, 30, 10, 14, 25, 176, 20, + 5, 28, 27, 0, 0, 0, 0, 0, 22, 24, + 0, 26, 0, 0, 30, 6, 3, 25, 11, 20, + 28, 16, 27, 0, 0, 0, 18, 22, 0, 24, + 19, 26, 15, 30, 10, 14, 0, 0, 0, 5, + 28, 0, 0, 0, 0, 0, 18, 22, 0, 0, + 19, 0, 15, 30, 40, 14, 0, 39, 42, 137, + 43, 0, 41, 128, 44, 50, 45, 0, 0, 0, + 0, 51, 55, 0, 0, 46, 0, 49, 0, 57, + 0, 0, 52, 56, 0, 0, 47, 48, 53, 54, + 40, 0, 0, 39, 42, 0, 43, 0, 41, 159, + 44, 50, 45, 0, 0, 0, 0, 51, 55, 0, + 0, 46, 0, 49, 0, 57, 0, 0, 52, 56, + 0, 0, 47, 48, 53, 54, 40, 0, 0, 39, + 42, 0, 43, 0, 41, 0, 44, 50, 45, 0, + 144, 0, 0, 51, 55, 0, 0, 46, 0, 49, + 0, 57, 0, 0, 52, 56, 0, 0, 47, 48, + 53, 54, 40, 0, 0, 39, 42, 0, 43, 0, + 41, 0, 44, 50, 45, 0, 0, 0, 0, 51, + 55, 0, 0, 46, 120, 49, 0, 57, 0, 0, + 52, 56, 0, 0, 47, 48, 53, 54, 40, 0, + 0, 39, 42, 0, 43, 0, 41, 0, 44, 50, + 45, 0, 0, 0, 0, 51, 55, 0, 0, 46, + 0, 49, 0, 57, 140, 0, 52, 56, 0, 0, + 47, 48, 53, 54, 40, 0, 0, 39, 42, 0, + 43, 0, 41, 135, 44, 50, 45, 0, 0, 0, + 0, 51, 55, 0, 0, 46, 0, 49, 0, 57, + 0, 0, 52, 56, 0, 0, 47, 48, 53, 54, + 40, 0, 0, 39, 42, 0, 43, 0, 41, 107, + 44, 50, 45, 0, 0, 0, 0, 51, 55, 0, + 0, 46, 0, 49, 0, 57, 0, 0, 52, 56, + 0, 0, 47, 48, 53, 54, 40, 0, 0, 39, + 42, 0, 43, 0, 41, 0, 44, 50, 45, 0, + 0, 0, 0, 51, 55, 0, 0, 46, 0, 49, + 0, 57, 0, 0, 52, 56, 0, 0, 47, 48, + 53, 54, 40, 0, 0, 39, 42, 0, 43, 0, + 41, 0, 44, 50, 45, 0, 0, 0, 0, 51, + 55, 0, 0, 46, 0, 49, 0, 0, 0, 0, + 52, 56, 0, 0, 47, 48, 53, 54, 40, 0, + 0, 39, 42, 0, 43, 0, 41, 0, 44, 0, + 45, 0, 0, 0, 0, 0, 55, 0, 0, 46, + 0, 49, 0, 57, 0, 0, 52, 56, 0, 0, + 47, 48, 53, 54, 40, 0, 0, 39, 42, 0, + 43, 0, 41, 0, 44, 0, 45, 0, 0, 0, + 0, 0, 55, 0, 0, 46, 0, 49, 0, 25, + 0, 20, 52, 56, 27, 0, 47, 48, 53, 54, + 0, 24, 0, 26, 0, 40, 0, 0, 39, 42, + 0, 43, 28, 41, 0, 44, 0, 45, 18, 22, + 0, 0, 19, 55, 15, 30, 46, 14, 49, 0, + 0, 0, 0, 0, 0, 0, 0, 47, 48, 40, + 54, 0, 39, 42, 0, 43, 0, 41, 0, 44, + 0, 45, 0, 0, 0, 40, 0, 55, 39, 42, + 46, 43, 49, 41, 0, 44, 0, 45, 0, 0, + 0, 47, 48, 0, 0, 0, 46, 0, 49, 0, + 0, 0, 0, 0, 0, 0, 0, 47, 48, } var yyPact = [...]int{ - -1000, -1000, 354, -1000, 101, -1000, -1000, 263, -1000, -1000, - -30, 471, 471, 471, 471, 471, 471, 471, -1000, -1000, - -1000, -1000, -1000, -4, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - -20, 471, 471, 471, 471, -1000, 48, 229, 89, 229, - 108, 23, 42, 32, 127, 85, 77, 263, -1000, -1000, - -1000, -37, -1000, 106, 229, 195, 74, 80, 80, 80, - 411, 411, 501, 501, 501, 501, 501, 501, 43, 43, - 392, 471, 426, 458, 392, 161, -1000, 58, -1000, -1000, - 18, 471, -1000, 57, -1000, 47, -1000, -1000, 471, 471, - 471, 471, -1000, -1000, 55, -1000, 471, 392, 471, -1000, - -1000, -8, 10, -6, -1000, 263, -1000, -1000, 263, -1000, - 127, 331, -1000, 46, 263, 331, 471, -6, 471, 83, - -1000, 297, -1000, 297, -21, 471, 297, + -1000, -1000, 192, -1000, -1000, -1000, -31, -1000, -1000, -1000, + 5, 173, -2, 502, 71, -1000, 71, 90, 71, 71, + 71, -1000, 119, -18, 71, 71, 71, 173, -1000, -1000, + -1000, -1000, -37, 114, 29, 90, 71, 46, -1000, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, -8, 71, 71, 71, 71, 502, 466, + 4, 71, 71, 89, 502, -1000, -1000, 71, -1000, 64, + 358, 99, 358, 115, 13, 59, 49, 250, 58, -1000, + -33, 634, 71, 71, 173, 430, 212, -1000, -1000, -1000, + -1000, 113, 113, 132, 132, 132, 132, 132, 132, 574, + 574, 651, 71, 685, 701, 651, 394, 212, -1000, 112, + 358, 322, 91, 71, 71, 107, -1000, 47, -1000, -1000, + 173, 71, -1000, 60, -1000, 44, -1000, -1000, 71, 71, + -1000, -1000, 105, 286, 90, 212, -1000, -22, -1000, 651, + 71, -1000, -1000, 54, -1000, 71, 610, 502, -1000, -1000, + -1000, 1, 22, -1000, -1000, 502, -1000, 250, 87, 212, + -1000, -1000, 610, -1000, 76, 502, 71, 71, 212, -1000, + 153, -1000, 71, 538, 538, -1000, -1000, 56, -1000, } var yyPgo = [...]int{ - 0, 20, 0, 4, 88, 108, 128, 8, 6, 2, - 1, 126, 125, 124, 5, 123, 120, 95, 119, 118, - 117, + 0, 157, 0, 1, 6, 97, 9, 10, 156, 8, + 12, 155, 154, 3, 153, 151, 150, 4, 11, 149, + 5, 148, 145, 72, 143, 2, 137, 133, 128, } var yyR1 = [...]int{ - 0, 19, 12, 12, 12, 12, 13, 13, 20, 20, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 26, 25, 25, 13, 13, 13, 13, 14, 14, + 15, 15, 15, 16, 16, 16, 27, 27, 17, 19, + 19, 18, 18, 18, 18, 28, 28, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 1, - 1, 14, 16, 16, 15, 15, 4, 4, 5, 5, - 17, 18, 18, 9, 10, 10, 6, 6, 7, 8, - 8, 11, 11, + 1, 20, 22, 22, 21, 21, 5, 5, 6, 6, + 7, 7, 23, 24, 24, 11, 8, 9, 10, 10, + 12, 12, } var yyR2 = [...]int{ - 0, 2, 0, 4, 2, 2, 1, 1, 0, 2, - 1, 1, 3, 4, 4, 4, 3, 3, 3, 3, - 4, 5, 4, 6, 4, 2, 2, 2, 3, 3, + 0, 2, 4, 1, 0, 2, 2, 3, 1, 1, + 7, 6, 1, 4, 5, 4, 2, 1, 4, 0, + 3, 1, 2, 1, 1, 0, 1, 1, 3, 4, + 4, 4, 6, 8, 5, 1, 3, 4, 4, 4, + 3, 3, 3, 2, 1, 4, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 5, 0, 1, 0, 1, 3, 1, 3, 1, 2, 1, 3, 0, 2, - 1, 1, 2, 1, 1, 3, 4, 6, 2, 1, - 2, 0, 3, + 1, 3, 1, 1, 2, 1, 4, 2, 1, 2, + 0, 3, } var yyChk = [...]int{ - -1000, -19, -12, 24, -13, 41, 23, -2, 38, -9, - -18, 17, 5, 19, 33, 10, 36, 7, 28, -17, - 39, -1, 9, 11, 5, 17, 7, 4, 12, 8, - 10, 14, 16, 25, 34, 35, 27, 15, 21, 31, - 36, 37, 22, 32, 29, -17, -5, -2, -4, -2, - -5, -14, -15, -5, -2, -16, -4, -2, -2, -2, - -2, -20, 28, -5, -2, -2, -3, -2, -2, -2, + -1000, -26, -13, 24, -14, 47, 23, -17, -15, -18, + 42, 26, -16, -2, 43, 40, 29, -4, 34, 38, + 7, -11, 35, -24, 17, 5, 19, 10, 28, -23, + 41, 47, -19, 28, -7, -4, -27, 30, 31, 7, + 4, 12, 8, 10, 14, 16, 25, 36, 37, 27, + 15, 21, 32, 38, 39, 22, 33, 29, -2, -2, + 11, 5, 17, -5, -2, -2, -2, 5, -23, -6, + -2, -5, -2, -6, -20, -21, -6, -2, -22, -4, + -28, 50, 5, 32, 9, -2, 13, 29, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, - -2, 31, -2, -2, -2, -2, 18, -8, -7, -6, - 26, 9, -1, -8, 6, -8, 20, 20, 13, 9, - 13, 9, 44, 6, -8, 18, 13, -2, 30, 18, - -7, -11, -10, 5, -9, -2, 6, 20, -2, -14, - -2, -2, 6, -3, -2, -2, 29, 9, 31, -10, - 18, -2, -9, -2, 6, 31, -2, + -2, -2, 32, -2, -2, -2, -2, 13, 28, -6, + -2, -2, -3, 13, 9, -6, 18, -10, -9, -8, + 26, 9, -1, -10, 6, -10, 20, 20, 13, 9, + 47, -18, -6, -2, -4, 13, -25, 47, -17, -2, + 30, -25, 6, -10, 18, 13, -2, -2, 6, 18, + -9, -12, -7, 6, 20, -2, -20, -2, 6, 13, + -25, 44, -2, 6, -3, -2, 29, 32, 13, -25, + -13, 18, 13, -2, -2, -25, 45, -3, 18, } var yyDef = [...]int{ - 2, -2, 0, 1, 49, 4, 5, 6, 7, 10, - 11, 58, 58, 58, 0, 0, 0, 0, 63, 61, - 60, 8, 50, 0, 58, 47, 0, 0, 0, 0, + 4, -2, 0, 1, 5, 6, 0, 8, 9, 19, + 0, 0, 12, 21, 23, 24, 0, 44, 0, 0, + 0, 27, 0, 35, 78, 78, 78, 0, 85, 83, + 82, 7, 25, 0, 0, 80, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 62, 0, 56, 49, 56, - 0, 52, 0, 0, 56, 54, 0, 56, 25, 26, - 27, 3, 19, 0, 56, 48, 0, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 0, 43, 44, 45, 0, 12, 0, 69, 71, - 0, 50, 59, 0, 18, 0, 16, 17, 0, 55, - 0, 0, 9, 20, 0, 22, 47, 42, 0, 13, - 70, 68, 0, 0, 64, 57, 14, 15, 51, 53, - 0, 24, 21, 0, 48, 46, 0, 0, 0, 0, - 23, 72, 65, 66, 0, 0, 67, + 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, + 0, 78, 67, 0, 76, 46, 47, 78, 84, 0, + 76, 69, 76, 0, 72, 0, 0, 76, 74, 43, + 0, 26, 78, 0, 0, 0, 0, 16, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 0, 63, 64, 65, 0, 0, 28, 0, + 76, 68, 0, 0, 0, 0, 36, 0, 88, 90, + 0, 70, 79, 0, 42, 0, 40, 41, 0, 75, + 18, 20, 0, 0, 81, 0, 15, 0, 3, 62, + 0, 13, 30, 0, 31, 67, 45, 77, 29, 37, + 89, 87, 0, 38, 39, 71, 73, 0, 0, 0, + 14, 4, 66, 34, 0, 68, 0, 0, 0, 11, + 0, 32, 67, 91, 86, 10, 2, 0, 33, } var yyTok1 = [...]int{ 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 41, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 47, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 5, 6, 7, 8, 9, 10, 11, 12, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 13, 44, + 3, 3, 3, 3, 3, 3, 3, 3, 13, 50, 14, 15, 16, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -377,7 +445,7 @@ var yyTok2 = [...]int{ 2, 3, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 42, 43, + 39, 40, 41, 42, 43, 44, 45, 46, 48, 49, } var yyTok3 = [...]int{ 0, @@ -722,35 +790,57 @@ yydefault: case 1: yyDollar = yyS[yypt-2 : yypt+1] - //line build/parse.y:153 + //line build/parse.y:167 { yylex.(*input).file = &File{Stmt: yyDollar[1].exprs} return 0 } case 2: + yyDollar = yyS[yypt-4 : yypt+1] + //line build/parse.y:174 + { + yyVAL.block = CodeBlock{ + Start: yyDollar[2].pos, + Statements: yyDollar[3].exprs, + End: End{Pos: yyDollar[4].pos}, + } + } + case 3: + yyDollar = yyS[yypt-1 : yypt+1] + //line build/parse.y:182 + { + // simple_stmt is never empty + start, _ := yyDollar[1].exprs[0].Span() + _, end := yyDollar[1].exprs[len(yyDollar[1].exprs)-1].Span() + yyVAL.block = CodeBlock{ + Start: start, + Statements: yyDollar[1].exprs, + End: End{Pos: end}, + } + } + case 4: yyDollar = yyS[yypt-0 : yypt+1] - //line build/parse.y:159 + //line build/parse.y:194 { yyVAL.exprs = nil yyVAL.lastRule = nil } - case 3: - yyDollar = yyS[yypt-4 : yypt+1] - //line build/parse.y:164 + case 5: + yyDollar = yyS[yypt-2 : yypt+1] + //line build/parse.y:199 { // If this statement follows a comment block, // attach the comments to the statement. if cb, ok := yyDollar[1].lastRule.(*CommentBlock); ok { - yyVAL.exprs = yyDollar[1].exprs - yyVAL.exprs[len(yyDollar[1].exprs)-1] = yyDollar[2].expr - yyDollar[2].expr.Comment().Before = cb.After - yyVAL.lastRule = yyDollar[2].expr + yyVAL.exprs = append(yyDollar[1].exprs[:len(yyDollar[1].exprs)-1], yyDollar[2].exprs...) + yyDollar[2].exprs[0].Comment().Before = cb.After + yyVAL.lastRule = yyDollar[2].exprs[len(yyDollar[2].exprs)-1] break } // Otherwise add to list. - yyVAL.exprs = append(yyDollar[1].exprs, yyDollar[2].expr) - yyVAL.lastRule = yyDollar[2].expr + yyVAL.exprs = append(yyDollar[1].exprs, yyDollar[2].exprs...) + yyVAL.lastRule = yyDollar[2].exprs[len(yyDollar[2].exprs)-1] // Consider this input: // @@ -763,21 +853,22 @@ yydefault: // for baz() instead. if x := yyDollar[1].lastRule; x != nil { com := x.Comment() - yyDollar[2].expr.Comment().Before = com.After + // stmt is never empty + yyDollar[2].exprs[0].Comment().Before = com.After com.After = nil } } - case 4: + case 6: yyDollar = yyS[yypt-2 : yypt+1] - //line build/parse.y:195 + //line build/parse.y:230 { // Blank line; sever last rule from future comments. yyVAL.exprs = yyDollar[1].exprs yyVAL.lastRule = nil } - case 5: - yyDollar = yyS[yypt-2 : yypt+1] - //line build/parse.y:201 + case 7: + yyDollar = yyS[yypt-3 : yypt+1] + //line build/parse.y:236 { yyVAL.exprs = yyDollar[1].exprs yyVAL.lastRule = yyDollar[1].lastRule @@ -789,30 +880,242 @@ yydefault: com := yyVAL.lastRule.Comment() com.After = append(com.After, Comment{Start: yyDollar[2].pos, Token: yyDollar[2].tok}) } - case 7: + case 8: yyDollar = yyS[yypt-1 : yypt+1] - //line build/parse.y:216 + //line build/parse.y:250 + { + yyVAL.exprs = yyDollar[1].exprs + } + case 9: + yyDollar = yyS[yypt-1 : yypt+1] + //line build/parse.y:254 + { + yyVAL.exprs = []Expr{yyDollar[1].expr} + } + case 10: + yyDollar = yyS[yypt-7 : yypt+1] + //line build/parse.y:260 + { + yyVAL.expr = &FuncDef{ + Start: yyDollar[1].pos, + Name: yyDollar[2].tok, + ListStart: yyDollar[3].pos, + Args: yyDollar[4].exprs, + Body: yyDollar[7].block, + End: yyDollar[7].block.End, + ForceCompact: forceCompact(yyDollar[3].pos, yyDollar[4].exprs, yyDollar[5].pos), + ForceMultiLine: forceMultiLine(yyDollar[3].pos, yyDollar[4].exprs, yyDollar[5].pos), + } + } + case 11: + yyDollar = yyS[yypt-6 : yypt+1] + //line build/parse.y:273 + { + yyVAL.expr = &ForLoop{ + Start: yyDollar[1].pos, + LoopVars: yyDollar[2].exprs, + Iterable: yyDollar[4].expr, + Body: yyDollar[6].block, + End: yyDollar[6].block.End, + } + } + case 12: + yyDollar = yyS[yypt-1 : yypt+1] + //line build/parse.y:283 + { + yyVAL.expr = yyDollar[1].expr + } + case 13: + yyDollar = yyS[yypt-4 : yypt+1] + //line build/parse.y:289 + { + yyVAL.expr = &IfElse{ + Start: yyDollar[1].pos, + Conditions: []Condition{ + Condition{ + If: yyDollar[2].expr, + Then: yyDollar[4].block, + }, + }, + End: yyDollar[4].block.End, + } + } + case 14: + yyDollar = yyS[yypt-5 : yypt+1] + //line build/parse.y:302 + { + block := yyDollar[1].expr.(*IfElse) + block.Conditions = append(block.Conditions, Condition{ + If: yyDollar[3].expr, + Then: yyDollar[5].block, + }) + block.End = yyDollar[5].block.End + yyVAL.expr = block + } + case 15: + yyDollar = yyS[yypt-4 : yypt+1] + //line build/parse.y:312 + { + block := yyDollar[1].expr.(*IfElse) + block.Conditions = append(block.Conditions, Condition{ + Then: yyDollar[4].block, + }) + block.End = yyDollar[4].block.End + yyVAL.expr = block + } + case 18: + yyDollar = yyS[yypt-4 : yypt+1] + //line build/parse.y:327 + { + yyVAL.exprs = append([]Expr{yyDollar[1].expr}, yyDollar[2].exprs...) + yyVAL.lastRule = yyVAL.exprs[len(yyVAL.exprs)-1] + } + case 19: + yyDollar = yyS[yypt-0 : yypt+1] + //line build/parse.y:333 + { + yyVAL.exprs = []Expr{} + } + case 20: + yyDollar = yyS[yypt-3 : yypt+1] + //line build/parse.y:337 + { + yyVAL.exprs = append(yyDollar[1].exprs, yyDollar[3].expr) + } + case 22: + yyDollar = yyS[yypt-2 : yypt+1] + //line build/parse.y:344 + { + _, end := yyDollar[2].expr.Span() + yyVAL.expr = &ReturnExpr{ + X: yyDollar[2].expr, + End: end, + } + } + case 23: + yyDollar = yyS[yypt-1 : yypt+1] + //line build/parse.y:352 + { + yyVAL.expr = &ReturnExpr{End: yyDollar[1].pos} + } + case 24: + yyDollar = yyS[yypt-1 : yypt+1] + //line build/parse.y:356 { yyVAL.expr = &PythonBlock{Start: yyDollar[1].pos, Token: yyDollar[1].tok} } - case 11: + case 28: + yyDollar = yyS[yypt-3 : yypt+1] + //line build/parse.y:366 + { + yyVAL.expr = &DotExpr{ + X: yyDollar[1].expr, + Dot: yyDollar[2].pos, + NamePos: yyDollar[3].pos, + Name: yyDollar[3].tok, + } + } + case 29: + yyDollar = yyS[yypt-4 : yypt+1] + //line build/parse.y:375 + { + yyVAL.expr = &CallExpr{ + X: &LiteralExpr{Start: yyDollar[1].pos, Token: "load"}, + ListStart: yyDollar[2].pos, + List: yyDollar[3].exprs, + End: End{Pos: yyDollar[4].pos}, + ForceCompact: forceCompact(yyDollar[2].pos, yyDollar[3].exprs, yyDollar[4].pos), + ForceMultiLine: forceMultiLine(yyDollar[2].pos, yyDollar[3].exprs, yyDollar[4].pos), + } + } + case 30: + yyDollar = yyS[yypt-4 : yypt+1] + //line build/parse.y:386 + { + yyVAL.expr = &CallExpr{ + X: yyDollar[1].expr, + ListStart: yyDollar[2].pos, + List: yyDollar[3].exprs, + End: End{Pos: yyDollar[4].pos}, + ForceCompact: forceCompact(yyDollar[2].pos, yyDollar[3].exprs, yyDollar[4].pos), + ForceMultiLine: forceMultiLine(yyDollar[2].pos, yyDollar[3].exprs, yyDollar[4].pos), + } + } + case 31: + yyDollar = yyS[yypt-4 : yypt+1] + //line build/parse.y:397 + { + yyVAL.expr = &IndexExpr{ + X: yyDollar[1].expr, + IndexStart: yyDollar[2].pos, + Y: yyDollar[3].expr, + End: yyDollar[4].pos, + } + } + case 32: + yyDollar = yyS[yypt-6 : yypt+1] + //line build/parse.y:406 + { + yyVAL.expr = &SliceExpr{ + X: yyDollar[1].expr, + SliceStart: yyDollar[2].pos, + From: yyDollar[3].expr, + FirstColon: yyDollar[4].pos, + To: yyDollar[5].expr, + End: yyDollar[6].pos, + } + } + case 33: + yyDollar = yyS[yypt-8 : yypt+1] + //line build/parse.y:417 + { + yyVAL.expr = &SliceExpr{ + X: yyDollar[1].expr, + SliceStart: yyDollar[2].pos, + From: yyDollar[3].expr, + FirstColon: yyDollar[4].pos, + To: yyDollar[5].expr, + SecondColon: yyDollar[6].pos, + Step: yyDollar[7].expr, + End: yyDollar[8].pos, + } + } + case 34: + yyDollar = yyS[yypt-5 : yypt+1] + //line build/parse.y:430 + { + yyVAL.expr = &CallExpr{ + X: yyDollar[1].expr, + ListStart: yyDollar[2].pos, + List: []Expr{ + &ListForExpr{ + Brack: "", + Start: yyDollar[2].pos, + X: yyDollar[3].expr, + For: yyDollar[4].forsifs, + End: End{Pos: yyDollar[5].pos}, + }, + }, + End: End{Pos: yyDollar[5].pos}, + } + } + case 35: yyDollar = yyS[yypt-1 : yypt+1] - //line build/parse.y:226 + //line build/parse.y:447 { if len(yyDollar[1].strings) == 1 { yyVAL.expr = yyDollar[1].strings[0] break } - yyVAL.expr = yyDollar[1].strings[0] for _, x := range yyDollar[1].strings[1:] { _, end := yyVAL.expr.Span() yyVAL.expr = binary(yyVAL.expr, end, "+", x) } } - case 12: + case 36: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:239 + //line build/parse.y:459 { yyVAL.expr = &ListExpr{ Start: yyDollar[1].pos, @@ -822,9 +1125,9 @@ yydefault: ForceMultiLine: forceMultiLine(yyDollar[1].pos, yyDollar[2].exprs, yyDollar[3].pos), } } - case 13: + case 37: yyDollar = yyS[yypt-4 : yypt+1] - //line build/parse.y:249 + //line build/parse.y:469 { exprStart, _ := yyDollar[2].expr.Span() yyVAL.expr = &ListForExpr{ @@ -836,9 +1139,9 @@ yydefault: ForceMultiLine: yyDollar[1].pos.Line != exprStart.Line, } } - case 14: + case 38: yyDollar = yyS[yypt-4 : yypt+1] - //line build/parse.y:261 + //line build/parse.y:481 { exprStart, _ := yyDollar[2].expr.Span() yyVAL.expr = &ListForExpr{ @@ -850,9 +1153,9 @@ yydefault: ForceMultiLine: yyDollar[1].pos.Line != exprStart.Line, } } - case 15: + case 39: yyDollar = yyS[yypt-4 : yypt+1] - //line build/parse.y:273 + //line build/parse.y:493 { exprStart, _ := yyDollar[2].expr.Span() yyVAL.expr = &ListForExpr{ @@ -864,9 +1167,9 @@ yydefault: ForceMultiLine: yyDollar[1].pos.Line != exprStart.Line, } } - case 16: + case 40: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:285 + //line build/parse.y:505 { yyVAL.expr = &DictExpr{ Start: yyDollar[1].pos, @@ -876,9 +1179,9 @@ yydefault: ForceMultiLine: forceMultiLine(yyDollar[1].pos, yyDollar[2].exprs, yyDollar[3].pos), } } - case 17: + case 41: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:295 + //line build/parse.y:515 { yyVAL.expr = &SetExpr{ Start: yyDollar[1].pos, @@ -888,9 +1191,9 @@ yydefault: ForceMultiLine: forceMultiLine(yyDollar[1].pos, yyDollar[2].exprs, yyDollar[3].pos), } } - case 18: + case 42: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:305 + //line build/parse.y:525 { if len(yyDollar[2].exprs) == 1 && yyDollar[2].comma.Line == 0 { // Just a parenthesized expression, not a tuple. @@ -911,76 +1214,15 @@ yydefault: } } } - case 19: - yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:326 + case 43: + yyDollar = yyS[yypt-2 : yypt+1] + //line build/parse.y:545 { - yyVAL.expr = &DotExpr{ - X: yyDollar[1].expr, - Dot: yyDollar[2].pos, - NamePos: yyDollar[3].pos, - Name: yyDollar[3].tok, - } + yyVAL.expr = unary(yyDollar[1].pos, yyDollar[1].tok, yyDollar[2].expr) } - case 20: + case 45: yyDollar = yyS[yypt-4 : yypt+1] - //line build/parse.y:335 - { - yyVAL.expr = &CallExpr{ - X: yyDollar[1].expr, - ListStart: yyDollar[2].pos, - List: yyDollar[3].exprs, - End: End{Pos: yyDollar[4].pos}, - ForceCompact: forceCompact(yyDollar[2].pos, yyDollar[3].exprs, yyDollar[4].pos), - ForceMultiLine: forceMultiLine(yyDollar[2].pos, yyDollar[3].exprs, yyDollar[4].pos), - } - } - case 21: - yyDollar = yyS[yypt-5 : yypt+1] - //line build/parse.y:346 - { - yyVAL.expr = &CallExpr{ - X: yyDollar[1].expr, - ListStart: yyDollar[2].pos, - List: []Expr{ - &ListForExpr{ - Brack: "", - Start: yyDollar[2].pos, - X: yyDollar[3].expr, - For: yyDollar[4].forsifs, - End: End{Pos: yyDollar[5].pos}, - }, - }, - End: End{Pos: yyDollar[5].pos}, - } - } - case 22: - yyDollar = yyS[yypt-4 : yypt+1] - //line build/parse.y:363 - { - yyVAL.expr = &IndexExpr{ - X: yyDollar[1].expr, - IndexStart: yyDollar[2].pos, - Y: yyDollar[3].expr, - End: yyDollar[4].pos, - } - } - case 23: - yyDollar = yyS[yypt-6 : yypt+1] - //line build/parse.y:372 - { - yyVAL.expr = &SliceExpr{ - X: yyDollar[1].expr, - SliceStart: yyDollar[2].pos, - Y: yyDollar[3].expr, - Colon: yyDollar[4].pos, - Z: yyDollar[5].expr, - End: yyDollar[6].pos, - } - } - case 24: - yyDollar = yyS[yypt-4 : yypt+1] - //line build/parse.y:383 + //line build/parse.y:550 { yyVAL.expr = &LambdaExpr{ Lambda: yyDollar[1].pos, @@ -989,129 +1231,123 @@ yydefault: Expr: yyDollar[4].expr, } } - case 25: + case 46: yyDollar = yyS[yypt-2 : yypt+1] - //line build/parse.y:391 + //line build/parse.y:558 { yyVAL.expr = unary(yyDollar[1].pos, yyDollar[1].tok, yyDollar[2].expr) } - case 26: + case 47: yyDollar = yyS[yypt-2 : yypt+1] - //line build/parse.y:392 + //line build/parse.y:559 { yyVAL.expr = unary(yyDollar[1].pos, yyDollar[1].tok, yyDollar[2].expr) } - case 27: - yyDollar = yyS[yypt-2 : yypt+1] - //line build/parse.y:393 - { - yyVAL.expr = unary(yyDollar[1].pos, yyDollar[1].tok, yyDollar[2].expr) - } - case 28: + case 48: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:394 + //line build/parse.y:560 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } - case 29: + case 49: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:395 + //line build/parse.y:561 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } - case 30: + case 50: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:396 + //line build/parse.y:562 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } - case 31: + case 51: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:397 + //line build/parse.y:563 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } - case 32: + case 52: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:398 + //line build/parse.y:564 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } - case 33: + case 53: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:399 + //line build/parse.y:565 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } - case 34: + case 54: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:400 + //line build/parse.y:566 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } - case 35: + case 55: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:401 + //line build/parse.y:567 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } - case 36: + case 56: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:402 + //line build/parse.y:568 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } - case 37: + case 57: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:403 + //line build/parse.y:569 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } - case 38: + case 58: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:404 + //line build/parse.y:570 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } - case 39: + case 59: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:405 + //line build/parse.y:571 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } - case 40: + case 60: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:406 + //line build/parse.y:572 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } - case 41: + case 61: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:407 + //line build/parse.y:573 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } - case 42: + case 62: yyDollar = yyS[yypt-4 : yypt+1] - //line build/parse.y:408 + //line build/parse.y:574 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, "not in", yyDollar[4].expr) } - case 43: + case 63: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:409 + //line build/parse.y:575 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } - case 44: + case 64: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:410 + //line build/parse.y:576 { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } - case 45: + case 65: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:412 + //line build/parse.y:578 { if b, ok := yyDollar[3].expr.(*UnaryExpr); ok && b.Op == "not" { yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, "is not", b.X) @@ -1119,9 +1355,9 @@ yydefault: yyVAL.expr = binary(yyDollar[1].expr, yyDollar[2].pos, yyDollar[2].tok, yyDollar[3].expr) } } - case 46: + case 66: yyDollar = yyS[yypt-5 : yypt+1] - //line build/parse.y:420 + //line build/parse.y:586 { yyVAL.expr = &ConditionalExpr{ Then: yyDollar[1].expr, @@ -1131,21 +1367,21 @@ yydefault: Else: yyDollar[5].expr, } } - case 47: + case 67: yyDollar = yyS[yypt-0 : yypt+1] - //line build/parse.y:431 + //line build/parse.y:597 { yyVAL.expr = nil } - case 49: + case 69: yyDollar = yyS[yypt-0 : yypt+1] - //line build/parse.y:441 + //line build/parse.y:607 { yyVAL.pos = Position{} } - case 51: + case 71: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:447 + //line build/parse.y:613 { yyVAL.expr = &KeyValueExpr{ Key: yyDollar[1].expr, @@ -1153,57 +1389,69 @@ yydefault: Value: yyDollar[3].expr, } } - case 52: + case 72: yyDollar = yyS[yypt-1 : yypt+1] - //line build/parse.y:457 + //line build/parse.y:623 { yyVAL.exprs = []Expr{yyDollar[1].expr} } - case 53: + case 73: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:461 + //line build/parse.y:627 { yyVAL.exprs = append(yyDollar[1].exprs, yyDollar[3].expr) } - case 54: + case 74: yyDollar = yyS[yypt-1 : yypt+1] - //line build/parse.y:467 + //line build/parse.y:633 { yyVAL.exprs = yyDollar[1].exprs } - case 55: + case 75: yyDollar = yyS[yypt-2 : yypt+1] - //line build/parse.y:471 + //line build/parse.y:637 { yyVAL.exprs = yyDollar[1].exprs } - case 56: + case 76: yyDollar = yyS[yypt-1 : yypt+1] - //line build/parse.y:477 + //line build/parse.y:643 { yyVAL.exprs = []Expr{yyDollar[1].expr} } - case 57: + case 77: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:481 + //line build/parse.y:647 { yyVAL.exprs = append(yyDollar[1].exprs, yyDollar[3].expr) } - case 58: + case 78: yyDollar = yyS[yypt-0 : yypt+1] - //line build/parse.y:486 + //line build/parse.y:652 { yyVAL.exprs, yyVAL.comma = nil, Position{} } - case 59: + case 79: yyDollar = yyS[yypt-2 : yypt+1] - //line build/parse.y:490 + //line build/parse.y:656 { yyVAL.exprs, yyVAL.comma = yyDollar[1].exprs, yyDollar[2].pos } - case 60: + case 80: yyDollar = yyS[yypt-1 : yypt+1] - //line build/parse.y:496 + //line build/parse.y:662 + { + yyVAL.exprs = []Expr{yyDollar[1].expr} + } + case 81: + yyDollar = yyS[yypt-3 : yypt+1] + //line build/parse.y:666 + { + yyVAL.exprs = append(yyDollar[1].exprs, yyDollar[3].expr) + } + case 82: + yyDollar = yyS[yypt-1 : yypt+1] + //line build/parse.y:672 { yyVAL.string = &StringExpr{ Start: yyDollar[1].pos, @@ -1213,39 +1461,27 @@ yydefault: Token: yyDollar[1].tok, } } - case 61: + case 83: yyDollar = yyS[yypt-1 : yypt+1] - //line build/parse.y:508 + //line build/parse.y:684 { yyVAL.strings = []*StringExpr{yyDollar[1].string} } - case 62: + case 84: yyDollar = yyS[yypt-2 : yypt+1] - //line build/parse.y:512 + //line build/parse.y:688 { yyVAL.strings = append(yyDollar[1].strings, yyDollar[2].string) } - case 63: + case 85: yyDollar = yyS[yypt-1 : yypt+1] - //line build/parse.y:518 + //line build/parse.y:694 { yyVAL.expr = &LiteralExpr{Start: yyDollar[1].pos, Token: yyDollar[1].tok} } - case 64: - yyDollar = yyS[yypt-1 : yypt+1] - //line build/parse.y:524 - { - yyVAL.exprs = []Expr{yyDollar[1].expr} - } - case 65: - yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:528 - { - yyVAL.exprs = append(yyDollar[1].exprs, yyDollar[3].expr) - } - case 66: + case 86: yyDollar = yyS[yypt-4 : yypt+1] - //line build/parse.y:534 + //line build/parse.y:700 { yyVAL.forc = &ForClause{ For: yyDollar[1].pos, @@ -1254,47 +1490,36 @@ yydefault: Expr: yyDollar[4].expr, } } - case 67: - yyDollar = yyS[yypt-6 : yypt+1] - //line build/parse.y:543 - { - yyVAL.forc = &ForClause{ - For: yyDollar[1].pos, - Var: yyDollar[3].exprs, - In: yyDollar[5].pos, - Expr: yyDollar[6].expr, - } - } - case 68: + case 87: yyDollar = yyS[yypt-2 : yypt+1] - //line build/parse.y:553 + //line build/parse.y:710 { yyVAL.forifs = &ForClauseWithIfClausesOpt{ For: yyDollar[1].forc, Ifs: yyDollar[2].ifs, } } - case 69: + case 88: yyDollar = yyS[yypt-1 : yypt+1] - //line build/parse.y:562 + //line build/parse.y:719 { yyVAL.forsifs = []*ForClauseWithIfClausesOpt{yyDollar[1].forifs} } - case 70: + case 89: yyDollar = yyS[yypt-2 : yypt+1] - //line build/parse.y:565 + //line build/parse.y:722 { yyVAL.forsifs = append(yyDollar[1].forsifs, yyDollar[2].forifs) } - case 71: + case 90: yyDollar = yyS[yypt-0 : yypt+1] - //line build/parse.y:570 + //line build/parse.y:727 { yyVAL.ifs = nil } - case 72: + case 91: yyDollar = yyS[yypt-3 : yypt+1] - //line build/parse.y:574 + //line build/parse.y:731 { yyVAL.ifs = append(yyDollar[1].ifs, &IfClause{ If: yyDollar[2].pos, diff --git a/vendor/github.com/bazelbuild/buildtools/build/print.go b/vendor/github.com/bazelbuild/buildtools/build/print.go index 77c9180e60b..e4a0ecdd44d 100644 --- a/vendor/github.com/bazelbuild/buildtools/build/print.go +++ b/vendor/github.com/bazelbuild/buildtools/build/print.go @@ -23,6 +23,9 @@ import ( "strings" ) +const nestedIndentation = 2 // Indentation of nested blocks +const listIndentation = 4 // Indentation of multiline expressions + // Format returns the formatted form of the given BUILD file. func Format(f *File) []byte { pr := &printer{} @@ -118,7 +121,19 @@ func (p *printer) file(f *File) { p.newline() } - for i, stmt := range f.Stmt { + p.statements(f.Stmt) + + for _, com := range f.After { + p.printf("%s", strings.TrimSpace(com.Token)) + p.newline() + } + + // If the last expression is in an indented code block there can be spaces in the last line. + p.trim() +} + +func (p *printer) statements(stmts []Expr) { + for i, stmt := range stmts { switch stmt := stmt.(type) { case *CommentBlock: // comments already handled @@ -128,11 +143,17 @@ func (p *printer) file(f *File) { p.printf("%s", strings.TrimSpace(com.Token)) p.newline() } - p.printf("%s", stmt.Token) // includes trailing newline + p.printf("%s", stmt.Token) + p.newline() default: p.expr(stmt, precLow) - p.newline() + + // Print an empty line break after the expression unless it's a code block. + // For a code block, the line break is generated by its last statement. + if !isCodeBlock(stmt) { + p.newline() + } } for _, com := range stmt.Comment().After { @@ -140,28 +161,26 @@ func (p *printer) file(f *File) { p.newline() } - if i+1 < len(f.Stmt) && !compactStmt(stmt, f.Stmt[i+1]) { + if i+1 < len(stmts) && !compactStmt(stmt, stmts[i+1], p.margin == 0) { p.newline() } } - - for _, com := range f.After { - p.printf("%s", strings.TrimSpace(com.Token)) - p.newline() - } } // compactStmt reports whether the pair of statements s1, s2 // should be printed without an intervening blank line. // We omit the blank line when both are subinclude statements // and the second one has no leading comments. -func compactStmt(s1, s2 Expr) bool { +func compactStmt(s1, s2 Expr, isTopLevel bool) bool { if len(s2.Comment().Before) > 0 { return false } - return (isCall(s1, "subinclude") || isCall(s1, "load")) && - (isCall(s2, "subinclude") || isCall(s2, "load")) + if isTopLevel { + return isCall(s1, "load") && isCall(s2, "load") + } else { + return !(isCodeBlock(s1) || isCodeBlock(s2)) + } } // isCall reports whether x is a call to a function with the given name. @@ -177,6 +196,20 @@ func isCall(x Expr, name string) bool { return nam.Token == name } +// isCodeBlock checks if the statement is a code block (def, if, for, etc.) +func isCodeBlock(x Expr) bool { + switch x.(type) { + case *FuncDef: + return true + case *ForLoop: + return true + case *IfElse: + return true + default: + return false + } +} + // Expression formatting. // The expression formatter must introduce parentheses to force the @@ -220,6 +253,11 @@ const ( var opPrec = map[string]int{ "=": precAssign, "+=": precAssign, + "-=": precAssign, + "*=": precAssign, + "/=": precAssign, + "//=": precAssign, + "%=": precAssign, "or": precOr, "and": precAnd, "<": precCmp, @@ -232,6 +270,7 @@ var opPrec = map[string]int{ "-": precAdd, "*": precMultiply, "/": precMultiply, + "//": precMultiply, "%": precMultiply, } @@ -327,12 +366,18 @@ func (p *printer) expr(v Expr, outerPrec int) { addParen(precSuffix) p.expr(v.X, precSuffix) p.printf("[") - if v.Y != nil { - p.expr(v.Y, precLow) + if v.From != nil { + p.expr(v.From, precLow) } p.printf(":") - if v.Z != nil { - p.expr(v.Z, precLow) + if v.To != nil { + p.expr(v.To, precLow) + } + if v.SecondColon.Byte != 0 { + p.printf(":") + if v.Step != nil { + p.expr(v.Step, precLow) + } } p.printf("]") @@ -379,7 +424,7 @@ func (p *printer) expr(v Expr, outerPrec int) { if v.LineBreak { p.margin = p.indent() if v.Op == "=" { - p.margin += 4 + p.margin += listIndentation } } @@ -427,6 +472,61 @@ func (p *printer) expr(v Expr, outerPrec int) { p.expr(v.Test, precSuffix) p.printf(" else ") p.expr(v.Else, precSuffix) + + case *ReturnExpr: + p.printf("return") + if v.X != nil { + p.printf(" ") + p.expr(v.X, precSuffix) + } + + case *FuncDef: + p.printf("def ") + p.printf(v.Name) + p.seq("()", v.Args, &v.End, modeCall, v.ForceCompact, v.ForceMultiLine) + p.printf(":") + p.margin += nestedIndentation + p.newline() + p.statements(v.Body.Statements) + p.margin -= nestedIndentation + + case *ForLoop: + p.printf("for ") + for i, loopVar := range v.LoopVars { + if i > 0 { + p.printf(", ") + } + p.expr(loopVar, precLow) + } + p.printf(" in ") + p.expr(v.Iterable, precLow) + p.printf(":") + p.margin += nestedIndentation + p.newline() + p.statements(v.Body.Statements) + p.margin -= nestedIndentation + + case *IfElse: + for i, block := range v.Conditions { + if i == 0 { + p.printf("if ") + } else if block.If == nil { + p.newline() + p.printf("else") + } else { + p.newline() + p.printf("elif ") + } + + if block.If != nil { + p.expr(block.If, precLow) + } + p.printf(":") + p.margin += nestedIndentation + p.newline() + p.statements(block.Then.Statements) + p.margin -= nestedIndentation + } } // Add closing parenthesis if needed. @@ -452,6 +552,7 @@ const ( modeTuple // (x,) modeParen // (x) modeDict // {x:y} + modeSeq // x, y ) // seq formats a list of values inside a given bracket pair (brack = "()", "[]", "{}"). @@ -504,7 +605,7 @@ func (p *printer) seq(brack string, list []Expr, end *End, mode seqMode, forceCo default: // Multi-line form. - p.margin += 4 + p.margin += listIndentation for i, x := range list { // If we are about to break the line before the first // element and there are trailing end-of-line comments @@ -528,7 +629,7 @@ func (p *printer) seq(brack string, list []Expr, end *End, mode seqMode, forceCo p.newline() p.printf("%s", strings.TrimSpace(com.Token)) } - p.margin -= 4 + p.margin -= listIndentation p.newline() } p.depth-- @@ -566,7 +667,7 @@ func (p *printer) listFor(v *ListForExpr) { if multiLine { if v.Brack != "" { - p.margin += 4 + p.margin += listIndentation } p.newline() } @@ -602,7 +703,7 @@ func (p *printer) listFor(v *ListForExpr) { p.printf("%s", strings.TrimSpace(com.Token)) } if v.Brack != "" { - p.margin -= 4 + p.margin -= listIndentation } p.newline() } @@ -612,3 +713,7 @@ func (p *printer) listFor(v *ListForExpr) { p.depth-- } } + +func (p *printer) isTopLevel() bool { + return p.margin == 0 +} diff --git a/vendor/github.com/bazelbuild/buildtools/build/rule.go b/vendor/github.com/bazelbuild/buildtools/build/rule.go index 7f8183628a0..5f4b99c37db 100644 --- a/vendor/github.com/bazelbuild/buildtools/build/rule.go +++ b/vendor/github.com/bazelbuild/buildtools/build/rule.go @@ -18,33 +18,48 @@ distributed under the License is distributed on an "AS IS" BASIS, package build -import "strings" +import ( + "strings" + "path/filepath" +) // A Rule represents a single BUILD rule. type Rule struct { - Call *CallExpr + Call *CallExpr + ImplicitName string // The name which should be used if the name attribute is not set. See the comment on File.implicitRuleName. +} + +func (f *File) Rule(call *CallExpr) *Rule { + r := &Rule{call, ""} + if r.AttrString("name") == "" { + r.ImplicitName = f.implicitRuleName() + } + return r } // Rules returns the rules in the file of the given kind (such as "go_library"). // If kind == "", Rules returns all rules in the file. func (f *File) Rules(kind string) []*Rule { var all []*Rule + for _, stmt := range f.Stmt { call, ok := stmt.(*CallExpr) if !ok { continue } - rule := &Rule{call} + rule := f.Rule(call) if kind != "" && rule.Kind() != kind { continue } all = append(all, rule) } + return all } // RuleAt returns the rule in the file that starts at the specified line, or null if no such rule. func (f *File) RuleAt(linenum int) *Rule { + for _, stmt := range f.Stmt { call, ok := stmt.(*CallExpr) if !ok { @@ -52,7 +67,7 @@ func (f *File) RuleAt(linenum int) *Rule { } start, end := call.X.Span() if start.Line <= linenum && linenum <= end.Line { - return &Rule{call} + return f.Rule(call) } } return nil @@ -65,9 +80,9 @@ func (f *File) DelRules(kind, name string) int { var i int for _, stmt := range f.Stmt { if call, ok := stmt.(*CallExpr); ok { - r := &Rule{call} + r := f.Rule(call) if (kind == "" || r.Kind() == kind) && - (name == "" || r.AttrString("name") == name) { + (name == "" || r.Name() == name) { continue } } @@ -79,6 +94,42 @@ func (f *File) DelRules(kind, name string) int { return n } +// If a build file contains exactly one unnamed rule, and no rules in the file explicitly have the +// same name as the name of the directory the build file is in, we treat the unnamed rule as if it +// had the name of the directory containing the BUILD file. +// This is following a convention used in the Pants build system to cut down on boilerplate. +func (f *File) implicitRuleName() string { + // We disallow empty names in the top-level BUILD files. + dir := filepath.Dir(f.Path) + if dir == "." { + return "" + } + sawAnonymousRule := false + possibleImplicitName := filepath.Base(dir) + + for _, stmt := range f.Stmt { + call, ok := stmt.(*CallExpr) + if !ok { + continue + } + temp := &Rule{call, ""} + if temp.AttrString("name") == possibleImplicitName { + // A target explicitly has the name of the dir, so no implicit targets are allowed. + return "" + } + if temp.Kind() != "" && temp.AttrString("name") == "" { + if sawAnonymousRule { + return "" + } + sawAnonymousRule = true + } + } + if sawAnonymousRule { + return possibleImplicitName + } + return "" +} + // Kind returns the rule's kind (such as "go_library"). // The kind of the rule may be given by a literal or it may be a sequence of dot expressions that // begins with a literal, if the call expression does not conform to either of these forms, an @@ -118,9 +169,13 @@ func (r *Rule) SetKind(kind string) { } // Name returns the rule's target name. -// If the rule has no target name, Name returns the empty string. +// If the rule has no explicit target name, Name returns the implicit name if there is one, else the empty string. func (r *Rule) Name() string { - return r.AttrString("name") + explicitName := r.AttrString("name") + if explicitName == "" { + return r.ImplicitName + } + return explicitName } // AttrKeys returns the keys of all the rule's attributes. diff --git a/vendor/github.com/bazelbuild/buildtools/build/syntax.go b/vendor/github.com/bazelbuild/buildtools/build/syntax.go index 6f35529f97d..e47341bd7d2 100644 --- a/vendor/github.com/bazelbuild/buildtools/build/syntax.go +++ b/vendor/github.com/bazelbuild/buildtools/build/syntax.go @@ -57,9 +57,8 @@ type Expr interface { // A Comment represents a single # comment. type Comment struct { - Start Position - Token string // without trailing newline - Suffix bool // an end of line (not whole line) comment + Start Position + Token string // without trailing newline } // Comments collects the comments associated with an expression. @@ -87,12 +86,12 @@ type File struct { Stmt []Expr } -func (x *File) Span() (start, end Position) { - if len(x.Stmt) == 0 { +func (f *File) Span() (start, end Position) { + if len(f.Stmt) == 0 { return } - start, _ = x.Stmt[0].Span() - _, end = x.Stmt[len(x.Stmt)-1].Span() + start, _ = f.Stmt[0].Span() + _, end = f.Stmt[len(f.Stmt)-1].Span() return start, end } @@ -360,15 +359,17 @@ func (x *ParenExpr) Span() (start, end Position) { return x.Start, x.End.Pos.add(")") } -// A SliceExpr represents a slice expression: X[Y:Z]. +// A SliceExpr represents a slice expression: expr[from:to] or expr[from:to:step] . type SliceExpr struct { Comments - X Expr - SliceStart Position - Y Expr - Colon Position - Z Expr - End Position + X Expr + SliceStart Position + From Expr + FirstColon Position + To Expr + SecondColon Position + Step Expr + End Position } func (x *SliceExpr) Span() (start, end Position) { @@ -421,3 +422,74 @@ func (x *ConditionalExpr) Span() (start, end Position) { _, end = x.Else.Span() return start, end } + +// A CodeBlock represents an indented code block. +type CodeBlock struct { + Statements []Expr + Start Position + End +} + +func (x *CodeBlock) Span() (start, end Position) { + return x.Start, x.End.Pos +} + +// A FuncDef represents a function definition expression: def foo(List):. +type FuncDef struct { + Comments + Start Position // position of def + Name string + ListStart Position // position of ( + Args []Expr + Body CodeBlock + End // position of the end + ForceCompact bool // force compact (non-multiline) form when printing + ForceMultiLine bool // force multiline form when printing +} + +func (x *FuncDef) Span() (start, end Position) { + return x.Start, x.End.Pos +} + +// A ReturnExpr represents a return statement: return f(x). +type ReturnExpr struct { + Comments + Start Position + X Expr + End Position +} + +func (x *ReturnExpr) Span() (start, end Position) { + return x.Start, x.End +} + +// A ForLoop represents a for loop block: for x in range(10):. +type ForLoop struct { + Comments + Start Position // position of for + LoopVars []Expr + Iterable Expr + Body CodeBlock + End // position of the end +} + +func (x *ForLoop) Span() (start, end Position) { + return x.Start, x.End.Pos +} + +// An IfElse represents an if-else blocks sequence: if x: ... elif y: ... else: ... . +type IfElse struct { + Comments + Start Position // position of if + Conditions []Condition + End // position of the end +} + +type Condition struct { + If Expr + Then CodeBlock +} + +func (x *IfElse) Span() (start, end Position) { + return x.Start, x.End.Pos +} diff --git a/vendor/github.com/bazelbuild/buildtools/build/walk.go b/vendor/github.com/bazelbuild/buildtools/build/walk.go index 1de19335414..dadd7e3e478 100644 --- a/vendor/github.com/bazelbuild/buildtools/build/walk.go +++ b/vendor/github.com/bazelbuild/buildtools/build/walk.go @@ -72,11 +72,14 @@ func walk1(v *Expr, stack *[]Expr, f func(x Expr, stk []Expr) Expr) Expr { walk1(&v.Value, stack, f) case *SliceExpr: walk1(&v.X, stack, f) - if v.Y != nil { - walk1(&v.Y, stack, f) + if v.From != nil { + walk1(&v.From, stack, f) } - if v.Z != nil { - walk1(&v.Z, stack, f) + if v.To != nil { + walk1(&v.To, stack, f) + } + if v.Step != nil { + walk1(&v.Step, stack, f) } case *ParenExpr: walk1(&v.X, stack, f) diff --git a/vendor/github.com/bazelbuild/buildtools/build_proto/build.gen.pb.go b/vendor/github.com/bazelbuild/buildtools/build_proto/build.gen.pb.go index 3e974de16c6..68919e3919e 100644 --- a/vendor/github.com/bazelbuild/buildtools/build_proto/build.gen.pb.go +++ b/vendor/github.com/bazelbuild/buildtools/build_proto/build.gen.pb.go @@ -1,6 +1,5 @@ -// Code generated by protoc-gen-go. +// Code generated by protoc-gen-go. DO NOT EDIT. // source: build_proto/build.proto -// DO NOT EDIT! /* Package blaze_query is a generated protocol buffer package. diff --git a/vendor/github.com/bazelbuild/buildtools/buildozer/README.md b/vendor/github.com/bazelbuild/buildtools/buildozer/README.md index f83eb9c829d..d110e4b38db 100644 --- a/vendor/github.com/bazelbuild/buildtools/buildozer/README.md +++ b/vendor/github.com/bazelbuild/buildtools/buildozer/README.md @@ -92,6 +92,7 @@ Buildozer supports the following commands(`'command args'`): * `new [(before|after) ]`: Add a new rule at the end of the BUILD file (before/after ``). * `print ` + * `remove `: Removes attribute `attr`. * `remove `: Removes `value(s)` from the list `attr`. The wildcard `*` matches all attributes. Lists containing none of the `value(s)` are not modified. @@ -100,6 +101,13 @@ Buildozer supports the following commands(`'command args'`): * `replace `: Replaces `old_value` with `new_value` in the list `attr`. Wildcard `*` matches all attributes. Lists not containing `old_value` are not modified. + * `substitute `: Replaces strings which + match `old_regexp` in the list `attr` according to `new_template`. Wildcard + `*` matches all attributes. The regular expression must follow + [RE2 syntax](https://github.com/google/re2/wiki/Syntax). `new_template` may + be a simple replacement string, but it may also expand numbered or named + groups using `$0` or `$x`. Lists without strings that match `old_regexp` + are not modified. * `set `: Sets the value of an attribute. If the attribute was already present, its old value is replaced. * `set_if_absent `: Sets the value of an attribute. If the @@ -138,6 +146,9 @@ buildozer 'set kind java_library' //pkg:%gwt_module # Replace the dependency on pkg_v1 with a dependency on pkg_v2 buildozer 'replace deps //pkg_v1 //pkg_v2' //pkg:rule +# Replace all dependencies using regular expressions. +buildozer 'substitute deps //old/(.*) //new/${1}' //pkg:rule + # Delete the dependency on foo in every cc_library in the package buildozer 'remove deps foo' //pkg:%cc_library diff --git a/vendor/github.com/bazelbuild/buildtools/buildozer/main.go b/vendor/github.com/bazelbuild/buildtools/buildozer/main.go index e3baf2e36bf..6309dd7b398 100644 --- a/vendor/github.com/bazelbuild/buildtools/buildozer/main.go +++ b/vendor/github.com/bazelbuild/buildtools/buildozer/main.go @@ -38,6 +38,7 @@ var ( editVariables = flag.Bool("edit-variables", false, "For attributes that simply assign a variable (e.g. hdrs = LIB_HDRS), edit the build variable instead of appending to the attribute.") isPrintingProto = flag.Bool("output_proto", false, "output serialized devtools.buildozer.Output protos instead of human-readable strings.") tablesPath = flag.String("tables", "", "path to JSON file with custom table definitions which will replace the built-in tables") + addTablesPath = flag.String("add_tables", "", "path to JSON file with custom table definitions which will be merged with the built-in tables") shortenLabelsFlag = flag.Bool("shorten_labels", true, "convert added labels to short form, e.g. //foo:bar => :bar") deleteWithComments = flag.Bool("delete_with_comments", true, "If a list attribute should be deleted even if there is a comment attached to it") @@ -67,9 +68,16 @@ func main() { } } + if *addTablesPath != "" { + if err := tables.ParseAndUpdateJSONDefinitions(*addTablesPath, true); err != nil { + fmt.Fprintf(os.Stderr, "buildifier: failed to parse %s for -add_tables: %s\n", *addTablesPath, err) + os.Exit(2) + } + } + edit.ShortenLabelsFlag = *shortenLabelsFlag edit.DeleteWithComments = *deleteWithComments - edit.Opts = edit.Options{ + opts := &edit.Options{ Stdout: *stdout, Buildifier: *buildifier, Parallelism: *parallelism, @@ -83,5 +91,5 @@ func main() { EditVariables: *editVariables, IsPrintingProto: *isPrintingProto, } - os.Exit(edit.Buildozer(flag.Args())) + os.Exit(edit.Buildozer(opts, flag.Args())) } diff --git a/vendor/github.com/bazelbuild/buildtools/edit/BUILD b/vendor/github.com/bazelbuild/buildtools/edit/BUILD index 045a980651d..273982d0db6 100644 --- a/vendor/github.com/bazelbuild/buildtools/edit/BUILD +++ b/vendor/github.com/bazelbuild/buildtools/edit/BUILD @@ -17,6 +17,7 @@ go_library( "//vendor/github.com/bazelbuild/buildtools/build_proto:go_default_library", "//vendor/github.com/bazelbuild/buildtools/file:go_default_library", "//vendor/github.com/bazelbuild/buildtools/lang:go_default_library", + "//vendor/github.com/bazelbuild/buildtools/tables:go_default_library", "//vendor/github.com/bazelbuild/buildtools/wspace:go_default_library", "//vendor/github.com/golang/protobuf/proto:go_default_library", ], diff --git a/vendor/github.com/bazelbuild/buildtools/edit/buildozer.go b/vendor/github.com/bazelbuild/buildtools/edit/buildozer.go index 5bd618ebbbc..51ee4573173 100644 --- a/vendor/github.com/bazelbuild/buildtools/edit/buildozer.go +++ b/vendor/github.com/bazelbuild/buildtools/edit/buildozer.go @@ -53,8 +53,10 @@ type Options struct { IsPrintingProto bool // output serialized devtools.buildozer.Output protos instead of human-readable strings } -// Opts represents the options to be used by buildozer, and can be overriden before calling Buildozer. -var Opts = Options{NumIO: 200, PreferEOLComments: true} +// NewOpts returns a new Options struct with some defaults set. +func NewOpts() *Options { + return &Options{NumIO: 200, PreferEOLComments: true} +} // Usage is a user-overriden func to print the program usage. var Usage = func() {} @@ -75,7 +77,7 @@ type CmdEnvironment struct { // The cmdXXX functions implement the various commands. -func cmdAdd(env CmdEnvironment) (*build.File, error) { +func cmdAdd(opts *Options, env CmdEnvironment) (*build.File, error) { attr := env.Args[0] for _, val := range env.Args[1:] { if IsIntList(attr) { @@ -88,14 +90,14 @@ func cmdAdd(env CmdEnvironment) (*build.File, error) { return env.File, nil } -func cmdComment(env CmdEnvironment) (*build.File, error) { +func cmdComment(opts *Options, env CmdEnvironment) (*build.File, error) { // The comment string is always the last argument in the list. str := env.Args[len(env.Args)-1] str = strings.Replace(str, "\\n", "\n", -1) // Multiline comments should go on a separate line. - fullLine := !Opts.PreferEOLComments || strings.Contains(str, "\n") + fullLine := !opts.PreferEOLComments || strings.Contains(str, "\n") str = strings.Replace("# "+str, "\n", "\n# ", -1) - comment := []build.Comment{build.Comment{Token: str}} + comment := []build.Comment{{Token: str}} // The comment might be attached to a rule, an attribute, or a value in a list, // depending on how many arguments are passed. @@ -139,7 +141,7 @@ func commentsText(comments []build.Comment) string { return strings.Replace(strings.Join(segments, " "), "\n", " ", -1) } -func cmdPrintComment(env CmdEnvironment) (*build.File, error) { +func cmdPrintComment(opts *Options, env CmdEnvironment) (*build.File, error) { attrError := func() error { return fmt.Errorf("rule \"//%s:%s\" has no attribute \"%s\"", env.Pkg, env.Rule.Name(), env.Args[0]) } @@ -147,7 +149,7 @@ func cmdPrintComment(env CmdEnvironment) (*build.File, error) { switch len(env.Args) { case 0: // Print rule comment. env.output.Fields = []*apipb.Output_Record_Field{ - &apipb.Output_Record_Field{Value: &apipb.Output_Record_Field_Text{commentsText(env.Rule.Call.Comments.Before)}}, + {Value: &apipb.Output_Record_Field_Text{commentsText(env.Rule.Call.Comments.Before)}}, } case 1: // Print attribute comment. attr := env.Rule.AttrDefn(env.Args[0]) @@ -156,7 +158,7 @@ func cmdPrintComment(env CmdEnvironment) (*build.File, error) { } comments := append(attr.Before, attr.Suffix...) env.output.Fields = []*apipb.Output_Record_Field{ - &apipb.Output_Record_Field{Value: &apipb.Output_Record_Field_Text{commentsText(comments)}}, + {Value: &apipb.Output_Record_Field_Text{commentsText(comments)}}, } case 2: // Print comment of a specific value in a list. attr := env.Rule.Attr(env.Args[0]) @@ -170,7 +172,7 @@ func cmdPrintComment(env CmdEnvironment) (*build.File, error) { } comments := append(expr.Comments.Before, expr.Comments.Suffix...) env.output.Fields = []*apipb.Output_Record_Field{ - &apipb.Output_Record_Field{Value: &apipb.Output_Record_Field_Text{commentsText(comments)}}, + {Value: &apipb.Output_Record_Field_Text{commentsText(comments)}}, } default: panic("cmdPrintComment") @@ -178,11 +180,11 @@ func cmdPrintComment(env CmdEnvironment) (*build.File, error) { return nil, nil } -func cmdDelete(env CmdEnvironment) (*build.File, error) { +func cmdDelete(opts *Options, env CmdEnvironment) (*build.File, error) { return DeleteRule(env.File, env.Rule), nil } -func cmdMove(env CmdEnvironment) (*build.File, error) { +func cmdMove(opts *Options, env CmdEnvironment) (*build.File, error) { oldAttr := env.Args[0] newAttr := env.Args[1] if len(env.Args) == 3 && env.Args[2] == "*" { @@ -204,7 +206,7 @@ func cmdMove(env CmdEnvironment) (*build.File, error) { return nil, nil } -func cmdNew(env CmdEnvironment) (*build.File, error) { +func cmdNew(opts *Options, env CmdEnvironment) (*build.File, error) { kind := env.Args[0] name := env.Args[1] addAtEOF, insertionIndex, err := findInsertionIndex(env) @@ -217,7 +219,7 @@ func cmdNew(env CmdEnvironment) (*build.File, error) { } call := &build.CallExpr{X: &build.LiteralExpr{Token: kind}} - rule := &build.Rule{Call: call} + rule := &build.Rule{call, ""} rule.SetAttr("name", &build.StringExpr{Value: name}) if addAtEOF { @@ -235,7 +237,7 @@ func findInsertionIndex(env CmdEnvironment) (bool, int, error) { } relativeToRuleName := env.Args[3] - ruleIdx := IndexOfRuleByName(env.File, relativeToRuleName) + ruleIdx, _ := IndexOfRuleByName(env.File, relativeToRuleName) if ruleIdx == -1 { return true, 0, nil } @@ -250,12 +252,12 @@ func findInsertionIndex(env CmdEnvironment) (bool, int, error) { } } -func cmdNewLoad(env CmdEnvironment) (*build.File, error) { +func cmdNewLoad(opts *Options, env CmdEnvironment) (*build.File, error) { env.File.Stmt = InsertLoad(env.File.Stmt, env.Args) return env.File, nil } -func cmdPrint(env CmdEnvironment) (*build.File, error) { +func cmdPrint(opts *Options, env CmdEnvironment) (*build.File, error) { format := env.Args if len(format) == 0 { format = []string{"name", "kind"} @@ -266,8 +268,10 @@ func cmdPrint(env CmdEnvironment) (*build.File, error) { value := env.Rule.Attr(str) if str == "kind" { fields[i] = &apipb.Output_Record_Field{Value: &apipb.Output_Record_Field_Text{env.Rule.Kind()}} + } else if str == "name" { + fields[i] = &apipb.Output_Record_Field{Value: &apipb.Output_Record_Field_Text{env.Rule.Name()}} } else if str == "label" { - if env.Rule.Attr("name") != nil { + if env.Rule.Name() != "" { fields[i] = &apipb.Output_Record_Field{Value: &apipb.Output_Record_Field_Text{fmt.Sprintf("//%s:%s", env.Pkg, env.Rule.Name())}} } else { return nil, nil @@ -310,7 +314,7 @@ func attrKeysForPattern(rule *build.Rule, pattern string) []string { return []string{pattern} } -func cmdRemove(env CmdEnvironment) (*build.File, error) { +func cmdRemove(opts *Options, env CmdEnvironment) (*build.File, error) { if len(env.Args) == 1 { // Remove the attribute if env.Rule.DelAttr(env.Args[0]) != nil { return env.File, nil @@ -330,7 +334,7 @@ func cmdRemove(env CmdEnvironment) (*build.File, error) { return nil, nil } -func cmdRename(env CmdEnvironment) (*build.File, error) { +func cmdRename(opts *Options, env CmdEnvironment) (*build.File, error) { oldAttr := env.Args[0] newAttr := env.Args[1] if err := RenameAttribute(env.Rule, oldAttr, newAttr); err != nil { @@ -339,7 +343,7 @@ func cmdRename(env CmdEnvironment) (*build.File, error) { return env.File, nil } -func cmdReplace(env CmdEnvironment) (*build.File, error) { +func cmdReplace(opts *Options, env CmdEnvironment) (*build.File, error) { oldV := env.Args[1] newV := env.Args[2] for _, key := range attrKeysForPattern(env.Rule, env.Args[0]) { @@ -355,7 +359,27 @@ func cmdReplace(env CmdEnvironment) (*build.File, error) { return env.File, nil } -func cmdSet(env CmdEnvironment) (*build.File, error) { +func cmdSubstitute(opts *Options, env CmdEnvironment) (*build.File, error) { + oldRegexp, err := regexp.Compile(env.Args[1]) + if err != nil { + return nil, err + } + newTemplate := env.Args[2] + for _, key := range attrKeysForPattern(env.Rule, env.Args[0]) { + attr := env.Rule.Attr(key) + e, ok := attr.(*build.StringExpr) + if !ok { + ListSubstitute(attr, oldRegexp, newTemplate) + continue + } + if newValue, ok := stringSubstitute(e.Value, oldRegexp, newTemplate); ok { + env.Rule.SetAttr(key, getAttrValueExpr(key, []string{newValue})) + } + } + return env.File, nil +} + +func cmdSet(opts *Options, env CmdEnvironment) (*build.File, error) { attr := env.Args[0] args := env.Args[1:] if attr == "kind" { @@ -366,7 +390,7 @@ func cmdSet(env CmdEnvironment) (*build.File, error) { return env.File, nil } -func cmdSetIfAbsent(env CmdEnvironment) (*build.File, error) { +func cmdSetIfAbsent(opts *Options, env CmdEnvironment) (*build.File, error) { attr := env.Args[0] args := env.Args[1:] if attr == "kind" { @@ -401,14 +425,14 @@ func getAttrValueExpr(attr string, args []string) build.Expr { } } -func cmdCopy(env CmdEnvironment) (*build.File, error) { +func cmdCopy(opts *Options, env CmdEnvironment) (*build.File, error) { attrName := env.Args[0] from := env.Args[1] return copyAttributeBetweenRules(env, attrName, from) } -func cmdCopyNoOverwrite(env CmdEnvironment) (*build.File, error) { +func cmdCopyNoOverwrite(opts *Options, env CmdEnvironment) (*build.File, error) { attrName := env.Args[0] from := env.Args[1] @@ -438,7 +462,7 @@ func copyAttributeBetweenRules(env CmdEnvironment, attrName string, from string) return env.File, nil } -func cmdFix(env CmdEnvironment) (*build.File, error) { +func cmdFix(opts *Options, env CmdEnvironment) (*build.File, error) { // Fix the whole file if env.Rule.Kind() == "package" { return FixFile(env.File, env.Pkg, env.Args), nil @@ -449,7 +473,7 @@ func cmdFix(env CmdEnvironment) (*build.File, error) { // CommandInfo provides a command function and info on incoming arguments. type CommandInfo struct { - Fn func(CmdEnvironment) (*build.File, error) + Fn func(*Options, CmdEnvironment) (*build.File, error) MinArg int MaxArg int Template string @@ -470,6 +494,7 @@ var AllCommands = map[string]CommandInfo{ "remove": {cmdRemove, 1, -1, " "}, "rename": {cmdRename, 2, 2, " "}, "replace": {cmdReplace, 3, 3, " "}, + "substitute": {cmdSubstitute, 3, 3, " "}, "set": {cmdSet, 2, -1, " "}, "set_if_absent": {cmdSetIfAbsent, 2, -1, " "}, "copy": {cmdCopy, 2, 2, " "}, @@ -500,13 +525,13 @@ func expandTargets(f *build.File, rule string) ([]*build.Rule, error) { return nil, fmt.Errorf("rule '%s' not found", rule) } -func filterRules(rules []*build.Rule) (result []*build.Rule) { - if len(Opts.FilterRuleTypes) == 0 { +func filterRules(opts *Options, rules []*build.Rule) (result []*build.Rule) { + if len(opts.FilterRuleTypes) == 0 { return rules } for _, rule := range rules { acceptableType := false - for _, filterType := range Opts.FilterRuleTypes { + for _, filterType := range opts.FilterRuleTypes { if rule.Kind() == filterType { acceptableType = true break @@ -634,7 +659,7 @@ var buildFileNamesSet = map[string]bool{ // rewrite parses the BUILD file for the given file, transforms the AST, // and write the changes back in the file (or on stdout). -func rewrite(commandsForFile commandsForFile) *rewriteResult { +func rewrite(opts *Options, commandsForFile commandsForFile) *rewriteResult { name := commandsForFile.file var data []byte var err error @@ -676,7 +701,7 @@ func rewrite(commandsForFile commandsForFile) *rewriteResult { } vars := map[string]*build.BinaryExpr{} - if Opts.EditVariables { + if opts.EditVariables { vars = getGlobalVariables(f.Stmt) } var errs []error @@ -684,7 +709,7 @@ func rewrite(commandsForFile commandsForFile) *rewriteResult { for _, commands := range commandsForFile.commands { target := commands.target commands := commands.commands - _, absPkg, rule := InterpretLabelForWorkspaceLocation(Opts.RootDir, target) + _, absPkg, rule := InterpretLabelForWorkspaceLocation(opts.RootDir, target) _, pkg, _ := ParseLabel(target) if pkg == stdinPackageName { // Special-case: This is already absolute absPkg = stdinPackageName @@ -694,23 +719,23 @@ func rewrite(commandsForFile commandsForFile) *rewriteResult { if err != nil { cerr := commandError(commands, target, err) errs = append(errs, cerr) - if !Opts.KeepGoing { + if !opts.KeepGoing { return &rewriteResult{file: name, errs: errs, records: records} } } - targets = filterRules(targets) + targets = filterRules(opts, targets) for _, cmd := range commands { for _, r := range targets { cmdInfo := AllCommands[cmd.tokens[0]] record := &apipb.Output_Record{} - newf, err := cmdInfo.Fn(CmdEnvironment{f, r, vars, absPkg, cmd.tokens[1:], record}) + newf, err := cmdInfo.Fn(opts, CmdEnvironment{f, r, vars, absPkg, cmd.tokens[1:], record}) if len(record.Fields) != 0 { records = append(records, record) } if err != nil { cerr := commandError([]command{cmd}, target, err) - if Opts.KeepGoing { + if opts.KeepGoing { errs = append(errs, cerr) } else { return &rewriteResult{file: name, errs: []error{cerr}, records: records} @@ -727,12 +752,12 @@ func rewrite(commandsForFile commandsForFile) *rewriteResult { return &rewriteResult{file: name, errs: errs, records: records} } f = RemoveEmptyPackage(f) - ndata, err := runBuildifier(f) + ndata, err := runBuildifier(opts, f) if err != nil { return &rewriteResult{file: name, errs: []error{fmt.Errorf("running buildifier: %v", err)}, records: records} } - if Opts.Stdout || name == stdinPackageName { + if opts.Stdout || name == stdinPackageName { os.Stdout.Write(ndata) return &rewriteResult{file: name, errs: errs, records: records} } @@ -760,15 +785,15 @@ var EditFile = func(fi os.FileInfo, name string) error { } // runBuildifier formats the build file f. -// Runs Opts.Buildifier if it's non-empty, otherwise uses built-in formatter. -// Opts.Buildifier is useful to force consistency with other tools that call Buildifier. -func runBuildifier(f *build.File) ([]byte, error) { - if Opts.Buildifier == "" { +// Runs opts.Buildifier if it's non-empty, otherwise uses built-in formatter. +// opts.Buildifier is useful to force consistency with other tools that call Buildifier. +func runBuildifier(opts *Options, f *build.File) ([]byte, error) { + if opts.Buildifier == "" { build.Rewrite(f, nil) return build.Format(f), nil } - cmd := exec.Command(Opts.Buildifier) + cmd := exec.Command(opts.Buildifier) data := build.Format(f) cmd.Stdin = bytes.NewBuffer(data) stdout := bytes.NewBuffer(nil) @@ -787,9 +812,9 @@ func runBuildifier(f *build.File) ([]byte, error) { // Given a target, whose package may contain a trailing "/...", returns all // extisting BUILD file paths which match the package. -func targetExpressionToBuildFiles(target string) []string { - file, _, _ := InterpretLabelForWorkspaceLocation(Opts.RootDir, target) - if Opts.RootDir == "" { +func targetExpressionToBuildFiles(opts *Options, target string) []string { + file, _, _ := InterpretLabelForWorkspaceLocation(opts.RootDir, target) + if opts.RootDir == "" { var err error if file, err = filepath.Abs(file); err != nil { fmt.Printf("Cannot make path absolute: %s\n", err.Error()) @@ -827,7 +852,7 @@ func targetExpressionToBuildFiles(target string) []string { // appendCommands adds the given commands to be applied to each of the given targets // via the commandMap. -func appendCommands(commandMap map[string][]commandsForTarget, args []string) { +func appendCommands(opts *Options, commandMap map[string][]commandsForTarget, args []string) { commands, targets := parseCommands(args) for _, target := range targets { if strings.HasSuffix(target, "/BUILD") { @@ -838,7 +863,7 @@ func appendCommands(commandMap map[string][]commandsForTarget, args []string) { if pkg == stdinPackageName { buildFiles = []string{stdinPackageName} } else { - buildFiles = targetExpressionToBuildFiles(target) + buildFiles = targetExpressionToBuildFiles(opts, target) } for _, file := range buildFiles { @@ -847,12 +872,12 @@ func appendCommands(commandMap map[string][]commandsForTarget, args []string) { } } -func appendCommandsFromFile(commandsByFile map[string][]commandsForTarget, fileName string) { +func appendCommandsFromFile(opts *Options, commandsByFile map[string][]commandsForTarget, fileName string) { var reader io.Reader - if Opts.CommandsFile == stdinPackageName { + if opts.CommandsFile == stdinPackageName { reader = os.Stdin } else { - rc := file.OpenReadFile(Opts.CommandsFile) + rc := file.OpenReadFile(opts.CommandsFile) reader = rc defer rc.Close() } @@ -863,7 +888,7 @@ func appendCommandsFromFile(commandsByFile map[string][]commandsForTarget, fileN continue } args := strings.Split(line, "|") - appendCommands(commandsByFile, args) + appendCommands(opts, commandsByFile, args) } if err := scanner.Err(); err != nil { fmt.Fprintf(os.Stderr, "Error while reading commands file: %v", scanner.Err()) @@ -905,28 +930,28 @@ func printRecord(writer io.Writer, record *apipb.Output_Record) { } // Buildozer loops over all arguments on the command line fixing BUILD files. -func Buildozer(args []string) int { +func Buildozer(opts *Options, args []string) int { commandsByFile := make(map[string][]commandsForTarget) - if Opts.CommandsFile != "" { - appendCommandsFromFile(commandsByFile, Opts.CommandsFile) + if opts.CommandsFile != "" { + appendCommandsFromFile(opts, commandsByFile, opts.CommandsFile) } else { if len(args) == 0 { Usage() } - appendCommands(commandsByFile, args) + appendCommands(opts, commandsByFile, args) } numFiles := len(commandsByFile) - if Opts.Parallelism > 0 { - runtime.GOMAXPROCS(Opts.Parallelism) + if opts.Parallelism > 0 { + runtime.GOMAXPROCS(opts.Parallelism) } results := make(chan *rewriteResult, numFiles) data := make(chan commandsForFile) - for i := 0; i < Opts.NumIO; i++ { + for i := 0; i < opts.NumIO; i++ { go func(results chan *rewriteResult, data chan commandsForFile) { for commandsForFile := range data { - results <- rewrite(commandsForFile) + results <- rewrite(opts, commandsForFile) } }(results, data) } @@ -946,7 +971,7 @@ func Buildozer(args []string) int { for _, err := range fileResults.errs { fmt.Fprintf(os.Stderr, "%s: %s\n", fileResults.file, err) } - if fileResults.modified && !Opts.Quiet { + if fileResults.modified && !opts.Quiet { fmt.Fprintf(os.Stderr, "fixed %s\n", fileResults.file) } if fileResults.records != nil { @@ -954,7 +979,7 @@ func Buildozer(args []string) int { } } - if Opts.IsPrintingProto { + if opts.IsPrintingProto { data, err := proto.Marshal(&apipb.Output{Records: records}) if err != nil { log.Fatal("marshaling error: ", err) @@ -969,7 +994,7 @@ func Buildozer(args []string) int { if hasErrors { return 2 } - if !fileModified && !Opts.Stdout { + if !fileModified && !opts.Stdout { return 3 } return 0 diff --git a/vendor/github.com/bazelbuild/buildtools/edit/edit.go b/vendor/github.com/bazelbuild/buildtools/edit/edit.go index c9b541fb595..1d54984d16b 100644 --- a/vendor/github.com/bazelbuild/buildtools/edit/edit.go +++ b/vendor/github.com/bazelbuild/buildtools/edit/edit.go @@ -20,11 +20,13 @@ import ( "os" "path" "path/filepath" + "regexp" "sort" "strconv" "strings" "github.com/bazelbuild/buildtools/build" + "github.com/bazelbuild/buildtools/tables" "github.com/bazelbuild/buildtools/wspace" ) @@ -55,7 +57,7 @@ func ParseLabel(target string) (string, string, string) { parts := strings.SplitN(target, ":", 2) parts[0] = strings.TrimPrefix(parts[0], "//") if len(parts) == 1 { - if strings.HasPrefix(target, "//") { + if strings.HasPrefix(target, "//") || tables.StripLabelLeadingSlashes { // "//absolute/pkg" -> "absolute/pkg", "pkg" return repo, parts[0], path.Base(parts[0]) } @@ -164,7 +166,7 @@ func ExprToRule(expr build.Expr, kind string) (*build.Rule, bool) { if !ok || k.Token != kind { return nil, false } - return &build.Rule{Call: call}, true + return &build.Rule{call, ""}, true } // ExistingPackageDeclaration returns the package declaration, or nil if there is none. @@ -200,7 +202,7 @@ func PackageDeclaration(f *build.File) *build.Rule { all = append(all, call) } f.Stmt = all - return &build.Rule{Call: call} + return &build.Rule{call, ""} } // RemoveEmptyPackage removes empty package declarations from the file, i.e.: @@ -274,49 +276,12 @@ func FindRuleByName(f *build.File, name string) *build.Rule { if name == "__pkg__" { return PackageDeclaration(f) } - i := IndexOfRuleByName(f, name) - if i != -1 { - return &build.Rule{Call: f.Stmt[i].(*build.CallExpr)} - } - return nil -} - -// UseImplicitName returns the rule in the file if it meets these conditions: -// - It is the only unnamed rule in the file. -// - The file path's ending directory name and the passed rule name match. -// In the Pants Build System, by pantsbuild, the use of an implicit name makes -// creating targets easier. This function implements such names. -func UseImplicitName(f *build.File, rule string) *build.Rule { - // We disallow empty names - if f.Path == "BUILD" { - return nil - } - ruleCount := 0 - var temp, found *build.Rule - pkg := filepath.Base(filepath.Dir(f.Path)) - - for _, stmt := range f.Stmt { - call, ok := stmt.(*build.CallExpr) - if !ok { - continue - } - temp = &build.Rule{Call: call} - if temp.Kind() != "" && temp.Name() == "" { - ruleCount++ - found = temp - } - } - - if ruleCount == 1 { - if rule == pkg { - return found - } - } - return nil + _, rule := IndexOfRuleByName(f, name) + return rule } // IndexOfRuleByName returns the index (in f.Stmt) of the CallExpr which defines a rule named `name`, or -1 if it doesn't exist. -func IndexOfRuleByName(f *build.File, name string) int { +func IndexOfRuleByName(f *build.File, name string) (int, *build.Rule) { linenum := -1 if strings.HasPrefix(name, "%") { // "%" will match the rule which begins at LINENUM. @@ -331,13 +296,13 @@ func IndexOfRuleByName(f *build.File, name string) int { if !ok { continue } - r := &build.Rule{Call: call} + r := f.Rule(call) start, _ := call.X.Span() if r.Name() == name || start.Line == linenum { - return i + return i, r } } - return -1 + return -1, nil } // FindExportedFile returns the first exports_files call which contains the @@ -377,7 +342,7 @@ func DeleteRuleByName(f *build.File, name string) *build.File { all = append(all, stmt) continue } - r := &build.Rule{Call: call} + r := f.Rule(call) if r.Name() != name { all = append(all, stmt) } @@ -537,6 +502,42 @@ func ListReplace(e build.Expr, old, value, pkg string) bool { return replaced } +// ListSubstitute replaces strings matching a regular expression in all lists +// in e and returns a Boolean to indicate whether the replacement was +// successful. +func ListSubstitute(e build.Expr, oldRegexp *regexp.Regexp, newTemplate string) bool { + substituted := false + for _, li := range AllLists(e) { + for k, elem := range li.List { + str, ok := elem.(*build.StringExpr) + if !ok { + continue + } + newValue, ok := stringSubstitute(str.Value, oldRegexp, newTemplate) + if ok { + li.List[k] = &build.StringExpr{Value: newValue, Comments: *elem.Comment()} + substituted = true + } + } + } + return substituted +} + +func stringSubstitute(oldValue string, oldRegexp *regexp.Regexp, newTemplate string) (string, bool) { + match := oldRegexp.FindStringSubmatchIndex(oldValue) + if match == nil { + return oldValue, false + } + newValue := string(oldRegexp.ExpandString(nil, newTemplate, oldValue, match)) + if match[0] > 0 { + newValue = oldValue[:match[0]] + newValue + } + if match[1] < len(oldValue) { + newValue = newValue + oldValue[match[1]:] + } + return newValue, true +} + // isExprLessThan compares two Expr statements. Currently, only labels are supported. func isExprLessThan(x1, x2 build.Expr) bool { str1, ok1 := x1.(*build.StringExpr) diff --git a/vendor/github.com/bazelbuild/buildtools/edit/types.go b/vendor/github.com/bazelbuild/buildtools/edit/types.go index 2b55328ac71..4c7ff0aa454 100644 --- a/vendor/github.com/bazelbuild/buildtools/edit/types.go +++ b/vendor/github.com/bazelbuild/buildtools/edit/types.go @@ -17,12 +17,22 @@ package edit import ( buildpb "github.com/bazelbuild/buildtools/build_proto" "github.com/bazelbuild/buildtools/lang" + "github.com/bazelbuild/buildtools/tables" ) var typeOf = lang.TypeOf // IsList returns true for all attributes whose type is a list. func IsList(attr string) bool { + overrideValue, isOverridden := tables.IsListArg[attr] + if isOverridden { + return overrideValue + } + // It stands to reason that a sortable list must be a list. + isSortableList := tables.IsSortableListArg[attr] + if isSortableList { + return true + } ty := typeOf[attr] return ty == buildpb.Attribute_STRING_LIST || ty == buildpb.Attribute_LABEL_LIST || diff --git a/vendor/github.com/bazelbuild/buildtools/tables/jsonparser.go b/vendor/github.com/bazelbuild/buildtools/tables/jsonparser.go index 4c2b015b80e..ca2bc4443af 100644 --- a/vendor/github.com/bazelbuild/buildtools/tables/jsonparser.go +++ b/vendor/github.com/bazelbuild/buildtools/tables/jsonparser.go @@ -24,6 +24,7 @@ import ( type Definitions struct { IsLabelArg map[string]bool LabelBlacklist map[string]bool + IsListArg map[string]bool IsSortableListArg map[string]bool SortableBlacklist map[string]bool SortableWhitelist map[string]bool @@ -54,9 +55,9 @@ func ParseAndUpdateJSONDefinitions(file string, merge bool) error { } if merge { - MergeTables(definitions.IsLabelArg, definitions.LabelBlacklist, definitions.IsSortableListArg, definitions.SortableBlacklist, definitions.SortableWhitelist, definitions.NamePriority, definitions.StripLabelLeadingSlashes, definitions.ShortenAbsoluteLabelsToRelative) + MergeTables(definitions.IsLabelArg, definitions.LabelBlacklist, definitions.IsListArg, definitions.IsSortableListArg, definitions.SortableBlacklist, definitions.SortableWhitelist, definitions.NamePriority, definitions.StripLabelLeadingSlashes, definitions.ShortenAbsoluteLabelsToRelative) } else { - OverrideTables(definitions.IsLabelArg, definitions.LabelBlacklist, definitions.IsSortableListArg, definitions.SortableBlacklist, definitions.SortableWhitelist, definitions.NamePriority, definitions.StripLabelLeadingSlashes, definitions.ShortenAbsoluteLabelsToRelative) + OverrideTables(definitions.IsLabelArg, definitions.LabelBlacklist, definitions.IsListArg, definitions.IsSortableListArg, definitions.SortableBlacklist, definitions.SortableWhitelist, definitions.NamePriority, definitions.StripLabelLeadingSlashes, definitions.ShortenAbsoluteLabelsToRelative) } return nil } diff --git a/vendor/github.com/bazelbuild/buildtools/tables/tables.go b/vendor/github.com/bazelbuild/buildtools/tables/tables.go index 146c4ed1d7d..6e0f6b2ba8e 100644 --- a/vendor/github.com/bazelbuild/buildtools/tables/tables.go +++ b/vendor/github.com/bazelbuild/buildtools/tables/tables.go @@ -97,6 +97,11 @@ var LabelBlacklist = map[string]bool{ "package_group.includes": true, } +// By default, edit.types.IsList consults lang.TypeOf to determine if an arg is a list. +// You may override this using IsListArg. Specifying a name here overrides any value +// in lang.TypeOf. +var IsListArg = map[string]bool{} + // IsSortableListArg: a named argument to a rule call is considered to be a sortable list // if the name is one of these names. There is a separate blacklist for // rule-specific exceptions. @@ -200,10 +205,13 @@ var StripLabelLeadingSlashes = false var ShortenAbsoluteLabelsToRelative = false +var FormatBzlFiles = false + // OverrideTables allows a user of the build package to override the special-case rules. The user-provided tables replace the built-in tables. -func OverrideTables(labelArg, blacklist, sortableListArg, sortBlacklist, sortWhitelist map[string]bool, namePriority map[string]int, stripLabelLeadingSlashes, shortenAbsoluteLabelsToRelative bool) { +func OverrideTables(labelArg, blacklist, listArg, sortableListArg, sortBlacklist, sortWhitelist map[string]bool, namePriority map[string]int, stripLabelLeadingSlashes, shortenAbsoluteLabelsToRelative bool) { IsLabelArg = labelArg LabelBlacklist = blacklist + IsListArg = listArg IsSortableListArg = sortableListArg SortableBlacklist = sortBlacklist SortableWhitelist = sortWhitelist @@ -213,13 +221,16 @@ func OverrideTables(labelArg, blacklist, sortableListArg, sortBlacklist, sortWhi } // MergeTables allows a user of the build package to override the special-case rules. The user-provided tables are merged into the built-in tables. -func MergeTables(labelArg, blacklist, sortableListArg, sortBlacklist, sortWhitelist map[string]bool, namePriority map[string]int, stripLabelLeadingSlashes, shortenAbsoluteLabelsToRelative bool) { +func MergeTables(labelArg, blacklist, listArg, sortableListArg, sortBlacklist, sortWhitelist map[string]bool, namePriority map[string]int, stripLabelLeadingSlashes, shortenAbsoluteLabelsToRelative bool) { for k, v := range labelArg { IsLabelArg[k] = v } for k, v := range blacklist { LabelBlacklist[k] = v } + for k, v := range listArg { + IsListArg[k] = v + } for k, v := range sortableListArg { IsSortableListArg[k] = v } diff --git a/vendor/modules.txt b/vendor/modules.txt index b663ed19b94..978b8c8f6d2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -128,7 +128,7 @@ github.com/bazelbuild/bazel-gazelle/internal/rule github.com/bazelbuild/bazel-gazelle/internal/version github.com/bazelbuild/bazel-gazelle/internal/walk github.com/bazelbuild/bazel-gazelle/internal/wspace -# github.com/bazelbuild/buildtools v0.0.0-20180226164855-80c7f0d45d7e => github.com/bazelbuild/buildtools v0.0.0-20171220125010-1a9c38e0df93 +# github.com/bazelbuild/buildtools v0.0.0-20180226164855-80c7f0d45d7e => github.com/bazelbuild/buildtools v0.0.0-20180226164855-80c7f0d45d7e github.com/bazelbuild/buildtools/api_proto github.com/bazelbuild/buildtools/build github.com/bazelbuild/buildtools/build_proto