github.com/k14s/starlark-go@v0.0.0-20200720175618-3a5c849cc368/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 Starlark parser and abstract syntax tree.
     6  package syntax // import "github.com/k14s/starlark-go/syntax"
     7  
     8  // A Node is a node in a Starlark 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 Starlark file.
    68  type File struct {
    69  	commentsRef
    70  	Path  string
    71  	Stmts []Stmt
    72  
    73  	Module interface{} // a *resolve.Module, set by resolver
    74  }
    75  
    76  func (x *File) Span() (start, end Position) {
    77  	if len(x.Stmts) == 0 {
    78  		return
    79  	}
    80  	start, _ = x.Stmts[0].Span()
    81  	_, end = x.Stmts[len(x.Stmts)-1].Span()
    82  	return start, end
    83  }
    84  
    85  // A Stmt is a Starlark statement.
    86  type Stmt interface {
    87  	Node
    88  	stmt()
    89  }
    90  
    91  func (*AssignStmt) stmt() {}
    92  func (*BranchStmt) stmt() {}
    93  func (*DefStmt) stmt()    {}
    94  func (*ExprStmt) stmt()   {}
    95  func (*ForStmt) stmt()    {}
    96  func (*WhileStmt) stmt()  {}
    97  func (*IfStmt) stmt()     {}
    98  func (*LoadStmt) stmt()   {}
    99  func (*ReturnStmt) stmt() {}
   100  
   101  // An AssignStmt represents an assignment:
   102  //	x = 0
   103  //	x, y = y, x
   104  // 	x += 1
   105  type AssignStmt struct {
   106  	commentsRef
   107  	OpPos Position
   108  	Op    Token // = EQ | {PLUS,MINUS,STAR,PERCENT}_EQ
   109  	LHS   Expr
   110  	RHS   Expr
   111  }
   112  
   113  func (x *AssignStmt) Span() (start, end Position) {
   114  	start, _ = x.LHS.Span()
   115  	_, end = x.RHS.Span()
   116  	return
   117  }
   118  
   119  // A DefStmt represents a function definition.
   120  type DefStmt struct {
   121  	commentsRef
   122  	Def    Position
   123  	Name   *Ident
   124  	Params []Expr // param = ident | ident=expr | * | *ident | **ident
   125  	Body   []Stmt
   126  
   127  	Function interface{} // a *resolve.Function, set by resolver
   128  }
   129  
   130  func (x *DefStmt) Span() (start, end Position) {
   131  	_, end = x.Body[len(x.Body)-1].Span()
   132  	return x.Def, end
   133  }
   134  
   135  // An ExprStmt is an expression evaluated for side effects.
   136  type ExprStmt struct {
   137  	commentsRef
   138  	X Expr
   139  }
   140  
   141  func (x *ExprStmt) Span() (start, end Position) {
   142  	return x.X.Span()
   143  }
   144  
   145  // An IfStmt is a conditional: If Cond: True; else: False.
   146  // 'elseif' is desugared into a chain of IfStmts.
   147  type IfStmt struct {
   148  	commentsRef
   149  	If      Position // IF or ELIF
   150  	Cond    Expr
   151  	True    []Stmt
   152  	ElsePos Position // ELSE or ELIF
   153  	False   []Stmt   // optional
   154  }
   155  
   156  func (x *IfStmt) Span() (start, end Position) {
   157  	body := x.False
   158  	if body == nil {
   159  		body = x.True
   160  	}
   161  	_, end = body[len(body)-1].Span()
   162  	return x.If, end
   163  }
   164  
   165  // A LoadStmt loads another module and binds names from it:
   166  // load(Module, "x", y="foo").
   167  //
   168  // The AST is slightly unfaithful to the concrete syntax here because
   169  // Starlark's load statement, so that it can be implemented in Python,
   170  // binds some names (like y above) with an identifier and some (like x)
   171  // without.  For consistency we create fake identifiers for all the
   172  // strings.
   173  type LoadStmt struct {
   174  	commentsRef
   175  	Load   Position
   176  	Module *Literal // a string
   177  	From   []*Ident // name defined in loading module
   178  	To     []*Ident // name in loaded module
   179  	Rparen Position
   180  }
   181  
   182  func (x *LoadStmt) Span() (start, end Position) {
   183  	return x.Load, x.Rparen
   184  }
   185  
   186  // ModuleName returns the name of the module loaded by this statement.
   187  func (x *LoadStmt) ModuleName() string { return x.Module.Value.(string) }
   188  
   189  // A BranchStmt changes the flow of control: break, continue, pass.
   190  type BranchStmt struct {
   191  	commentsRef
   192  	Token    Token // = BREAK | CONTINUE | PASS
   193  	TokenPos Position
   194  }
   195  
   196  func (x *BranchStmt) Span() (start, end Position) {
   197  	return x.TokenPos, x.TokenPos.add(x.Token.String())
   198  }
   199  
   200  // A ReturnStmt returns from a function.
   201  type ReturnStmt struct {
   202  	commentsRef
   203  	Return Position
   204  	Result Expr // may be nil
   205  }
   206  
   207  func (x *ReturnStmt) Span() (start, end Position) {
   208  	if x.Result == nil {
   209  		return x.Return, x.Return.add("return")
   210  	}
   211  	_, end = x.Result.Span()
   212  	return x.Return, end
   213  }
   214  
   215  // An Expr is a Starlark expression.
   216  type Expr interface {
   217  	Node
   218  	expr()
   219  }
   220  
   221  func (*BinaryExpr) expr()    {}
   222  func (*CallExpr) expr()      {}
   223  func (*Comprehension) expr() {}
   224  func (*CondExpr) expr()      {}
   225  func (*DictEntry) expr()     {}
   226  func (*DictExpr) expr()      {}
   227  func (*DotExpr) expr()       {}
   228  func (*Ident) expr()         {}
   229  func (*IndexExpr) expr()     {}
   230  func (*LambdaExpr) expr()    {}
   231  func (*ListExpr) expr()      {}
   232  func (*Literal) expr()       {}
   233  func (*ParenExpr) expr()     {}
   234  func (*SliceExpr) expr()     {}
   235  func (*TupleExpr) expr()     {}
   236  func (*UnaryExpr) expr()     {}
   237  
   238  // An Ident represents an identifier.
   239  type Ident struct {
   240  	commentsRef
   241  	NamePos Position
   242  	Name    string
   243  
   244  	Binding interface{} // a *resolver.Binding, set by resolver
   245  }
   246  
   247  func (x *Ident) Span() (start, end Position) {
   248  	return x.NamePos, x.NamePos.add(x.Name)
   249  }
   250  
   251  // A Literal represents a literal string or number.
   252  type Literal struct {
   253  	commentsRef
   254  	Token    Token // = STRING | INT
   255  	TokenPos Position
   256  	Raw      string      // uninterpreted text
   257  	Value    interface{} // = string | int64 | *big.Int
   258  }
   259  
   260  func (x *Literal) Span() (start, end Position) {
   261  	return x.TokenPos, x.TokenPos.add(x.Raw)
   262  }
   263  
   264  // A ParenExpr represents a parenthesized expression: (X).
   265  type ParenExpr struct {
   266  	commentsRef
   267  	Lparen Position
   268  	X      Expr
   269  	Rparen Position
   270  }
   271  
   272  func (x *ParenExpr) Span() (start, end Position) {
   273  	return x.Lparen, x.Rparen.add(")")
   274  }
   275  
   276  // A CallExpr represents a function call expression: Fn(Args).
   277  type CallExpr struct {
   278  	commentsRef
   279  	Fn     Expr
   280  	Lparen Position
   281  	Args   []Expr // arg = expr | ident=expr | *expr | **expr
   282  	Rparen Position
   283  }
   284  
   285  func (x *CallExpr) Span() (start, end Position) {
   286  	start, _ = x.Fn.Span()
   287  	return start, x.Rparen.add(")")
   288  }
   289  
   290  // A DotExpr represents a field or method selector: X.Name.
   291  type DotExpr struct {
   292  	commentsRef
   293  	X       Expr
   294  	Dot     Position
   295  	NamePos Position
   296  	Name    *Ident
   297  }
   298  
   299  func (x *DotExpr) Span() (start, end Position) {
   300  	start, _ = x.X.Span()
   301  	_, end = x.Name.Span()
   302  	return
   303  }
   304  
   305  // A Comprehension represents a list or dict comprehension:
   306  // [Body for ... if ...] or {Body for ... if ...}
   307  type Comprehension struct {
   308  	commentsRef
   309  	Curly   bool // {x:y for ...} or {x for ...}, not [x for ...]
   310  	Lbrack  Position
   311  	Body    Expr
   312  	Clauses []Node // = *ForClause | *IfClause
   313  	Rbrack  Position
   314  }
   315  
   316  func (x *Comprehension) Span() (start, end Position) {
   317  	return x.Lbrack, x.Rbrack.add("]")
   318  }
   319  
   320  // A ForStmt represents a loop: for Vars in X: Body.
   321  type ForStmt struct {
   322  	commentsRef
   323  	For  Position
   324  	Vars Expr // name, or tuple of names
   325  	X    Expr
   326  	Body []Stmt
   327  }
   328  
   329  func (x *ForStmt) Span() (start, end Position) {
   330  	_, end = x.Body[len(x.Body)-1].Span()
   331  	return x.For, end
   332  }
   333  
   334  // A WhileStmt represents a while loop: while X: Body.
   335  type WhileStmt struct {
   336  	commentsRef
   337  	While Position
   338  	Cond  Expr
   339  	Body  []Stmt
   340  }
   341  
   342  func (x *WhileStmt) Span() (start, end Position) {
   343  	_, end = x.Body[len(x.Body)-1].Span()
   344  	return x.While, end
   345  }
   346  
   347  // A ForClause represents a for clause in a list comprehension: for Vars in X.
   348  type ForClause struct {
   349  	commentsRef
   350  	For  Position
   351  	Vars Expr // name, or tuple of names
   352  	In   Position
   353  	X    Expr
   354  }
   355  
   356  func (x *ForClause) Span() (start, end Position) {
   357  	_, end = x.X.Span()
   358  	return x.For, end
   359  }
   360  
   361  // An IfClause represents an if clause in a list comprehension: if Cond.
   362  type IfClause struct {
   363  	commentsRef
   364  	If   Position
   365  	Cond Expr
   366  }
   367  
   368  func (x *IfClause) Span() (start, end Position) {
   369  	_, end = x.Cond.Span()
   370  	return x.If, end
   371  }
   372  
   373  // A DictExpr represents a dictionary literal: { List }.
   374  type DictExpr struct {
   375  	commentsRef
   376  	Lbrace Position
   377  	List   []Expr // all *DictEntrys
   378  	Rbrace Position
   379  }
   380  
   381  func (x *DictExpr) Span() (start, end Position) {
   382  	return x.Lbrace, x.Rbrace.add("}")
   383  }
   384  
   385  // A DictEntry represents a dictionary entry: Key: Value.
   386  // Used only within a DictExpr.
   387  type DictEntry struct {
   388  	commentsRef
   389  	Key   Expr
   390  	Colon Position
   391  	Value Expr
   392  }
   393  
   394  func (x *DictEntry) Span() (start, end Position) {
   395  	start, _ = x.Key.Span()
   396  	_, end = x.Value.Span()
   397  	return start, end
   398  }
   399  
   400  // A LambdaExpr represents an inline function abstraction.
   401  //
   402  // Although they may be added in future, lambda expressions are not
   403  // currently part of the Starlark spec, so their use is controlled by the
   404  // resolver.AllowLambda flag.
   405  type LambdaExpr struct {
   406  	commentsRef
   407  	Lambda Position
   408  	Params []Expr // param = ident | ident=expr | * | *ident | **ident
   409  	Body   Expr
   410  
   411  	Function interface{} // a *resolve.Function, set by resolver
   412  }
   413  
   414  func (x *LambdaExpr) Span() (start, end Position) {
   415  	_, end = x.Body.Span()
   416  	return x.Lambda, end
   417  }
   418  
   419  // A ListExpr represents a list literal: [ List ].
   420  type ListExpr struct {
   421  	commentsRef
   422  	Lbrack Position
   423  	List   []Expr
   424  	Rbrack Position
   425  }
   426  
   427  func (x *ListExpr) Span() (start, end Position) {
   428  	return x.Lbrack, x.Rbrack.add("]")
   429  }
   430  
   431  // CondExpr represents the conditional: X if COND else ELSE.
   432  type CondExpr struct {
   433  	commentsRef
   434  	If      Position
   435  	Cond    Expr
   436  	True    Expr
   437  	ElsePos Position
   438  	False   Expr
   439  }
   440  
   441  func (x *CondExpr) Span() (start, end Position) {
   442  	start, _ = x.True.Span()
   443  	_, end = x.False.Span()
   444  	return start, end
   445  }
   446  
   447  // A TupleExpr represents a tuple literal: (List).
   448  type TupleExpr struct {
   449  	commentsRef
   450  	Lparen Position // optional (e.g. in x, y = 0, 1), but required if List is empty
   451  	List   []Expr
   452  	Rparen Position
   453  }
   454  
   455  func (x *TupleExpr) Span() (start, end Position) {
   456  	if x.Lparen.IsValid() {
   457  		return x.Lparen, x.Rparen
   458  	} else {
   459  		return Start(x.List[0]), End(x.List[len(x.List)-1])
   460  	}
   461  }
   462  
   463  // A UnaryExpr represents a unary expression: Op X.
   464  //
   465  // As a special case, UnaryOp{Op:Star} may also represent
   466  // the star parameter in def f(*args) or def f(*, x).
   467  type UnaryExpr struct {
   468  	commentsRef
   469  	OpPos Position
   470  	Op    Token
   471  	X     Expr // may be nil if Op==STAR
   472  }
   473  
   474  func (x *UnaryExpr) Span() (start, end Position) {
   475  	if x.X != nil {
   476  		_, end = x.X.Span()
   477  	} else {
   478  		end = x.OpPos.add("*")
   479  	}
   480  	return x.OpPos, end
   481  }
   482  
   483  // A BinaryExpr represents a binary expression: X Op Y.
   484  //
   485  // As a special case, BinaryExpr{Op:EQ} may also
   486  // represent a named argument in a call f(k=v)
   487  // or a named parameter in a function declaration
   488  // def f(param=default).
   489  type BinaryExpr struct {
   490  	commentsRef
   491  	X     Expr
   492  	OpPos Position
   493  	Op    Token
   494  	Y     Expr
   495  }
   496  
   497  func (x *BinaryExpr) Span() (start, end Position) {
   498  	start, _ = x.X.Span()
   499  	_, end = x.Y.Span()
   500  	return start, end
   501  }
   502  
   503  // A SliceExpr represents a slice or substring expression: X[Lo:Hi:Step].
   504  type SliceExpr struct {
   505  	commentsRef
   506  	X            Expr
   507  	Lbrack       Position
   508  	Lo, Hi, Step Expr // all optional
   509  	Rbrack       Position
   510  }
   511  
   512  func (x *SliceExpr) Span() (start, end Position) {
   513  	start, _ = x.X.Span()
   514  	return start, x.Rbrack
   515  }
   516  
   517  // An IndexExpr represents an index expression: X[Y].
   518  type IndexExpr struct {
   519  	commentsRef
   520  	X      Expr
   521  	Lbrack Position
   522  	Y      Expr
   523  	Rbrack Position
   524  }
   525  
   526  func (x *IndexExpr) Span() (start, end Position) {
   527  	start, _ = x.X.Span()
   528  	return start, x.Rbrack
   529  }