...

Source file src/go.starlark.net/syntax/syntax.go

Documentation: go.starlark.net/syntax

     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 "go.starlark.net/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 | BYTES | INT | FLOAT
   255  	TokenPos Position
   256  	Raw      string      // uninterpreted text
   257  	Value    interface{} // = string | int64 | *big.Int | float64
   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  type LambdaExpr struct {
   402  	commentsRef
   403  	Lambda Position
   404  	Params []Expr // param = ident | ident=expr | * | *ident | **ident
   405  	Body   Expr
   406  
   407  	Function interface{} // a *resolve.Function, set by resolver
   408  }
   409  
   410  func (x *LambdaExpr) Span() (start, end Position) {
   411  	_, end = x.Body.Span()
   412  	return x.Lambda, end
   413  }
   414  
   415  // A ListExpr represents a list literal: [ List ].
   416  type ListExpr struct {
   417  	commentsRef
   418  	Lbrack Position
   419  	List   []Expr
   420  	Rbrack Position
   421  }
   422  
   423  func (x *ListExpr) Span() (start, end Position) {
   424  	return x.Lbrack, x.Rbrack.add("]")
   425  }
   426  
   427  // CondExpr represents the conditional: X if COND else ELSE.
   428  type CondExpr struct {
   429  	commentsRef
   430  	If      Position
   431  	Cond    Expr
   432  	True    Expr
   433  	ElsePos Position
   434  	False   Expr
   435  }
   436  
   437  func (x *CondExpr) Span() (start, end Position) {
   438  	start, _ = x.True.Span()
   439  	_, end = x.False.Span()
   440  	return start, end
   441  }
   442  
   443  // A TupleExpr represents a tuple literal: (List).
   444  type TupleExpr struct {
   445  	commentsRef
   446  	Lparen Position // optional (e.g. in x, y = 0, 1), but required if List is empty
   447  	List   []Expr
   448  	Rparen Position
   449  }
   450  
   451  func (x *TupleExpr) Span() (start, end Position) {
   452  	if x.Lparen.IsValid() {
   453  		return x.Lparen, x.Rparen
   454  	} else {
   455  		return Start(x.List[0]), End(x.List[len(x.List)-1])
   456  	}
   457  }
   458  
   459  // A UnaryExpr represents a unary expression: Op X.
   460  //
   461  // As a special case, UnaryOp{Op:Star} may also represent
   462  // the star parameter in def f(*args) or def f(*, x).
   463  type UnaryExpr struct {
   464  	commentsRef
   465  	OpPos Position
   466  	Op    Token
   467  	X     Expr // may be nil if Op==STAR
   468  }
   469  
   470  func (x *UnaryExpr) Span() (start, end Position) {
   471  	if x.X != nil {
   472  		_, end = x.X.Span()
   473  	} else {
   474  		end = x.OpPos.add("*")
   475  	}
   476  	return x.OpPos, end
   477  }
   478  
   479  // A BinaryExpr represents a binary expression: X Op Y.
   480  //
   481  // As a special case, BinaryExpr{Op:EQ} may also
   482  // represent a named argument in a call f(k=v)
   483  // or a named parameter in a function declaration
   484  // def f(param=default).
   485  type BinaryExpr struct {
   486  	commentsRef
   487  	X     Expr
   488  	OpPos Position
   489  	Op    Token
   490  	Y     Expr
   491  }
   492  
   493  func (x *BinaryExpr) Span() (start, end Position) {
   494  	start, _ = x.X.Span()
   495  	_, end = x.Y.Span()
   496  	return start, end
   497  }
   498  
   499  // A SliceExpr represents a slice or substring expression: X[Lo:Hi:Step].
   500  type SliceExpr struct {
   501  	commentsRef
   502  	X            Expr
   503  	Lbrack       Position
   504  	Lo, Hi, Step Expr // all optional
   505  	Rbrack       Position
   506  }
   507  
   508  func (x *SliceExpr) Span() (start, end Position) {
   509  	start, _ = x.X.Span()
   510  	return start, x.Rbrack
   511  }
   512  
   513  // An IndexExpr represents an index expression: X[Y].
   514  type IndexExpr struct {
   515  	commentsRef
   516  	X      Expr
   517  	Lbrack Position
   518  	Y      Expr
   519  	Rbrack Position
   520  }
   521  
   522  func (x *IndexExpr) Span() (start, end Position) {
   523  	start, _ = x.X.Span()
   524  	return start, x.Rbrack
   525  }
   526  

View as plain text