| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // The AST package declares the types used to represent |
| // syntax trees for Go packages. |
| // |
| package ast |
| |
| import ( |
| "go/token" |
| "unicode" |
| "utf8" |
| ) |
| |
| |
| // ---------------------------------------------------------------------------- |
| // Interfaces |
| // |
| // There are 3 main classes of nodes: Expressions and type nodes, |
| // statement nodes, and declaration nodes. The node names usually |
| // match the corresponding Go spec production names to which they |
| // correspond. The node fields correspond to the individual parts |
| // of the respective productions. |
| // |
| // All nodes contain position information marking the beginning of |
| // the corresponding source text segment; it is accessible via the |
| // Pos accessor method. Nodes may contain additional position info |
| // for language constructs where comments may be found between parts |
| // of the construct (typically any larger, parenthesized subpart). |
| // That position information is needed to properly position comments |
| // when printing the construct. |
| |
| |
| // All node types implement the Node interface. |
| type Node interface { |
| // Pos returns the (beginning) position of the node. |
| Pos() token.Position |
| } |
| |
| |
| // All expression nodes implement the Expr interface. |
| type Expr interface { |
| Node |
| exprNode() |
| } |
| |
| |
| // All statement nodes implement the Stmt interface. |
| type Stmt interface { |
| Node |
| stmtNode() |
| } |
| |
| |
| // All declaration nodes implement the Decl interface. |
| type Decl interface { |
| Node |
| declNode() |
| } |
| |
| |
| // ---------------------------------------------------------------------------- |
| // Comments |
| |
| // A Comment node represents a single //-style or /*-style comment. |
| type Comment struct { |
| token.Position // beginning position of the comment |
| Text []byte // comment text (excluding '\n' for //-style comments) |
| } |
| |
| |
| // A CommentGroup represents a sequence of comments |
| // with no other tokens and no empty lines between. |
| // |
| type CommentGroup struct { |
| List []*Comment |
| Next *CommentGroup // next comment group in source order |
| } |
| |
| |
| // ---------------------------------------------------------------------------- |
| // Expressions and types |
| |
| // A Field represents a Field declaration list in a struct type, |
| // a method list in an interface type, or a parameter/result declaration |
| // in a signature. |
| // |
| type Field struct { |
| Doc *CommentGroup // associated documentation; or nil |
| Names []*Ident // field/method/parameter names; or nil if anonymous field |
| Type Expr // field/method/parameter type |
| Tag []*BasicLit // field tag; or nil |
| Comment *CommentGroup // line comments; or nil |
| } |
| |
| |
| func (f *Field) Pos() token.Position { |
| if len(f.Names) > 0 { |
| return f.Names[0].Pos() |
| } |
| return f.Type.Pos() |
| } |
| |
| |
| // An expression is represented by a tree consisting of one |
| // or more of the following concrete expression nodes. |
| // |
| type ( |
| // A BadExpr node is a placeholder for expressions containing |
| // syntax errors for which no correct expression nodes can be |
| // created. |
| // |
| BadExpr struct { |
| token.Position // beginning position of bad expression |
| } |
| |
| // An Ident node represents an identifier. |
| Ident struct { |
| token.Position // identifier position |
| Obj *Object // denoted object |
| } |
| |
| // An Ellipsis node stands for the "..." type in a |
| // parameter list or the "..." length in an array type. |
| // |
| Ellipsis struct { |
| token.Position // position of "..." |
| Elt Expr // ellipsis element type (parameter lists only) |
| } |
| |
| // A BasicLit node represents a literal of basic type. |
| BasicLit struct { |
| token.Position // literal position |
| Kind token.Token // token.INT, token.FLOAT, token.CHAR, or token.STRING |
| Value []byte // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 'a', '\x7f', "foo" or `\m\n\o` |
| } |
| |
| // A StringList node represents a sequence of adjacent string literals. |
| // A single string literal (common case) is represented by a BasicLit |
| // node; StringList nodes are used only if there are two or more string |
| // literals in a sequence. |
| // TODO(gri) Deprecated. StringLists are only created by exp/parser; |
| // Remove when exp/parser is removed. |
| // |
| StringList struct { |
| Strings []*BasicLit // list of strings, len(Strings) > 1 |
| } |
| |
| // A FuncLit node represents a function literal. |
| FuncLit struct { |
| Type *FuncType // function type |
| Body *BlockStmt // function body |
| } |
| |
| // A CompositeLit node represents a composite literal. |
| // |
| CompositeLit struct { |
| Type Expr // literal type |
| Lbrace token.Position // position of "{" |
| Elts []Expr // list of composite elements |
| Rbrace token.Position // position of "}" |
| } |
| |
| // A ParenExpr node represents a parenthesized expression. |
| ParenExpr struct { |
| token.Position // position of "(" |
| X Expr // parenthesized expression |
| Rparen token.Position // position of ")" |
| } |
| |
| // A SelectorExpr node represents an expression followed by a selector. |
| SelectorExpr struct { |
| X Expr // expression |
| Sel *Ident // field selector |
| } |
| |
| // An IndexExpr node represents an expression followed by an index. |
| IndexExpr struct { |
| X Expr // expression |
| Index Expr // index expression |
| } |
| |
| // An SliceExpr node represents an expression followed by slice indices. |
| SliceExpr struct { |
| X Expr // expression |
| Index Expr // beginning of slice range |
| End Expr // end of slice range; or nil |
| } |
| |
| // A TypeAssertExpr node represents an expression followed by a |
| // type assertion. |
| // |
| TypeAssertExpr struct { |
| X Expr // expression |
| Type Expr // asserted type; nil means type switch X.(type) |
| } |
| |
| // A CallExpr node represents an expression followed by an argument list. |
| CallExpr struct { |
| Fun Expr // function expression |
| Lparen token.Position // position of "(" |
| Args []Expr // function arguments |
| Rparen token.Position // positions of ")" |
| } |
| |
| // A StarExpr node represents an expression of the form "*" Expression. |
| // Semantically it could be a unary "*" expression, or a pointer type. |
| StarExpr struct { |
| token.Position // position of "*" |
| X Expr // operand |
| } |
| |
| // A UnaryExpr node represents a unary expression. |
| // Unary "*" expressions are represented via StarExpr nodes. |
| // |
| UnaryExpr struct { |
| token.Position // position of Op |
| Op token.Token // operator |
| X Expr // operand |
| } |
| |
| // A BinaryExpr node represents a binary expression. |
| // |
| BinaryExpr struct { |
| X Expr // left operand |
| OpPos token.Position // position of Op |
| Op token.Token // operator |
| Y Expr // right operand |
| } |
| |
| // A KeyValueExpr node represents (key : value) pairs |
| // in composite literals. |
| // |
| KeyValueExpr struct { |
| Key Expr |
| Colon token.Position // position of ":" |
| Value Expr |
| } |
| ) |
| |
| |
| // The direction of a channel type is indicated by one |
| // of the following constants. |
| // |
| type ChanDir int |
| |
| const ( |
| SEND ChanDir = 1 << iota |
| RECV |
| ) |
| |
| |
| // A type is represented by a tree consisting of one |
| // or more of the following type-specific expression |
| // nodes. |
| // |
| type ( |
| // An ArrayType node represents an array or slice type. |
| ArrayType struct { |
| token.Position // position of "[" |
| Len Expr // Ellipsis node for [...]T array types, nil for slice types |
| Elt Expr // element type |
| } |
| |
| // A StructType node represents a struct type. |
| StructType struct { |
| token.Position // position of "struct" keyword |
| Lbrace token.Position // position of "{" |
| Fields []*Field // list of field declarations |
| Rbrace token.Position // position of "}" |
| Incomplete bool // true if (source) fields are missing in the Fields list |
| } |
| |
| // Pointer types are represented via StarExpr nodes. |
| |
| // A FuncType node represents a function type. |
| FuncType struct { |
| token.Position // position of "func" keyword |
| Params []*Field // (incoming) parameters |
| Results []*Field // (outgoing) results |
| } |
| |
| // An InterfaceType node represents an interface type. |
| InterfaceType struct { |
| token.Position // position of "interface" keyword |
| Lbrace token.Position // position of "{" |
| Methods []*Field // list of methods |
| Rbrace token.Position // position of "}" |
| Incomplete bool // true if (source) methods are missing in the Methods list |
| } |
| |
| // A MapType node represents a map type. |
| MapType struct { |
| token.Position // position of "map" keyword |
| Key Expr |
| Value Expr |
| } |
| |
| // A ChanType node represents a channel type. |
| ChanType struct { |
| token.Position // position of "chan" keyword or "<-" (whichever comes first) |
| Dir ChanDir // channel direction |
| Value Expr // value type |
| } |
| ) |
| |
| |
| // Pos() implementations for expression/type where the position |
| // corresponds to the position of a sub-node. |
| // |
| func (x *StringList) Pos() token.Position { return x.Strings[0].Pos() } |
| func (x *FuncLit) Pos() token.Position { return x.Type.Pos() } |
| func (x *CompositeLit) Pos() token.Position { return x.Type.Pos() } |
| func (x *SelectorExpr) Pos() token.Position { return x.X.Pos() } |
| func (x *IndexExpr) Pos() token.Position { return x.X.Pos() } |
| func (x *SliceExpr) Pos() token.Position { return x.X.Pos() } |
| func (x *TypeAssertExpr) Pos() token.Position { return x.X.Pos() } |
| func (x *CallExpr) Pos() token.Position { return x.Fun.Pos() } |
| func (x *BinaryExpr) Pos() token.Position { return x.X.Pos() } |
| func (x *KeyValueExpr) Pos() token.Position { return x.Key.Pos() } |
| |
| |
| // exprNode() ensures that only expression/type nodes can be |
| // assigned to an ExprNode. |
| func (x *BadExpr) exprNode() {} |
| func (x *Ident) exprNode() {} |
| func (x *Ellipsis) exprNode() {} |
| func (x *BasicLit) exprNode() {} |
| func (x *StringList) exprNode() {} |
| func (x *FuncLit) exprNode() {} |
| func (x *CompositeLit) exprNode() {} |
| func (x *ParenExpr) exprNode() {} |
| func (x *SelectorExpr) exprNode() {} |
| func (x *IndexExpr) exprNode() {} |
| func (x *SliceExpr) exprNode() {} |
| func (x *TypeAssertExpr) exprNode() {} |
| func (x *CallExpr) exprNode() {} |
| func (x *StarExpr) exprNode() {} |
| func (x *UnaryExpr) exprNode() {} |
| func (x *BinaryExpr) exprNode() {} |
| func (x *KeyValueExpr) exprNode() {} |
| |
| func (x *ArrayType) exprNode() {} |
| func (x *StructType) exprNode() {} |
| func (x *FuncType) exprNode() {} |
| func (x *InterfaceType) exprNode() {} |
| func (x *MapType) exprNode() {} |
| func (x *ChanType) exprNode() {} |
| |
| |
| // ---------------------------------------------------------------------------- |
| // Convenience functions for Idents |
| |
| // NewIdent creates a new Ident without position and minimal object |
| // information. Useful for ASTs generated by code other than the Go |
| // parser. |
| // |
| func NewIdent(name string) *Ident { return &Ident{noPos, NewObj(Err, noPos, name)} } |
| |
| |
| // IsExported returns whether name is an exported Go symbol |
| // (i.e., whether it begins with an uppercase letter). |
| func IsExported(name string) bool { |
| ch, _ := utf8.DecodeRuneInString(name) |
| return unicode.IsUpper(ch) |
| } |
| |
| |
| // IsExported returns whether id is an exported Go symbol |
| // (i.e., whether it begins with an uppercase letter). |
| func (id *Ident) IsExported() bool { return id.Obj.IsExported() } |
| |
| |
| // Name returns an identifier's name. |
| func (id *Ident) Name() string { return id.Obj.Name } |
| |
| |
| func (id *Ident) String() string { |
| if id != nil && id.Obj != nil { |
| return id.Obj.Name |
| } |
| return "<nil>" |
| } |
| |
| |
| // ---------------------------------------------------------------------------- |
| // Statements |
| |
| // A statement is represented by a tree consisting of one |
| // or more of the following concrete statement nodes. |
| // |
| type ( |
| // A BadStmt node is a placeholder for statements containing |
| // syntax errors for which no correct statement nodes can be |
| // created. |
| // |
| BadStmt struct { |
| token.Position // beginning position of bad statement |
| } |
| |
| // A DeclStmt node represents a declaration in a statement list. |
| DeclStmt struct { |
| Decl Decl |
| } |
| |
| // An EmptyStmt node represents an empty statement. |
| // The "position" of the empty statement is the position |
| // of the immediately preceeding semicolon. |
| // |
| EmptyStmt struct { |
| token.Position // position of preceeding ";" |
| } |
| |
| // A LabeledStmt node represents a labeled statement. |
| LabeledStmt struct { |
| Label *Ident |
| Stmt Stmt |
| } |
| |
| // An ExprStmt node represents a (stand-alone) expression |
| // in a statement list. |
| // |
| ExprStmt struct { |
| X Expr // expression |
| } |
| |
| // An IncDecStmt node represents an increment or decrement statement. |
| IncDecStmt struct { |
| X Expr |
| Tok token.Token // INC or DEC |
| } |
| |
| // An AssignStmt node represents an assignment or |
| // a short variable declaration. |
| AssignStmt struct { |
| Lhs []Expr |
| TokPos token.Position // position of Tok |
| Tok token.Token // assignment token, DEFINE |
| Rhs []Expr |
| } |
| |
| // A GoStmt node represents a go statement. |
| GoStmt struct { |
| token.Position // position of "go" keyword |
| Call *CallExpr |
| } |
| |
| // A DeferStmt node represents a defer statement. |
| DeferStmt struct { |
| token.Position // position of "defer" keyword |
| Call *CallExpr |
| } |
| |
| // A ReturnStmt node represents a return statement. |
| ReturnStmt struct { |
| token.Position // position of "return" keyword |
| Results []Expr |
| } |
| |
| // A BranchStmt node represents a break, continue, goto, |
| // or fallthrough statement. |
| // |
| BranchStmt struct { |
| token.Position // position of Tok |
| Tok token.Token // keyword token (BREAK, CONTINUE, GOTO, FALLTHROUGH) |
| Label *Ident |
| } |
| |
| // A BlockStmt node represents a braced statement list. |
| BlockStmt struct { |
| token.Position // position of "{" |
| List []Stmt |
| Rbrace token.Position // position of "}" |
| } |
| |
| // An IfStmt node represents an if statement. |
| IfStmt struct { |
| token.Position // position of "if" keyword |
| Init Stmt |
| Cond Expr |
| Body *BlockStmt |
| Else Stmt |
| } |
| |
| // A CaseClause represents a case of an expression switch statement. |
| CaseClause struct { |
| token.Position // position of "case" or "default" keyword |
| Values []Expr // nil means default case |
| Colon token.Position // position of ":" |
| Body []Stmt // statement list; or nil |
| } |
| |
| // A SwitchStmt node represents an expression switch statement. |
| SwitchStmt struct { |
| token.Position // position of "switch" keyword |
| Init Stmt |
| Tag Expr |
| Body *BlockStmt // CaseClauses only |
| } |
| |
| // A TypeCaseClause represents a case of a type switch statement. |
| TypeCaseClause struct { |
| token.Position // position of "case" or "default" keyword |
| Types []Expr // nil means default case |
| Colon token.Position // position of ":" |
| Body []Stmt // statement list; or nil |
| } |
| |
| // An TypeSwitchStmt node represents a type switch statement. |
| TypeSwitchStmt struct { |
| token.Position // position of "switch" keyword |
| Init Stmt |
| Assign Stmt // x := y.(type) |
| Body *BlockStmt // TypeCaseClauses only |
| } |
| |
| // A CommClause node represents a case of a select statement. |
| CommClause struct { |
| token.Position // position of "case" or "default" keyword |
| Tok token.Token // ASSIGN or DEFINE (valid only if Lhs != nil) |
| Lhs, Rhs Expr // Rhs == nil means default case |
| Colon token.Position // position of ":" |
| Body []Stmt // statement list; or nil |
| } |
| |
| // An SelectStmt node represents a select statement. |
| SelectStmt struct { |
| token.Position // position of "select" keyword |
| Body *BlockStmt // CommClauses only |
| } |
| |
| // A ForStmt represents a for statement. |
| ForStmt struct { |
| token.Position // position of "for" keyword |
| Init Stmt |
| Cond Expr |
| Post Stmt |
| Body *BlockStmt |
| } |
| |
| // A RangeStmt represents a for statement with a range clause. |
| RangeStmt struct { |
| token.Position // position of "for" keyword |
| Key, Value Expr // Value may be nil |
| TokPos token.Position // position of Tok |
| Tok token.Token // ASSIGN, DEFINE |
| X Expr // value to range over |
| Body *BlockStmt |
| } |
| ) |
| |
| |
| // Pos() implementations for statement nodes where the position |
| // corresponds to the position of a sub-node. |
| // |
| func (s *DeclStmt) Pos() token.Position { return s.Decl.Pos() } |
| func (s *LabeledStmt) Pos() token.Position { return s.Label.Pos() } |
| func (s *ExprStmt) Pos() token.Position { return s.X.Pos() } |
| func (s *IncDecStmt) Pos() token.Position { return s.X.Pos() } |
| func (s *AssignStmt) Pos() token.Position { return s.Lhs[0].Pos() } |
| |
| |
| // stmtNode() ensures that only statement nodes can be |
| // assigned to a StmtNode. |
| // |
| func (s *BadStmt) stmtNode() {} |
| func (s *DeclStmt) stmtNode() {} |
| func (s *EmptyStmt) stmtNode() {} |
| func (s *LabeledStmt) stmtNode() {} |
| func (s *ExprStmt) stmtNode() {} |
| func (s *IncDecStmt) stmtNode() {} |
| func (s *AssignStmt) stmtNode() {} |
| func (s *GoStmt) stmtNode() {} |
| func (s *DeferStmt) stmtNode() {} |
| func (s *ReturnStmt) stmtNode() {} |
| func (s *BranchStmt) stmtNode() {} |
| func (s *BlockStmt) stmtNode() {} |
| func (s *IfStmt) stmtNode() {} |
| func (s *CaseClause) stmtNode() {} |
| func (s *SwitchStmt) stmtNode() {} |
| func (s *TypeCaseClause) stmtNode() {} |
| func (s *TypeSwitchStmt) stmtNode() {} |
| func (s *CommClause) stmtNode() {} |
| func (s *SelectStmt) stmtNode() {} |
| func (s *ForStmt) stmtNode() {} |
| func (s *RangeStmt) stmtNode() {} |
| |
| |
| // ---------------------------------------------------------------------------- |
| // Declarations |
| |
| // A Spec node represents a single (non-parenthesized) import, |
| // constant, type, or variable declaration. |
| // |
| type ( |
| // The Spec type stands for any of *ImportSpec, *ValueSpec, and *TypeSpec. |
| Spec interface { |
| Node |
| specNode() |
| } |
| |
| // An ImportSpec node represents a single package import. |
| ImportSpec struct { |
| Doc *CommentGroup // associated documentation; or nil |
| Name *Ident // local package name (including "."); or nil |
| Path []*BasicLit // package path |
| Comment *CommentGroup // line comments; or nil |
| } |
| |
| // A ValueSpec node represents a constant or variable declaration |
| // (ConstSpec or VarSpec production). |
| ValueSpec struct { |
| Doc *CommentGroup // associated documentation; or nil |
| Names []*Ident // value names |
| Type Expr // value type; or nil |
| Values []Expr // initial values; or nil |
| Comment *CommentGroup // line comments; or nil |
| } |
| |
| // A TypeSpec node represents a type declaration (TypeSpec production). |
| TypeSpec struct { |
| Doc *CommentGroup // associated documentation; or nil |
| Name *Ident // type name |
| Type Expr // *ArrayType, *StructType, *FuncType, *InterfaceType, *MapType, *ChanType or *Ident |
| Comment *CommentGroup // line comments; or nil |
| } |
| ) |
| |
| |
| // Pos() implementations for spec nodes. |
| // |
| func (s *ImportSpec) Pos() token.Position { |
| if s.Name != nil { |
| return s.Name.Pos() |
| } |
| return s.Path[0].Pos() |
| } |
| |
| func (s *ValueSpec) Pos() token.Position { return s.Names[0].Pos() } |
| func (s *TypeSpec) Pos() token.Position { return s.Name.Pos() } |
| |
| |
| // specNode() ensures that only spec nodes can be |
| // assigned to a Spec. |
| // |
| func (s *ImportSpec) specNode() {} |
| func (s *ValueSpec) specNode() {} |
| func (s *TypeSpec) specNode() {} |
| |
| |
| // A declaration is represented by one of the following declaration nodes. |
| // |
| type ( |
| // A BadDecl node is a placeholder for declarations containing |
| // syntax errors for which no correct declaration nodes can be |
| // created. |
| // |
| BadDecl struct { |
| token.Position // beginning position of bad declaration |
| } |
| |
| // A GenDecl node (generic declaration node) represents an import, |
| // constant, type or variable declaration. A valid Lparen position |
| // (Lparen.Line > 0) indicates a parenthesized declaration. |
| // |
| // Relationship between Tok value and Specs element type: |
| // |
| // token.IMPORT *ImportSpec |
| // token.CONST *ValueSpec |
| // token.TYPE *TypeSpec |
| // token.VAR *ValueSpec |
| // |
| GenDecl struct { |
| Doc *CommentGroup // associated documentation; or nil |
| token.Position // position of Tok |
| Tok token.Token // IMPORT, CONST, TYPE, VAR |
| Lparen token.Position // position of '(', if any |
| Specs []Spec |
| Rparen token.Position // position of ')', if any |
| } |
| |
| // A FuncDecl node represents a function declaration. |
| FuncDecl struct { |
| Doc *CommentGroup // associated documentation; or nil |
| Recv *Field // receiver (methods); or nil (functions) |
| Name *Ident // function/method name |
| Type *FuncType // position of Func keyword, parameters and results |
| Body *BlockStmt // function body; or nil (forward declaration) |
| } |
| ) |
| |
| |
| // The position of a FuncDecl node is the position of its function type. |
| func (d *FuncDecl) Pos() token.Position { return d.Type.Pos() } |
| |
| |
| // declNode() ensures that only declaration nodes can be |
| // assigned to a DeclNode. |
| // |
| func (d *BadDecl) declNode() {} |
| func (d *GenDecl) declNode() {} |
| func (d *FuncDecl) declNode() {} |
| |
| |
| // ---------------------------------------------------------------------------- |
| // Files and packages |
| |
| // A File node represents a Go source file. |
| // |
| type File struct { |
| Doc *CommentGroup // associated documentation; or nil |
| token.Position // position of "package" keyword |
| Name *Ident // package name |
| Decls []Decl // top-level declarations |
| Comments *CommentGroup // list of all comments in the source file |
| } |
| |
| |
| // A Package node represents a set of source files |
| // collectively building a Go package. |
| // |
| type Package struct { |
| Name string // package name |
| Path string // package path |
| Scope *Scope // package scope |
| Files map[string]*File // path-relative filenames |
| } |