github.com/google/skylark@v0.0.0-20181101142754-a5f7082aabed/syntax/syntax.go (about)

     1  // Copyright 2017 The Bazel Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package syntax provides a Skylark parser and abstract syntax tree.
     6  package syntax
     7  
     8  // A Node is a node in a Skylark syntax tree.
     9  type Node interface {
    10  	// Span returns the start and end position of the expression.
    11  	Span() (start, end Position)
    12  
    13  	// Comments returns the comments associated with this node.
    14  	// It returns nil if RetainComments was not specified during parsing,
    15  	// or if AllocComments was not called.
    16  	Comments() *Comments
    17  
    18  	// AllocComments allocates a new Comments node if there was none.
    19  	// This makes possible to add new comments using Comments() method.
    20  	AllocComments()
    21  }
    22  
    23  // A Comment represents a single # comment.
    24  type Comment struct {
    25  	Start Position
    26  	Text  string // without trailing newline
    27  }
    28  
    29  // Comments collects the comments associated with an expression.
    30  type Comments struct {
    31  	Before []Comment // whole-line comments before this expression
    32  	Suffix []Comment // end-of-line comments after this expression (up to 1)
    33  
    34  	// For top-level expressions only, After lists whole-line
    35  	// comments following the expression.
    36  	After []Comment
    37  }
    38  
    39  // A commentsRef is a possibly-nil reference to a set of comments.
    40  // A commentsRef is embedded in each type of syntax node,
    41  // and provides its Comments and AllocComments methods.
    42  type commentsRef struct{ ref *Comments }
    43  
    44  // Comments returns the comments associated with a syntax node,
    45  // or nil if AllocComments has not yet been called.
    46  func (cr commentsRef) Comments() *Comments { return cr.ref }
    47  
    48  // AllocComments enables comments to be associated with a syntax node.
    49  func (cr *commentsRef) AllocComments() {
    50  	if cr.ref == nil {
    51  		cr.ref = new(Comments)
    52  	}
    53  }
    54  
    55  // Start returns the start position of the expression.
    56  func Start(n Node) Position {
    57  	start, _ := n.Span()
    58  	return start
    59  }
    60  
    61  // End returns the end position of the expression.
    62  func End(n Node) Position {
    63  	_, end := n.Span()
    64  	return end
    65  }
    66  
    67  // A File represents a Skylark file.
    68  type File struct {
    69  	commentsRef
    70  	Path  string
    71  	Stmts []Stmt
    72  
    73  	// set by resolver:
    74  	Locals  []*Ident // this file's (comprehension-)local variables
    75  	Globals []*Ident // this file's global variables
    76  }
    77  
    78  func (x *File) Span() (start, end Position) {
    79  	if len(x.Stmts) == 0 {
    80  		return
    81  	}
    82  	start, _ = x.Stmts[0].Span()
    83  	_, end = x.Stmts[len(x.Stmts)-1].Span()
    84  	return start, end
    85  }
    86  
    87  // A Stmt is a Skylark statement.
    88  type Stmt interface {
    89  	Node
    90  	stmt()
    91  }
    92  
    93  func (*AssignStmt) stmt() {}
    94  func (*BranchStmt) stmt() {}
    95  func (*DefStmt) stmt()    {}
    96  func (*ExprStmt) stmt()   {}
    97  func (*ForStmt) stmt()    {}
    98  func (*IfStmt) stmt()     {}
    99  func (*LoadStmt) stmt()   {}
   100  func (*ReturnStmt) stmt() {}
   101  
   102  // An AssignStmt represents an assignment:
   103  //	x = 0
   104  //	x, y = y, x
   105  // 	x += 1
   106  type AssignStmt struct {
   107  	commentsRef
   108  	OpPos Position
   109  	Op    Token // = EQ | {PLUS,MINUS,STAR,PERCENT}_EQ
   110  	LHS   Expr
   111  	RHS   Expr
   112  }
   113  
   114  func (x *AssignStmt) Span() (start, end Position) {
   115  	start, _ = x.LHS.Span()
   116  	_, end = x.RHS.Span()
   117  	return
   118  }
   119  
   120  // A Function represents the common parts of LambdaExpr and DefStmt.
   121  type Function struct {
   122  	commentsRef
   123  	StartPos Position // position of DEF or LAMBDA token
   124  	Params   []Expr   // param = ident | ident=expr | *ident | **ident
   125  	Body     []Stmt
   126  
   127  	// set by resolver:
   128  	HasVarargs bool     // whether params includes *args (convenience)
   129  	HasKwargs  bool     // whether params includes **kwargs (convenience)
   130  	Locals     []*Ident // this function's local variables, parameters first
   131  	FreeVars   []*Ident // enclosing local variables to capture in closure
   132  }
   133  
   134  func (x *Function) Span() (start, end Position) {
   135  	_, end = x.Body[len(x.Body)-1].Span()
   136  	return x.StartPos, end
   137  }
   138  
   139  // A DefStmt represents a function definition.
   140  type DefStmt struct {
   141  	commentsRef
   142  	Def  Position
   143  	Name *Ident
   144  	Function
   145  }
   146  
   147  func (x *DefStmt) Span() (start, end Position) {
   148  	_, end = x.Function.Body[len(x.Body)-1].Span()
   149  	return x.Def, end
   150  }
   151  
   152  // An ExprStmt is an expression evaluated for side effects.
   153  type ExprStmt struct {
   154  	commentsRef
   155  	X Expr
   156  }
   157  
   158  func (x *ExprStmt) Span() (start, end Position) {
   159  	return x.X.Span()
   160  }
   161  
   162  // An IfStmt is a conditional: If Cond: True; else: False.
   163  // 'elseif' is desugared into a chain of IfStmts.
   164  type IfStmt struct {
   165  	commentsRef
   166  	If      Position // IF or ELIF
   167  	Cond    Expr
   168  	True    []Stmt
   169  	ElsePos Position // ELSE or ELIF
   170  	False   []Stmt   // optional
   171  }
   172  
   173  func (x *IfStmt) Span() (start, end Position) {
   174  	body := x.False
   175  	if body == nil {
   176  		body = x.True
   177  	}
   178  	_, end = body[len(body)-1].Span()
   179  	return x.If, end
   180  }
   181  
   182  // A LoadStmt loads another module and binds names from it:
   183  // load(Module, "x", y="foo").
   184  //
   185  // The AST is slightly unfaithful to the concrete syntax here because
   186  // Skylark's load statement, so that it can be implemented in Python,
   187  // binds some names (like y above) with an identifier and some (like x)
   188  // without.  For consistency we create fake identifiers for all the
   189  // strings.
   190  type LoadStmt struct {
   191  	commentsRef
   192  	Load   Position
   193  	Module *Literal // a string
   194  	From   []*Ident // name defined in loading module
   195  	To     []*Ident // name in loaded module
   196  	Rparen Position
   197  }
   198  
   199  func (x *LoadStmt) Span() (start, end Position) {
   200  	return x.Load, x.Rparen
   201  }
   202  
   203  // ModuleName returns the name of the module loaded by this statement.
   204  func (x *LoadStmt) ModuleName() string { return x.Module.Value.(string) }
   205  
   206  // A BranchStmt changes the flow of control: break, continue, pass.
   207  type BranchStmt struct {
   208  	commentsRef
   209  	Token    Token // = BREAK | CONTINUE | PASS
   210  	TokenPos Position
   211  }
   212  
   213  func (x *BranchStmt) Span() (start, end Position) {
   214  	return x.TokenPos, x.TokenPos.add(x.Token.String())
   215  }
   216  
   217  // A ReturnStmt returns from a function.
   218  type ReturnStmt struct {
   219  	commentsRef
   220  	Return Position
   221  	Result Expr // may be nil
   222  }
   223  
   224  func (x *ReturnStmt) Span() (start, end Position) {
   225  	if x.Result == nil {
   226  		return x.Return, x.Return.add("return")
   227  	}
   228  	_, end = x.Result.Span()
   229  	return x.Return, end
   230  }
   231  
   232  // An Expr is a Skylark expression.
   233  type Expr interface {
   234  	Node
   235  	expr()
   236  }
   237  
   238  func (*BinaryExpr) expr()    {}
   239  func (*CallExpr) expr()      {}
   240  func (*Comprehension) expr() {}
   241  func (*CondExpr) expr()      {}
   242  func (*DictEntry) expr()     {}
   243  func (*DictExpr) expr()      {}
   244  func (*DotExpr) expr()       {}
   245  func (*Ident) expr()         {}
   246  func (*IndexExpr) expr()     {}
   247  func (*LambdaExpr) expr()    {}
   248  func (*ListExpr) expr()      {}
   249  func (*Literal) expr()       {}
   250  func (*ParenExpr) expr()     {}
   251  func (*SliceExpr) expr()     {}
   252  func (*TupleExpr) expr()     {}
   253  func (*UnaryExpr) expr()     {}
   254  
   255  // An Ident represents an identifier.
   256  type Ident struct {
   257  	commentsRef
   258  	NamePos Position
   259  	Name    string
   260  
   261  	// set by resolver:
   262  
   263  	Scope uint8 // see type resolve.Scope
   264  	Index int   // index into enclosing {DefStmt,File}.Locals (if scope==Local) or DefStmt.FreeVars (if scope==Free) or File.Globals (if scope==Global)
   265  }
   266  
   267  func (x *Ident) Span() (start, end Position) {
   268  	return x.NamePos, x.NamePos.add(x.Name)
   269  }
   270  
   271  // A Literal represents a literal string or number.
   272  type Literal struct {
   273  	commentsRef
   274  	Token    Token // = STRING | INT
   275  	TokenPos Position
   276  	Raw      string      // uninterpreted text
   277  	Value    interface{} // = string | int64 | *big.Int
   278  }
   279  
   280  func (x *Literal) Span() (start, end Position) {
   281  	return x.TokenPos, x.TokenPos.add(x.Raw)
   282  }
   283  
   284  // A ParenExpr represents a parenthesized expression: (X).
   285  type ParenExpr struct {
   286  	commentsRef
   287  	Lparen Position
   288  	X      Expr
   289  	Rparen Position
   290  }
   291  
   292  func (x *ParenExpr) Span() (start, end Position) {
   293  	return x.Lparen, x.Rparen.add(")")
   294  }
   295  
   296  // A CallExpr represents a function call expression: Fn(Args).
   297  type CallExpr struct {
   298  	commentsRef
   299  	Fn     Expr
   300  	Lparen Position
   301  	Args   []Expr // arg = expr | ident=expr | *expr | **expr
   302  	Rparen Position
   303  }
   304  
   305  func (x *CallExpr) Span() (start, end Position) {
   306  	start, _ = x.Fn.Span()
   307  	return start, x.Rparen.add(")")
   308  }
   309  
   310  // A DotExpr represents a field or method selector: X.Name.
   311  type DotExpr struct {
   312  	commentsRef
   313  	X       Expr
   314  	Dot     Position
   315  	NamePos Position
   316  	Name    *Ident
   317  }
   318  
   319  func (x *DotExpr) Span() (start, end Position) {
   320  	start, _ = x.X.Span()
   321  	_, end = x.Name.Span()
   322  	return
   323  }
   324  
   325  // A Comprehension represents a list or dict comprehension:
   326  // [Body for ... if ...] or {Body for ... if ...}
   327  type Comprehension struct {
   328  	commentsRef
   329  	Curly   bool // {x:y for ...} or {x for ...}, not [x for ...]
   330  	Lbrack  Position
   331  	Body    Expr
   332  	Clauses []Node // = *ForClause | *IfClause
   333  	Rbrack  Position
   334  }
   335  
   336  func (x *Comprehension) Span() (start, end Position) {
   337  	return x.Lbrack, x.Rbrack.add("]")
   338  }
   339  
   340  // A ForStmt represents a loop: for Vars in X: Body.
   341  type ForStmt struct {
   342  	commentsRef
   343  	For  Position
   344  	Vars Expr // name, or tuple of names
   345  	X    Expr
   346  	Body []Stmt
   347  }
   348  
   349  func (x *ForStmt) Span() (start, end Position) {
   350  	_, end = x.Body[len(x.Body)-1].Span()
   351  	return x.For, end
   352  }
   353  
   354  // A ForClause represents a for clause in a list comprehension: for Vars in X.
   355  type ForClause struct {
   356  	commentsRef
   357  	For  Position
   358  	Vars Expr // name, or tuple of names
   359  	In   Position
   360  	X    Expr
   361  }
   362  
   363  func (x *ForClause) Span() (start, end Position) {
   364  	_, end = x.X.Span()
   365  	return x.For, end
   366  }
   367  
   368  // An IfClause represents an if clause in a list comprehension: if Cond.
   369  type IfClause struct {
   370  	commentsRef
   371  	If   Position
   372  	Cond Expr
   373  }
   374  
   375  func (x *IfClause) Span() (start, end Position) {
   376  	_, end = x.Cond.Span()
   377  	return x.If, end
   378  }
   379  
   380  // A DictExpr represents a dictionary literal: { List }.
   381  type DictExpr struct {
   382  	commentsRef
   383  	Lbrace Position
   384  	List   []Expr // all *DictEntrys
   385  	Rbrace Position
   386  }
   387  
   388  func (x *DictExpr) Span() (start, end Position) {
   389  	return x.Lbrace, x.Rbrace.add("}")
   390  }
   391  
   392  // A DictEntry represents a dictionary entry: Key: Value.
   393  // Used only within a DictExpr.
   394  type DictEntry struct {
   395  	commentsRef
   396  	Key   Expr
   397  	Colon Position
   398  	Value Expr
   399  }
   400  
   401  func (x *DictEntry) Span() (start, end Position) {
   402  	start, _ = x.Key.Span()
   403  	_, end = x.Value.Span()
   404  	return start, end
   405  }
   406  
   407  // A LambdaExpr represents an inline function abstraction.
   408  //
   409  // Although they may be added in future, lambda expressions are not
   410  // currently part of the Skylark spec, so their use is controlled by the
   411  // resolver.AllowLambda flag.
   412  type LambdaExpr struct {
   413  	commentsRef
   414  	Lambda Position
   415  	Function
   416  }
   417  
   418  func (x *LambdaExpr) Span() (start, end Position) {
   419  	_, end = x.Function.Body[len(x.Body)-1].Span()
   420  	return x.Lambda, end
   421  }
   422  
   423  // A ListExpr represents a list literal: [ List ].
   424  type ListExpr struct {
   425  	commentsRef
   426  	Lbrack Position
   427  	List   []Expr
   428  	Rbrack Position
   429  }
   430  
   431  func (x *ListExpr) Span() (start, end Position) {
   432  	return x.Lbrack, x.Rbrack.add("]")
   433  }
   434  
   435  // CondExpr represents the conditional: X if COND else ELSE.
   436  type CondExpr struct {
   437  	commentsRef
   438  	If      Position
   439  	Cond    Expr
   440  	True    Expr
   441  	ElsePos Position
   442  	False   Expr
   443  }
   444  
   445  func (x *CondExpr) Span() (start, end Position) {
   446  	start, _ = x.True.Span()
   447  	_, end = x.False.Span()
   448  	return start, end
   449  }
   450  
   451  // A TupleExpr represents a tuple literal: (List).
   452  type TupleExpr struct {
   453  	commentsRef
   454  	Lparen Position // optional (e.g. in x, y = 0, 1), but required if List is empty
   455  	List   []Expr
   456  	Rparen Position
   457  }
   458  
   459  func (x *TupleExpr) Span() (start, end Position) {
   460  	if x.Lparen.IsValid() {
   461  		return x.Lparen, x.Rparen
   462  	} else {
   463  		return Start(x.List[0]), End(x.List[len(x.List)-1])
   464  	}
   465  }
   466  
   467  // A UnaryExpr represents a unary expression: Op X.
   468  type UnaryExpr struct {
   469  	commentsRef
   470  	OpPos Position
   471  	Op    Token
   472  	X     Expr
   473  }
   474  
   475  func (x *UnaryExpr) Span() (start, end Position) {
   476  	_, end = x.X.Span()
   477  	return x.OpPos, end
   478  }
   479  
   480  // A BinaryExpr represents a binary expression: X Op Y.
   481  type BinaryExpr struct {
   482  	commentsRef
   483  	X     Expr
   484  	OpPos Position
   485  	Op    Token
   486  	Y     Expr
   487  }
   488  
   489  func (x *BinaryExpr) Span() (start, end Position) {
   490  	start, _ = x.X.Span()
   491  	_, end = x.Y.Span()
   492  	return start, end
   493  }
   494  
   495  // A SliceExpr represents a slice or substring expression: X[Lo:Hi:Step].
   496  type SliceExpr struct {
   497  	commentsRef
   498  	X            Expr
   499  	Lbrack       Position
   500  	Lo, Hi, Step Expr // all optional
   501  	Rbrack       Position
   502  }
   503  
   504  func (x *SliceExpr) Span() (start, end Position) {
   505  	start, _ = x.X.Span()
   506  	return start, x.Rbrack
   507  }
   508  
   509  // An IndexExpr represents an index expression: X[Y].
   510  type IndexExpr struct {
   511  	commentsRef
   512  	X      Expr
   513  	Lbrack Position
   514  	Y      Expr
   515  	Rbrack Position
   516  }
   517  
   518  func (x *IndexExpr) Span() (start, end Position) {
   519  	start, _ = x.X.Span()
   520  	return start, x.Rbrack
   521  }