go.starlark.net@v0.0.0-20231101134539-556fd59b42f6/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 "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  	Options *FileOptions
    75  }
    76  
    77  func (x *File) Span() (start, end Position) {
    78  	if len(x.Stmts) == 0 {
    79  		return
    80  	}
    81  	start, _ = x.Stmts[0].Span()
    82  	_, end = x.Stmts[len(x.Stmts)-1].Span()
    83  	return start, end
    84  }
    85  
    86  // A Stmt is a Starlark statement.
    87  type Stmt interface {
    88  	Node
    89  	stmt()
    90  }
    91  
    92  func (*AssignStmt) stmt() {}
    93  func (*BranchStmt) stmt() {}
    94  func (*DefStmt) stmt()    {}
    95  func (*ExprStmt) stmt()   {}
    96  func (*ForStmt) stmt()    {}
    97  func (*WhileStmt) stmt()  {}
    98  func (*IfStmt) stmt()     {}
    99  func (*LoadStmt) stmt()   {}
   100  func (*ReturnStmt) stmt() {}
   101  
   102  // An AssignStmt represents an assignment:
   103  //
   104  //	x = 0
   105  //	x, y = y, x
   106  //	x += 1
   107  type AssignStmt struct {
   108  	commentsRef
   109  	OpPos Position
   110  	Op    Token // = EQ | {PLUS,MINUS,STAR,PERCENT}_EQ
   111  	LHS   Expr
   112  	RHS   Expr
   113  }
   114  
   115  func (x *AssignStmt) Span() (start, end Position) {
   116  	start, _ = x.LHS.Span()
   117  	_, end = x.RHS.Span()
   118  	return
   119  }
   120  
   121  // A DefStmt represents a function definition.
   122  type DefStmt struct {
   123  	commentsRef
   124  	Def    Position
   125  	Name   *Ident
   126  	Lparen Position
   127  	Params []Expr // param = ident | ident=expr | * | *ident | **ident
   128  	Rparen Position
   129  	Body   []Stmt
   130  
   131  	Function interface{} // a *resolve.Function, set by resolver
   132  }
   133  
   134  func (x *DefStmt) Span() (start, end Position) {
   135  	_, end = x.Body[len(x.Body)-1].Span()
   136  	return x.Def, end
   137  }
   138  
   139  // An ExprStmt is an expression evaluated for side effects.
   140  type ExprStmt struct {
   141  	commentsRef
   142  	X Expr
   143  }
   144  
   145  func (x *ExprStmt) Span() (start, end Position) {
   146  	return x.X.Span()
   147  }
   148  
   149  // An IfStmt is a conditional: If Cond: True; else: False.
   150  // 'elseif' is desugared into a chain of IfStmts.
   151  type IfStmt struct {
   152  	commentsRef
   153  	If      Position // IF or ELIF
   154  	Cond    Expr
   155  	True    []Stmt
   156  	ElsePos Position // ELSE or ELIF
   157  	False   []Stmt   // optional
   158  }
   159  
   160  func (x *IfStmt) Span() (start, end Position) {
   161  	body := x.False
   162  	if body == nil {
   163  		body = x.True
   164  	}
   165  	_, end = body[len(body)-1].Span()
   166  	return x.If, end
   167  }
   168  
   169  // A LoadStmt loads another module and binds names from it:
   170  // load(Module, "x", y="foo").
   171  //
   172  // The AST is slightly unfaithful to the concrete syntax here because
   173  // Starlark's load statement, so that it can be implemented in Python,
   174  // binds some names (like y above) with an identifier and some (like x)
   175  // without.  For consistency we create fake identifiers for all the
   176  // strings.
   177  type LoadStmt struct {
   178  	commentsRef
   179  	Load   Position
   180  	Module *Literal // a string
   181  	From   []*Ident // name defined in loading module
   182  	To     []*Ident // name in loaded module
   183  	Rparen Position
   184  }
   185  
   186  func (x *LoadStmt) Span() (start, end Position) {
   187  	return x.Load, x.Rparen
   188  }
   189  
   190  // ModuleName returns the name of the module loaded by this statement.
   191  func (x *LoadStmt) ModuleName() string { return x.Module.Value.(string) }
   192  
   193  // A BranchStmt changes the flow of control: break, continue, pass.
   194  type BranchStmt struct {
   195  	commentsRef
   196  	Token    Token // = BREAK | CONTINUE | PASS
   197  	TokenPos Position
   198  }
   199  
   200  func (x *BranchStmt) Span() (start, end Position) {
   201  	return x.TokenPos, x.TokenPos.add(x.Token.String())
   202  }
   203  
   204  // A ReturnStmt returns from a function.
   205  type ReturnStmt struct {
   206  	commentsRef
   207  	Return Position
   208  	Result Expr // may be nil
   209  }
   210  
   211  func (x *ReturnStmt) Span() (start, end Position) {
   212  	if x.Result == nil {
   213  		return x.Return, x.Return.add("return")
   214  	}
   215  	_, end = x.Result.Span()
   216  	return x.Return, end
   217  }
   218  
   219  // An Expr is a Starlark expression.
   220  type Expr interface {
   221  	Node
   222  	expr()
   223  }
   224  
   225  func (*BinaryExpr) expr()    {}
   226  func (*CallExpr) expr()      {}
   227  func (*Comprehension) expr() {}
   228  func (*CondExpr) expr()      {}
   229  func (*DictEntry) expr()     {}
   230  func (*DictExpr) expr()      {}
   231  func (*DotExpr) expr()       {}
   232  func (*Ident) expr()         {}
   233  func (*IndexExpr) expr()     {}
   234  func (*LambdaExpr) expr()    {}
   235  func (*ListExpr) expr()      {}
   236  func (*Literal) expr()       {}
   237  func (*ParenExpr) expr()     {}
   238  func (*SliceExpr) expr()     {}
   239  func (*TupleExpr) expr()     {}
   240  func (*UnaryExpr) expr()     {}
   241  
   242  // An Ident represents an identifier.
   243  type Ident struct {
   244  	commentsRef
   245  	NamePos Position
   246  	Name    string
   247  
   248  	Binding interface{} // a *resolver.Binding, set by resolver
   249  }
   250  
   251  func (x *Ident) Span() (start, end Position) {
   252  	return x.NamePos, x.NamePos.add(x.Name)
   253  }
   254  
   255  // A Literal represents a literal string or number.
   256  type Literal struct {
   257  	commentsRef
   258  	Token    Token // = STRING | BYTES | INT | FLOAT
   259  	TokenPos Position
   260  	Raw      string      // uninterpreted text
   261  	Value    interface{} // = string | int64 | *big.Int | float64
   262  }
   263  
   264  func (x *Literal) Span() (start, end Position) {
   265  	return x.TokenPos, x.TokenPos.add(x.Raw)
   266  }
   267  
   268  // A ParenExpr represents a parenthesized expression: (X).
   269  type ParenExpr struct {
   270  	commentsRef
   271  	Lparen Position
   272  	X      Expr
   273  	Rparen Position
   274  }
   275  
   276  func (x *ParenExpr) Span() (start, end Position) {
   277  	return x.Lparen, x.Rparen.add(")")
   278  }
   279  
   280  // A CallExpr represents a function call expression: Fn(Args).
   281  type CallExpr struct {
   282  	commentsRef
   283  	Fn     Expr
   284  	Lparen Position
   285  	Args   []Expr // arg = expr | ident=expr | *expr | **expr
   286  	Rparen Position
   287  }
   288  
   289  func (x *CallExpr) Span() (start, end Position) {
   290  	start, _ = x.Fn.Span()
   291  	return start, x.Rparen.add(")")
   292  }
   293  
   294  // A DotExpr represents a field or method selector: X.Name.
   295  type DotExpr struct {
   296  	commentsRef
   297  	X       Expr
   298  	Dot     Position
   299  	NamePos Position
   300  	Name    *Ident
   301  }
   302  
   303  func (x *DotExpr) Span() (start, end Position) {
   304  	start, _ = x.X.Span()
   305  	_, end = x.Name.Span()
   306  	return
   307  }
   308  
   309  // A Comprehension represents a list or dict comprehension:
   310  // [Body for ... if ...] or {Body for ... if ...}
   311  type Comprehension struct {
   312  	commentsRef
   313  	Curly   bool // {x:y for ...} or {x for ...}, not [x for ...]
   314  	Lbrack  Position
   315  	Body    Expr
   316  	Clauses []Node // = *ForClause | *IfClause
   317  	Rbrack  Position
   318  }
   319  
   320  func (x *Comprehension) Span() (start, end Position) {
   321  	return x.Lbrack, x.Rbrack.add("]")
   322  }
   323  
   324  // A ForStmt represents a loop: for Vars in X: Body.
   325  type ForStmt struct {
   326  	commentsRef
   327  	For  Position
   328  	Vars Expr // name, or tuple of names
   329  	X    Expr
   330  	Body []Stmt
   331  }
   332  
   333  func (x *ForStmt) Span() (start, end Position) {
   334  	_, end = x.Body[len(x.Body)-1].Span()
   335  	return x.For, end
   336  }
   337  
   338  // A WhileStmt represents a while loop: while X: Body.
   339  type WhileStmt struct {
   340  	commentsRef
   341  	While Position
   342  	Cond  Expr
   343  	Body  []Stmt
   344  }
   345  
   346  func (x *WhileStmt) Span() (start, end Position) {
   347  	_, end = x.Body[len(x.Body)-1].Span()
   348  	return x.While, end
   349  }
   350  
   351  // A ForClause represents a for clause in a list comprehension: for Vars in X.
   352  type ForClause struct {
   353  	commentsRef
   354  	For  Position
   355  	Vars Expr // name, or tuple of names
   356  	In   Position
   357  	X    Expr
   358  }
   359  
   360  func (x *ForClause) Span() (start, end Position) {
   361  	_, end = x.X.Span()
   362  	return x.For, end
   363  }
   364  
   365  // An IfClause represents an if clause in a list comprehension: if Cond.
   366  type IfClause struct {
   367  	commentsRef
   368  	If   Position
   369  	Cond Expr
   370  }
   371  
   372  func (x *IfClause) Span() (start, end Position) {
   373  	_, end = x.Cond.Span()
   374  	return x.If, end
   375  }
   376  
   377  // A DictExpr represents a dictionary literal: { List }.
   378  type DictExpr struct {
   379  	commentsRef
   380  	Lbrace Position
   381  	List   []Expr // all *DictEntrys
   382  	Rbrace Position
   383  }
   384  
   385  func (x *DictExpr) Span() (start, end Position) {
   386  	return x.Lbrace, x.Rbrace.add("}")
   387  }
   388  
   389  // A DictEntry represents a dictionary entry: Key: Value.
   390  // Used only within a DictExpr.
   391  type DictEntry struct {
   392  	commentsRef
   393  	Key   Expr
   394  	Colon Position
   395  	Value Expr
   396  }
   397  
   398  func (x *DictEntry) Span() (start, end Position) {
   399  	start, _ = x.Key.Span()
   400  	_, end = x.Value.Span()
   401  	return start, end
   402  }
   403  
   404  // A LambdaExpr represents an inline function abstraction.
   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  }