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