github.com/cheshirekow/buildtools@v0.0.0-20200224190056-5d637702fe81/build/syntax.go (about)

     1  /*
     2  Copyright 2016 Google Inc. All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   See the License for the specific language governing permissions and
    14   limitations under the License.
    15  */
    16  
    17  // Package build implements parsing and printing of BUILD files.
    18  package build
    19  
    20  // Syntax data structure definitions.
    21  
    22  import (
    23  	"strings"
    24  	"unicode/utf8"
    25  )
    26  
    27  // A Position describes the position between two bytes of input.
    28  type Position struct {
    29  	Line     int // line in input (starting at 1)
    30  	LineRune int // rune in line (starting at 1)
    31  	Byte     int // byte in input (starting at 0)
    32  }
    33  
    34  // add returns the position at the end of s, assuming it starts at p.
    35  func (p Position) add(s string) Position {
    36  	p.Byte += len(s)
    37  	if n := strings.Count(s, "\n"); n > 0 {
    38  		p.Line += n
    39  		s = s[strings.LastIndex(s, "\n")+1:]
    40  		p.LineRune = 1
    41  	}
    42  	p.LineRune += utf8.RuneCountInString(s)
    43  	return p
    44  }
    45  
    46  // An Expr represents an input element.
    47  type Expr interface {
    48  	// Span returns the start and end position of the expression,
    49  	// excluding leading or trailing comments.
    50  	Span() (start, end Position)
    51  
    52  	// Comment returns the comments attached to the expression.
    53  	// This method would normally be named 'Comments' but that
    54  	// would interfere with embedding a type of the same name.
    55  	Comment() *Comments
    56  }
    57  
    58  // A Comment represents a single # comment.
    59  type Comment struct {
    60  	Start Position
    61  	Token string // without trailing newline
    62  }
    63  
    64  // Comments collects the comments associated with an expression.
    65  type Comments struct {
    66  	Before []Comment // whole-line comments before this expression
    67  	Suffix []Comment // end-of-line comments after this expression
    68  
    69  	// For top-level expressions only, After lists whole-line
    70  	// comments following the expression.
    71  	After []Comment
    72  }
    73  
    74  // Comment returns the receiver. This isn't useful by itself, but
    75  // a Comments struct is embedded into all the expression
    76  // implementation types, and this gives each of those a Comment
    77  // method to satisfy the Expr interface.
    78  func (c *Comments) Comment() *Comments {
    79  	return c
    80  }
    81  
    82  // stmtsEnd returns the end position of the last non-nil statement
    83  func stmtsEnd(stmts []Expr) Position {
    84  	for i := len(stmts) - 1; i >= 0; i-- {
    85  		if stmts[i] != nil {
    86  			_, end := stmts[i].Span()
    87  			return end
    88  		}
    89  	}
    90  	return Position{}
    91  }
    92  
    93  // A File represents an entire BUILD or .bzl file.
    94  type File struct {
    95  	Path string // file path, relative to workspace directory
    96  	Pkg  string // optional; the package of the file
    97  	Type FileType
    98  	Comments
    99  	Stmt []Expr
   100  }
   101  
   102  // DisplayPath returns the filename if it's not empty, "<stdin>" otherwise
   103  func (f *File) DisplayPath() string {
   104  	if f.Path == "" {
   105  		return "<stdin>"
   106  	}
   107  	return f.Path
   108  }
   109  
   110  func (f *File) Span() (start, end Position) {
   111  	if len(f.Stmt) == 0 {
   112  		p := Position{Line: 1, LineRune: 1}
   113  		return p, p
   114  	}
   115  	start = Position{}
   116  	end = stmtsEnd(f.Stmt)
   117  	return start, end
   118  }
   119  
   120  // A CommentBlock represents a top-level block of comments separate
   121  // from any rule.
   122  type CommentBlock struct {
   123  	Comments
   124  	Start Position
   125  }
   126  
   127  func (x *CommentBlock) Span() (start, end Position) {
   128  	return x.Start, x.Start
   129  }
   130  
   131  // An Ident represents an identifier.
   132  type Ident struct {
   133  	Comments
   134  	NamePos Position
   135  	Name    string
   136  }
   137  
   138  func (x *Ident) Span() (start, end Position) {
   139  	return x.NamePos, x.NamePos.add(x.Name)
   140  }
   141  
   142  // BranchStmt represents a `pass`, `break`, or `continue` statement.
   143  type BranchStmt struct {
   144  	Comments
   145  	Token    string // pass, break, continue
   146  	TokenPos Position
   147  }
   148  
   149  func (x *BranchStmt) Span() (start, end Position) {
   150  	return x.TokenPos, x.TokenPos.add(x.Token)
   151  }
   152  
   153  func (x *Ident) asString() *StringExpr {
   154  	_, end := x.Span()
   155  	return &StringExpr{
   156  		Comments: x.Comments,
   157  		Start:    x.NamePos,
   158  		Value:    x.Name,
   159  		End:      end,
   160  	}
   161  }
   162  
   163  // A LiteralExpr represents a literal number.
   164  type LiteralExpr struct {
   165  	Comments
   166  	Start Position
   167  	Token string // identifier token
   168  }
   169  
   170  func (x *LiteralExpr) Span() (start, end Position) {
   171  	return x.Start, x.Start.add(x.Token)
   172  }
   173  
   174  // A StringExpr represents a single literal string.
   175  type StringExpr struct {
   176  	Comments
   177  	Start       Position
   178  	Value       string // string value (decoded)
   179  	TripleQuote bool   // triple quote output
   180  	End         Position
   181  
   182  	// To allow specific formatting of string literals,
   183  	// at least within our requirements, record the
   184  	// preferred form of Value. This field is a hint:
   185  	// it is only used if it is a valid quoted form for Value.
   186  	Token string
   187  }
   188  
   189  func (x *StringExpr) Span() (start, end Position) {
   190  	return x.Start, x.End
   191  }
   192  
   193  // An End represents the end of a parenthesized or bracketed expression.
   194  // It is a place to hang comments.
   195  type End struct {
   196  	Comments
   197  	Pos Position
   198  }
   199  
   200  func (x *End) Span() (start, end Position) {
   201  	return x.Pos, x.Pos.add(")")
   202  }
   203  
   204  // A CallExpr represents a function call expression: X(List).
   205  type CallExpr struct {
   206  	Comments
   207  	X              Expr
   208  	ListStart      Position // position of (
   209  	List           []Expr
   210  	End                 // position of )
   211  	ForceCompact   bool // force compact (non-multiline) form when printing
   212  	ForceMultiLine bool // force multiline form when printing
   213  }
   214  
   215  func (x *CallExpr) Span() (start, end Position) {
   216  	start, _ = x.X.Span()
   217  	return start, x.End.Pos.add(")")
   218  }
   219  
   220  // A DotExpr represents a field selector: X.Name.
   221  type DotExpr struct {
   222  	Comments
   223  	X       Expr
   224  	Dot     Position
   225  	NamePos Position
   226  	Name    string
   227  }
   228  
   229  func (x *DotExpr) Span() (start, end Position) {
   230  	start, _ = x.X.Span()
   231  	return start, x.NamePos.add(x.Name)
   232  }
   233  
   234  // A Comprehension represents a list comprehension expression: [X for ... if ...].
   235  type Comprehension struct {
   236  	Comments
   237  	Curly          bool // curly braces (as opposed to square brackets)
   238  	Lbrack         Position
   239  	Body           Expr
   240  	Clauses        []Expr // = *ForClause | *IfClause
   241  	ForceMultiLine bool   // split expression across multiple lines
   242  	End
   243  }
   244  
   245  func (x *Comprehension) Span() (start, end Position) {
   246  	return x.Lbrack, x.End.Pos.add("]")
   247  }
   248  
   249  // A ForClause represents a for clause in a list comprehension: for Var in Expr.
   250  type ForClause struct {
   251  	Comments
   252  	For  Position
   253  	Vars Expr
   254  	In   Position
   255  	X    Expr
   256  }
   257  
   258  func (x *ForClause) Span() (start, end Position) {
   259  	_, end = x.X.Span()
   260  	return x.For, end
   261  }
   262  
   263  // An IfClause represents an if clause in a list comprehension: if Cond.
   264  type IfClause struct {
   265  	Comments
   266  	If   Position
   267  	Cond Expr
   268  }
   269  
   270  func (x *IfClause) Span() (start, end Position) {
   271  	_, end = x.Cond.Span()
   272  	return x.If, end
   273  }
   274  
   275  // A KeyValueExpr represents a dictionary entry: Key: Value.
   276  type KeyValueExpr struct {
   277  	Comments
   278  	Key   Expr
   279  	Colon Position
   280  	Value Expr
   281  }
   282  
   283  func (x *KeyValueExpr) Span() (start, end Position) {
   284  	start, _ = x.Key.Span()
   285  	_, end = x.Value.Span()
   286  	return start, end
   287  }
   288  
   289  // A DictExpr represents a dictionary literal: { List }.
   290  type DictExpr struct {
   291  	Comments
   292  	Start Position
   293  	List  []Expr // all *KeyValueExprs
   294  	End
   295  	ForceMultiLine bool // force multiline form when printing
   296  }
   297  
   298  func (x *DictExpr) Span() (start, end Position) {
   299  	return x.Start, x.End.Pos.add("}")
   300  }
   301  
   302  // A ListExpr represents a list literal: [ List ].
   303  type ListExpr struct {
   304  	Comments
   305  	Start Position
   306  	List  []Expr
   307  	End
   308  	ForceMultiLine bool // force multiline form when printing
   309  }
   310  
   311  func (x *ListExpr) Span() (start, end Position) {
   312  	return x.Start, x.End.Pos.add("]")
   313  }
   314  
   315  // A SetExpr represents a set literal: { List }.
   316  type SetExpr struct {
   317  	Comments
   318  	Start Position
   319  	List  []Expr
   320  	End
   321  	ForceMultiLine bool // force multiline form when printing
   322  }
   323  
   324  func (x *SetExpr) Span() (start, end Position) {
   325  	return x.Start, x.End.Pos.add("}")
   326  }
   327  
   328  // A TupleExpr represents a tuple literal: (List)
   329  type TupleExpr struct {
   330  	Comments
   331  	NoBrackets bool // true if a tuple has no brackets, e.g. `a, b = x`
   332  	Start      Position
   333  	List       []Expr
   334  	End
   335  	ForceCompact   bool // force compact (non-multiline) form when printing
   336  	ForceMultiLine bool // force multiline form when printing
   337  }
   338  
   339  func (x *TupleExpr) Span() (start, end Position) {
   340  	if !x.NoBrackets {
   341  		return x.Start, x.End.Pos.add(")")
   342  	}
   343  	start, _ = x.List[0].Span()
   344  	_, end = x.List[len(x.List)-1].Span()
   345  	return start, end
   346  }
   347  
   348  // A UnaryExpr represents a unary expression: Op X.
   349  type UnaryExpr struct {
   350  	Comments
   351  	OpStart Position
   352  	Op      string
   353  	X       Expr
   354  }
   355  
   356  func (x *UnaryExpr) Span() (start, end Position) {
   357  	if x.X == nil {
   358  		return x.OpStart, x.OpStart
   359  	}
   360  	_, end = x.X.Span()
   361  	return x.OpStart, end
   362  }
   363  
   364  // A BinaryExpr represents a binary expression: X Op Y.
   365  type BinaryExpr struct {
   366  	Comments
   367  	X         Expr
   368  	OpStart   Position
   369  	Op        string
   370  	LineBreak bool // insert line break between Op and Y
   371  	Y         Expr
   372  }
   373  
   374  func (x *BinaryExpr) Span() (start, end Position) {
   375  	start, _ = x.X.Span()
   376  	_, end = x.Y.Span()
   377  	return start, end
   378  }
   379  
   380  // An AssignExpr represents a binary expression with `=`: LHS = RHS.
   381  type AssignExpr struct {
   382  	Comments
   383  	LHS       Expr
   384  	OpPos     Position
   385  	Op        string
   386  	LineBreak bool // insert line break between Op and RHS
   387  	RHS       Expr
   388  }
   389  
   390  func (x *AssignExpr) Span() (start, end Position) {
   391  	start, _ = x.LHS.Span()
   392  	_, end = x.RHS.Span()
   393  	return start, end
   394  }
   395  
   396  // A ParenExpr represents a parenthesized expression: (X).
   397  type ParenExpr struct {
   398  	Comments
   399  	Start Position
   400  	X     Expr
   401  	End
   402  	ForceMultiLine bool // insert line break after opening ( and before closing )
   403  }
   404  
   405  func (x *ParenExpr) Span() (start, end Position) {
   406  	return x.Start, x.End.Pos.add(")")
   407  }
   408  
   409  // A SliceExpr represents a slice expression: expr[from:to] or expr[from:to:step] .
   410  type SliceExpr struct {
   411  	Comments
   412  	X           Expr
   413  	SliceStart  Position
   414  	From        Expr
   415  	FirstColon  Position
   416  	To          Expr
   417  	SecondColon Position
   418  	Step        Expr
   419  	End         Position
   420  }
   421  
   422  func (x *SliceExpr) Span() (start, end Position) {
   423  	start, _ = x.X.Span()
   424  	return start, x.End.add("]")
   425  }
   426  
   427  // An IndexExpr represents an index expression: X[Y].
   428  type IndexExpr struct {
   429  	Comments
   430  	X          Expr
   431  	IndexStart Position
   432  	Y          Expr
   433  	End        Position
   434  }
   435  
   436  func (x *IndexExpr) Span() (start, end Position) {
   437  	start, _ = x.X.Span()
   438  	return start, x.End.add("]")
   439  }
   440  
   441  // A Function represents the common parts of LambdaExpr and DefStmt
   442  type Function struct {
   443  	Comments
   444  	StartPos Position // position of DEF or LAMBDA token
   445  	Params   []Expr
   446  	Body     []Expr
   447  }
   448  
   449  func (x *Function) Span() (start, end Position) {
   450  	_, end = x.Body[len(x.Body)-1].Span()
   451  	return x.StartPos, end
   452  }
   453  
   454  // A LambdaExpr represents a lambda expression: lambda Var: Expr.
   455  type LambdaExpr struct {
   456  	Comments
   457  	Function
   458  }
   459  
   460  func (x *LambdaExpr) Span() (start, end Position) {
   461  	return x.Function.Span()
   462  }
   463  
   464  // ConditionalExpr represents the conditional: X if TEST else ELSE.
   465  type ConditionalExpr struct {
   466  	Comments
   467  	Then      Expr
   468  	IfStart   Position
   469  	Test      Expr
   470  	ElseStart Position
   471  	Else      Expr
   472  }
   473  
   474  // Span returns the start and end position of the expression,
   475  // excluding leading or trailing comments.
   476  func (x *ConditionalExpr) Span() (start, end Position) {
   477  	start, _ = x.Then.Span()
   478  	_, end = x.Else.Span()
   479  	return start, end
   480  }
   481  
   482  // A LoadStmt loads another module and binds names from it:
   483  // load(Module, "x", y="foo").
   484  //
   485  // The AST is slightly unfaithful to the concrete syntax here because
   486  // Skylark's load statement, so that it can be implemented in Python,
   487  // binds some names (like y above) with an identifier and some (like x)
   488  // without.  For consistency we create fake identifiers for all the
   489  // strings.
   490  type LoadStmt struct {
   491  	Comments
   492  	Load         Position
   493  	Module       *StringExpr
   494  	From         []*Ident // name defined in loading module
   495  	To           []*Ident // name in loaded module
   496  	Rparen       End
   497  	ForceCompact bool // force compact (non-multiline) form when printing
   498  }
   499  
   500  func (x *LoadStmt) Span() (start, end Position) {
   501  	return x.Load, x.Rparen.Pos.add(")")
   502  }
   503  
   504  // A DefStmt represents a function definition expression: def foo(List):.
   505  type DefStmt struct {
   506  	Comments
   507  	Function
   508  	Name           string
   509  	ColonPos       Position // position of the ":"
   510  	ForceCompact   bool     // force compact (non-multiline) form when printing the arguments
   511  	ForceMultiLine bool     // force multiline form when printing the arguments
   512  }
   513  
   514  func (x *DefStmt) Span() (start, end Position) {
   515  	return x.Function.Span()
   516  }
   517  
   518  // HeaderSpan returns the span of the function header `def f(...):`
   519  func (x *DefStmt) HeaderSpan() (start, end Position) {
   520  	return x.Function.StartPos, x.ColonPos
   521  }
   522  
   523  // A ReturnStmt represents a return statement: return f(x).
   524  type ReturnStmt struct {
   525  	Comments
   526  	Return Position
   527  	Result Expr // may be nil
   528  }
   529  
   530  func (x *ReturnStmt) Span() (start, end Position) {
   531  	if x.Result == nil {
   532  		return x.Return, x.Return.add("return")
   533  	}
   534  	_, end = x.Result.Span()
   535  	return x.Return, end
   536  }
   537  
   538  // A ForStmt represents a for loop block: for x in range(10):.
   539  type ForStmt struct {
   540  	Comments
   541  	Function
   542  	For  Position // position of for
   543  	Vars Expr
   544  	X    Expr
   545  	Body []Expr
   546  }
   547  
   548  func (x *ForStmt) Span() (start, end Position) {
   549  	end = stmtsEnd(x.Body)
   550  	return x.For, end
   551  }
   552  
   553  // An IfStmt represents an if-else block: if x: ... else: ... .
   554  // `elif`s are treated as a chain of `IfStmt`s.
   555  type IfStmt struct {
   556  	Comments
   557  	If      Position // position of if
   558  	Cond    Expr
   559  	True    []Expr
   560  	ElsePos End    // position of else or elif
   561  	False   []Expr // optional
   562  }
   563  
   564  func (x *IfStmt) Span() (start, end Position) {
   565  	body := x.False
   566  	if body == nil {
   567  		body = x.True
   568  	}
   569  	end = stmtsEnd(body)
   570  	return x.If, end
   571  }