// 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.
// Package ast declares the types used to represent syntax trees for Go// packages.
package astimport ()// ----------------------------------------------------------------------------// 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.typeNodeinterface {Pos() token.Pos// position of first character belonging to the nodeEnd() token.Pos// position of first character immediately after the node}// All expression nodes implement the Expr interface.typeExprinterface {Node exprNode()}// All statement nodes implement the Stmt interface.typeStmtinterface {Node stmtNode()}// All declaration nodes implement the Decl interface.typeDeclinterface {Node declNode()}// ----------------------------------------------------------------------------// Comments// A Comment node represents a single //-style or /*-style comment.//// The Text field contains the comment text without carriage returns (\r) that// may have been present in the source. Because a comment's end position is// computed using len(Text), the position reported by End() does not match the// true source end position for comments containing carriage returns.typeCommentstruct { Slash token.Pos// position of "/" starting the comment Text string// comment text (excluding '\n' for //-style comments)}func ( *Comment) () token.Pos { return .Slash }func ( *Comment) () token.Pos { returntoken.Pos(int(.Slash) + len(.Text)) }// A CommentGroup represents a sequence of comments// with no other tokens and no empty lines between.typeCommentGroupstruct { List []*Comment// len(List) > 0}func ( *CommentGroup) () token.Pos { return .List[0].Pos() }func ( *CommentGroup) () token.Pos { return .List[len(.List)-1].End() }func isWhitespace( byte) bool { return == ' ' || == '\t' || == '\n' || == '\r' }func stripTrailingWhitespace( string) string { := len()for > 0 && isWhitespace([-1]) { -- }return [0:]}// Text returns the text of the comment.// Comment markers (//, /*, and */), the first space of a line comment, and// leading and trailing empty lines are removed.// Comment directives like "//line" and "//go:noinline" are also removed.// Multiple empty lines are reduced to one, and trailing space on lines is trimmed.// Unless the result is empty, it is newline-terminated.func ( *CommentGroup) () string {if == nil {return"" } := make([]string, len(.List))for , := range .List { [] = .Text } := make([]string, 0, 10) // most comments are less than 10 linesfor , := range {// Remove comment markers. // The parser has given us exactly the comment text.switch [1] {case'/'://-style comment (no newline at the end) = [2:]iflen() == 0 {// empty linebreak }if [0] == ' ' {// strip first space - required for Example tests = [1:]break }ifisDirective() {// Ignore //go:noinline, //line, and so on.continue }case'*':/*-style comment */ = [2 : len()-2] }// Split on newlines. := strings.Split(, "\n")// Walk lines, stripping trailing white space and adding to list.for , := range { = append(, stripTrailingWhitespace()) } }// Remove leading blank lines; convert runs of // interior blank lines to a single blank line. := 0for , := range {if != "" || > 0 && [-1] != "" { [] = ++ } } = [0:]// Add final "" entry to get trailing newline from Join.if > 0 && [-1] != "" { = append(, "") }returnstrings.Join(, "\n")}// isDirective reports whether c is a comment directive.// This code is also in go/printer.func isDirective( string) bool {// "//line " is a line directive. // "//extern " is for gccgo. // "//export " is for cgo. // (The // has been removed.)ifstrings.HasPrefix(, "line ") || strings.HasPrefix(, "extern ") || strings.HasPrefix(, "export ") {returntrue }// "//[a-z0-9]+:[a-z0-9]" // (The // has been removed.) := strings.Index(, ":")if <= 0 || +1 >= len() {returnfalse }for := 0; <= +1; ++ {if == {continue } := []if !('a' <= && <= 'z' || '0' <= && <= '9') {returnfalse } }returntrue}// ----------------------------------------------------------------------------// 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.// Field.Names is nil for unnamed parameters (parameter lists which only contain types)// and embedded struct fields. In the latter case, the field name is the type name.typeFieldstruct { Doc *CommentGroup// associated documentation; or nil Names []*Ident// field/method/(type) parameter names; or nil Type Expr// field/method/parameter type; or nil Tag *BasicLit// field tag; or nil Comment *CommentGroup// line comments; or nil}func ( *Field) () token.Pos {iflen(.Names) > 0 {return .Names[0].Pos() }if .Type != nil {return .Type.Pos() }returntoken.NoPos}func ( *Field) () token.Pos {if .Tag != nil {return .Tag.End() }if .Type != nil {return .Type.End() }iflen(.Names) > 0 {return .Names[len(.Names)-1].End() }returntoken.NoPos}// A FieldList represents a list of Fields, enclosed by parentheses,// curly braces, or square brackets.typeFieldListstruct { Opening token.Pos// position of opening parenthesis/brace/bracket, if any List []*Field// field list; or nil Closing token.Pos// position of closing parenthesis/brace/bracket, if any}func ( *FieldList) () token.Pos {if .Opening.IsValid() {return .Opening }// the list should not be empty in this case; // be conservative and guard against bad ASTsiflen(.List) > 0 {return .List[0].Pos() }returntoken.NoPos}func ( *FieldList) () token.Pos {if .Closing.IsValid() {return .Closing + 1 }// the list should not be empty in this case; // be conservative and guard against bad ASTsif := len(.List); > 0 {return .List[-1].End() }returntoken.NoPos}// NumFields returns the number of parameters or struct fields represented by a FieldList.func ( *FieldList) () int { := 0if != nil {for , := range .List { := len(.Names)if == 0 { = 1 } += } }return}// 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 an expression containing // syntax errors for which a correct expression node cannot be // created. //BadExprstruct { From, To token.Pos// position range of bad expression }// An Ident node represents an identifier.Identstruct { NamePos token.Pos// identifier position Name string// identifier name Obj *Object// denoted object; or nil }// An Ellipsis node stands for the "..." type in a // parameter list or the "..." length in an array type. //Ellipsisstruct { Ellipsis token.Pos// position of "..." Elt Expr// ellipsis element type (parameter lists only); or nil }// A BasicLit node represents a literal of basic type.BasicLitstruct { ValuePos token.Pos// literal position Kind token.Token// token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING Value string// literal string; e.g. 42, 0x7f, 3.14, 1e-9, 2.4i, 'a', '\x7f', "foo" or `\m\n\o` }// A FuncLit node represents a function literal.FuncLitstruct { Type *FuncType// function type Body *BlockStmt// function body }// A CompositeLit node represents a composite literal.CompositeLitstruct { Type Expr// literal type; or nil Lbrace token.Pos// position of "{" Elts []Expr// list of composite elements; or nil Rbrace token.Pos// position of "}" Incomplete bool// true if (source) expressions are missing in the Elts list }// A ParenExpr node represents a parenthesized expression.ParenExprstruct { Lparen token.Pos// position of "(" X Expr// parenthesized expression Rparen token.Pos// position of ")" }// A SelectorExpr node represents an expression followed by a selector.SelectorExprstruct { X Expr// expression Sel *Ident// field selector }// An IndexExpr node represents an expression followed by an index.IndexExprstruct { X Expr// expression Lbrack token.Pos// position of "[" Index Expr// index expression Rbrack token.Pos// position of "]" }// An IndexListExpr node represents an expression followed by multiple // indices.IndexListExprstruct { X Expr// expression Lbrack token.Pos// position of "[" Indices []Expr// index expressions Rbrack token.Pos// position of "]" }// A SliceExpr node represents an expression followed by slice indices.SliceExprstruct { X Expr// expression Lbrack token.Pos// position of "[" Low Expr// begin of slice range; or nil High Expr// end of slice range; or nil Max Expr// maximum capacity of slice; or nil Slice3 bool// true if 3-index slice (2 colons present) Rbrack token.Pos// position of "]" }// A TypeAssertExpr node represents an expression followed by a // type assertion. //TypeAssertExprstruct { X Expr// expression Lparen token.Pos// position of "(" Type Expr// asserted type; nil means type switch X.(type) Rparen token.Pos// position of ")" }// A CallExpr node represents an expression followed by an argument list.CallExprstruct { Fun Expr// function expression Lparen token.Pos// position of "(" Args []Expr// function arguments; or nil Ellipsis token.Pos// position of "..." (token.NoPos if there is no "...") Rparen token.Pos// position of ")" }// A StarExpr node represents an expression of the form "*" Expression. // Semantically it could be a unary "*" expression, or a pointer type. //StarExprstruct { Star token.Pos// position of "*" X Expr// operand }// A UnaryExpr node represents a unary expression. // Unary "*" expressions are represented via StarExpr nodes. //UnaryExprstruct { OpPos token.Pos// position of Op Op token.Token// operator X Expr// operand }// A BinaryExpr node represents a binary expression.BinaryExprstruct { X Expr// left operand OpPos token.Pos// position of Op Op token.Token// operator Y Expr// right operand }// A KeyValueExpr node represents (key : value) pairs // in composite literals. //KeyValueExprstruct { Key Expr Colon token.Pos// position of ":" Value Expr })// The direction of a channel type is indicated by a bit// mask including one or both of the following constants.typeChanDirintconst (SENDChanDir = 1 << iotaRECV)// 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.ArrayTypestruct { Lbrack token.Pos// 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.StructTypestruct { Struct token.Pos// position of "struct" keyword Fields *FieldList// list of field declarations 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.FuncTypestruct { Func token.Pos// position of "func" keyword (token.NoPos if there is no "func") TypeParams *FieldList// type parameters; or nil Params *FieldList// (incoming) parameters; non-nil Results *FieldList// (outgoing) results; or nil }// An InterfaceType node represents an interface type.InterfaceTypestruct { Interface token.Pos// position of "interface" keyword Methods *FieldList// list of embedded interfaces, methods, or types Incomplete bool// true if (source) methods or types are missing in the Methods list }// A MapType node represents a map type.MapTypestruct { Map token.Pos// position of "map" keyword Key Expr Value Expr }// A ChanType node represents a channel type.ChanTypestruct { Begin token.Pos// position of "chan" keyword or "<-" (whichever comes first) Arrow token.Pos// position of "<-" (token.NoPos if there is no "<-") Dir ChanDir// channel direction Value Expr// value type })// Pos and End implementations for expression/type nodes.func ( *BadExpr) () token.Pos { return .From }func ( *Ident) () token.Pos { return .NamePos }func ( *Ellipsis) () token.Pos { return .Ellipsis }func ( *BasicLit) () token.Pos { return .ValuePos }func ( *FuncLit) () token.Pos { return .Type.Pos() }func ( *CompositeLit) () token.Pos {if .Type != nil {return .Type.Pos() }return .Lbrace}func ( *ParenExpr) () token.Pos { return .Lparen }func ( *SelectorExpr) () token.Pos { return .X.Pos() }func ( *IndexExpr) () token.Pos { return .X.Pos() }func ( *IndexListExpr) () token.Pos { return .X.Pos() }func ( *SliceExpr) () token.Pos { return .X.Pos() }func ( *TypeAssertExpr) () token.Pos { return .X.Pos() }func ( *CallExpr) () token.Pos { return .Fun.Pos() }func ( *StarExpr) () token.Pos { return .Star }func ( *UnaryExpr) () token.Pos { return .OpPos }func ( *BinaryExpr) () token.Pos { return .X.Pos() }func ( *KeyValueExpr) () token.Pos { return .Key.Pos() }func ( *ArrayType) () token.Pos { return .Lbrack }func ( *StructType) () token.Pos { return .Struct }func ( *FuncType) () token.Pos {if .Func.IsValid() || .Params == nil { // see issue 3870return .Func }return .Params.Pos() // interface method declarations have no "func" keyword}func ( *InterfaceType) () token.Pos { return .Interface }func ( *MapType) () token.Pos { return .Map }func ( *ChanType) () token.Pos { return .Begin }func ( *BadExpr) () token.Pos { return .To }func ( *Ident) () token.Pos { returntoken.Pos(int(.NamePos) + len(.Name)) }func ( *Ellipsis) () token.Pos {if .Elt != nil {return .Elt.End() }return .Ellipsis + 3// len("...")}func ( *BasicLit) () token.Pos { returntoken.Pos(int(.ValuePos) + len(.Value)) }func ( *FuncLit) () token.Pos { return .Body.End() }func ( *CompositeLit) () token.Pos { return .Rbrace + 1 }func ( *ParenExpr) () token.Pos { return .Rparen + 1 }func ( *SelectorExpr) () token.Pos { return .Sel.End() }func ( *IndexExpr) () token.Pos { return .Rbrack + 1 }func ( *IndexListExpr) () token.Pos { return .Rbrack + 1 }func ( *SliceExpr) () token.Pos { return .Rbrack + 1 }func ( *TypeAssertExpr) () token.Pos { return .Rparen + 1 }func ( *CallExpr) () token.Pos { return .Rparen + 1 }func ( *StarExpr) () token.Pos { return .X.End() }func ( *UnaryExpr) () token.Pos { return .X.End() }func ( *BinaryExpr) () token.Pos { return .Y.End() }func ( *KeyValueExpr) () token.Pos { return .Value.End() }func ( *ArrayType) () token.Pos { return .Elt.End() }func ( *StructType) () token.Pos { return .Fields.End() }func ( *FuncType) () token.Pos {if .Results != nil {return .Results.End() }return .Params.End()}func ( *InterfaceType) () token.Pos { return .Methods.End() }func ( *MapType) () token.Pos { return .Value.End() }func ( *ChanType) () token.Pos { return .Value.End() }// exprNode() ensures that only expression/type nodes can be// assigned to an Expr.func (*BadExpr) () {}func (*Ident) () {}func (*Ellipsis) () {}func (*BasicLit) () {}func (*FuncLit) () {}func (*CompositeLit) () {}func (*ParenExpr) () {}func (*SelectorExpr) () {}func (*IndexExpr) () {}func (*IndexListExpr) () {}func (*SliceExpr) () {}func (*TypeAssertExpr) () {}func (*CallExpr) () {}func (*StarExpr) () {}func (*UnaryExpr) () {}func (*BinaryExpr) () {}func (*KeyValueExpr) () {}func (*ArrayType) () {}func (*StructType) () {}func (*FuncType) () {}func (*InterfaceType) () {}func (*MapType) () {}func (*ChanType) () {}// ----------------------------------------------------------------------------// Convenience functions for Idents// NewIdent creates a new Ident without position.// Useful for ASTs generated by code other than the Go parser.func ( string) *Ident { return &Ident{token.NoPos, , nil} }// IsExported reports whether name starts with an upper-case letter.func ( string) bool { returntoken.IsExported() }// IsExported reports whether id starts with an upper-case letter.func ( *Ident) () bool { returntoken.IsExported(.Name) }func ( *Ident) () string {if != nil {return .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. //BadStmtstruct { From, To token.Pos// position range of bad statement }// A DeclStmt node represents a declaration in a statement list.DeclStmtstruct { Decl Decl// *GenDecl with CONST, TYPE, or VAR token }// An EmptyStmt node represents an empty statement. // The "position" of the empty statement is the position // of the immediately following (explicit or implicit) semicolon. //EmptyStmtstruct { Semicolon token.Pos// position of following ";" Implicit bool// if set, ";" was omitted in the source }// A LabeledStmt node represents a labeled statement.LabeledStmtstruct { Label *Ident Colon token.Pos// position of ":" Stmt Stmt }// An ExprStmt node represents a (stand-alone) expression // in a statement list. //ExprStmtstruct { X Expr// expression }// A SendStmt node represents a send statement.SendStmtstruct { Chan Expr Arrow token.Pos// position of "<-" Value Expr }// An IncDecStmt node represents an increment or decrement statement.IncDecStmtstruct { X Expr TokPos token.Pos// position of Tok Tok token.Token// INC or DEC }// An AssignStmt node represents an assignment or // a short variable declaration. //AssignStmtstruct { Lhs []Expr TokPos token.Pos// position of Tok Tok token.Token// assignment token, DEFINE Rhs []Expr }// A GoStmt node represents a go statement.GoStmtstruct { Go token.Pos// position of "go" keyword Call *CallExpr }// A DeferStmt node represents a defer statement.DeferStmtstruct { Defer token.Pos// position of "defer" keyword Call *CallExpr }// A ReturnStmt node represents a return statement.ReturnStmtstruct { Return token.Pos// position of "return" keyword Results []Expr// result expressions; or nil }// A BranchStmt node represents a break, continue, goto, // or fallthrough statement. //BranchStmtstruct { TokPos token.Pos// position of Tok Tok token.Token// keyword token (BREAK, CONTINUE, GOTO, FALLTHROUGH) Label *Ident// label name; or nil }// A BlockStmt node represents a braced statement list.BlockStmtstruct { Lbrace token.Pos// position of "{" List []Stmt Rbrace token.Pos// position of "}", if any (may be absent due to syntax error) }// An IfStmt node represents an if statement.IfStmtstruct { If token.Pos// position of "if" keyword Init Stmt// initialization statement; or nil Cond Expr// condition Body *BlockStmt Else Stmt// else branch; or nil }// A CaseClause represents a case of an expression or type switch statement.CaseClausestruct { Case token.Pos// position of "case" or "default" keyword List []Expr// list of expressions or types; nil means default case Colon token.Pos// position of ":" Body []Stmt// statement list; or nil }// A SwitchStmt node represents an expression switch statement.SwitchStmtstruct { Switch token.Pos// position of "switch" keyword Init Stmt// initialization statement; or nil Tag Expr// tag expression; or nil Body *BlockStmt// CaseClauses only }// A TypeSwitchStmt node represents a type switch statement.TypeSwitchStmtstruct { Switch token.Pos// position of "switch" keyword Init Stmt// initialization statement; or nil Assign Stmt// x := y.(type) or y.(type) Body *BlockStmt// CaseClauses only }// A CommClause node represents a case of a select statement.CommClausestruct { Case token.Pos// position of "case" or "default" keyword Comm Stmt// send or receive statement; nil means default case Colon token.Pos// position of ":" Body []Stmt// statement list; or nil }// A SelectStmt node represents a select statement.SelectStmtstruct { Select token.Pos// position of "select" keyword Body *BlockStmt// CommClauses only }// A ForStmt represents a for statement.ForStmtstruct { For token.Pos// position of "for" keyword Init Stmt// initialization statement; or nil Cond Expr// condition; or nil Post Stmt// post iteration statement; or nil Body *BlockStmt }// A RangeStmt represents a for statement with a range clause.RangeStmtstruct { For token.Pos// position of "for" keyword Key, Value Expr// Key, Value may be nil TokPos token.Pos// position of Tok; invalid if Key == nil Tok token.Token// ILLEGAL if Key == nil, ASSIGN, DEFINE Range token.Pos// position of "range" keyword X Expr// value to range over Body *BlockStmt })// Pos and End implementations for statement nodes.func ( *BadStmt) () token.Pos { return .From }func ( *DeclStmt) () token.Pos { return .Decl.Pos() }func ( *EmptyStmt) () token.Pos { return .Semicolon }func ( *LabeledStmt) () token.Pos { return .Label.Pos() }func ( *ExprStmt) () token.Pos { return .X.Pos() }func ( *SendStmt) () token.Pos { return .Chan.Pos() }func ( *IncDecStmt) () token.Pos { return .X.Pos() }func ( *AssignStmt) () token.Pos { return .Lhs[0].Pos() }func ( *GoStmt) () token.Pos { return .Go }func ( *DeferStmt) () token.Pos { return .Defer }func ( *ReturnStmt) () token.Pos { return .Return }func ( *BranchStmt) () token.Pos { return .TokPos }func ( *BlockStmt) () token.Pos { return .Lbrace }func ( *IfStmt) () token.Pos { return .If }func ( *CaseClause) () token.Pos { return .Case }func ( *SwitchStmt) () token.Pos { return .Switch }func ( *TypeSwitchStmt) () token.Pos { return .Switch }func ( *CommClause) () token.Pos { return .Case }func ( *SelectStmt) () token.Pos { return .Select }func ( *ForStmt) () token.Pos { return .For }func ( *RangeStmt) () token.Pos { return .For }func ( *BadStmt) () token.Pos { return .To }func ( *DeclStmt) () token.Pos { return .Decl.End() }func ( *EmptyStmt) () token.Pos {if .Implicit {return .Semicolon }return .Semicolon + 1/* len(";") */}func ( *LabeledStmt) () token.Pos { return .Stmt.End() }func ( *ExprStmt) () token.Pos { return .X.End() }func ( *SendStmt) () token.Pos { return .Value.End() }func ( *IncDecStmt) () token.Pos {return .TokPos + 2/* len("++") */}func ( *AssignStmt) () token.Pos { return .Rhs[len(.Rhs)-1].End() }func ( *GoStmt) () token.Pos { return .Call.End() }func ( *DeferStmt) () token.Pos { return .Call.End() }func ( *ReturnStmt) () token.Pos {if := len(.Results); > 0 {return .Results[-1].End() }return .Return + 6// len("return")}func ( *BranchStmt) () token.Pos {if .Label != nil {return .Label.End() }returntoken.Pos(int(.TokPos) + len(.Tok.String()))}func ( *BlockStmt) () token.Pos {if .Rbrace.IsValid() {return .Rbrace + 1 }if := len(.List); > 0 {return .List[-1].End() }return .Lbrace + 1}func ( *IfStmt) () token.Pos {if .Else != nil {return .Else.End() }return .Body.End()}func ( *CaseClause) () token.Pos {if := len(.Body); > 0 {return .Body[-1].End() }return .Colon + 1}func ( *SwitchStmt) () token.Pos { return .Body.End() }func ( *TypeSwitchStmt) () token.Pos { return .Body.End() }func ( *CommClause) () token.Pos {if := len(.Body); > 0 {return .Body[-1].End() }return .Colon + 1}func ( *SelectStmt) () token.Pos { return .Body.End() }func ( *ForStmt) () token.Pos { return .Body.End() }func ( *RangeStmt) () token.Pos { return .Body.End() }// stmtNode() ensures that only statement nodes can be// assigned to a Stmt.func (*BadStmt) () {}func (*DeclStmt) () {}func (*EmptyStmt) () {}func (*LabeledStmt) () {}func (*ExprStmt) () {}func (*SendStmt) () {}func (*IncDecStmt) () {}func (*AssignStmt) () {}func (*GoStmt) () {}func (*DeferStmt) () {}func (*ReturnStmt) () {}func (*BranchStmt) () {}func (*BlockStmt) () {}func (*IfStmt) () {}func (*CaseClause) () {}func (*SwitchStmt) () {}func (*TypeSwitchStmt) () {}func (*CommClause) () {}func (*SelectStmt) () {}func (*ForStmt) () {}func (*RangeStmt) () {}// ----------------------------------------------------------------------------// 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.Specinterface {Node specNode() }// An ImportSpec node represents a single package import.ImportSpecstruct { Doc *CommentGroup// associated documentation; or nil Name *Ident// local package name (including "."); or nil Path *BasicLit// import path Comment *CommentGroup// line comments; or nil EndPos token.Pos// end of spec (overrides Path.Pos if nonzero) }// A ValueSpec node represents a constant or variable declaration // (ConstSpec or VarSpec production). //ValueSpecstruct { Doc *CommentGroup// associated documentation; or nil Names []*Ident// value names (len(Names) > 0) 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).TypeSpecstruct { Doc *CommentGroup// associated documentation; or nil Name *Ident// type name TypeParams *FieldList// type parameters; or nil Assign token.Pos// position of '=', if any Type Expr// *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes Comment *CommentGroup// line comments; or nil })// Pos and End implementations for spec nodes.func ( *ImportSpec) () token.Pos {if .Name != nil {return .Name.Pos() }return .Path.Pos()}func ( *ValueSpec) () token.Pos { return .Names[0].Pos() }func ( *TypeSpec) () token.Pos { return .Name.Pos() }func ( *ImportSpec) () token.Pos {if .EndPos != 0 {return .EndPos }return .Path.End()}func ( *ValueSpec) () token.Pos {if := len(.Values); > 0 {return .Values[-1].End() }if .Type != nil {return .Type.End() }return .Names[len(.Names)-1].End()}func ( *TypeSpec) () token.Pos { return .Type.End() }// specNode() ensures that only spec nodes can be// assigned to a Spec.func (*ImportSpec) () {}func (*ValueSpec) () {}func (*TypeSpec) () {}// A declaration is represented by one of the following declaration nodes.type (// A BadDecl node is a placeholder for a declaration containing // syntax errors for which a correct declaration node cannot be // created. //BadDeclstruct { From, To token.Pos// position range of bad declaration }// A GenDecl node (generic declaration node) represents an import, // constant, type or variable declaration. A valid Lparen position // (Lparen.IsValid()) indicates a parenthesized declaration. // // Relationship between Tok value and Specs element type: // // token.IMPORT *ImportSpec // token.CONST *ValueSpec // token.TYPE *TypeSpec // token.VAR *ValueSpec //GenDeclstruct { Doc *CommentGroup// associated documentation; or nil TokPos token.Pos// position of Tok Tok token.Token// IMPORT, CONST, TYPE, or VAR Lparen token.Pos// position of '(', if any Specs []Spec Rparen token.Pos// position of ')', if any }// A FuncDecl node represents a function declaration.FuncDeclstruct { Doc *CommentGroup// associated documentation; or nil Recv *FieldList// receiver (methods); or nil (functions) Name *Ident// function/method name Type *FuncType// function signature: type and value parameters, results, and position of "func" keyword Body *BlockStmt// function body; or nil for external (non-Go) function })// Pos and End implementations for declaration nodes.func ( *BadDecl) () token.Pos { return .From }func ( *GenDecl) () token.Pos { return .TokPos }func ( *FuncDecl) () token.Pos { return .Type.Pos() }func ( *BadDecl) () token.Pos { return .To }func ( *GenDecl) () token.Pos {if .Rparen.IsValid() {return .Rparen + 1 }return .Specs[0].End()}func ( *FuncDecl) () token.Pos {if .Body != nil {return .Body.End() }return .Type.End()}// declNode() ensures that only declaration nodes can be// assigned to a Decl.func (*BadDecl) () {}func (*GenDecl) () {}func (*FuncDecl) () {}// ----------------------------------------------------------------------------// Files and packages// A File node represents a Go source file.//// The Comments list contains all comments in the source file in order of// appearance, including the comments that are pointed to from other nodes// via Doc and Comment fields.//// For correct printing of source code containing comments (using packages// go/format and go/printer), special care must be taken to update comments// when a File's syntax tree is modified: For printing, comments are interspersed// between tokens based on their position. If syntax tree nodes are// removed or moved, relevant comments in their vicinity must also be removed// (from the File.Comments list) or moved accordingly (by updating their// positions). A CommentMap may be used to facilitate some of these operations.//// Whether and how a comment is associated with a node depends on the// interpretation of the syntax tree by the manipulating program: Except for Doc// and Comment comments directly associated with nodes, the remaining comments// are "free-floating" (see also issues #18593, #20744).typeFilestruct { Doc *CommentGroup// associated documentation; or nil Package token.Pos// position of "package" keyword Name *Ident// package name Decls []Decl// top-level declarations; or nil FileStart, FileEnd token.Pos// start and end of entire file Scope *Scope// package scope (this file only) Imports []*ImportSpec// imports in this file Unresolved []*Ident// unresolved identifiers in this file Comments []*CommentGroup// list of all comments in the source file GoVersion string// minimum Go version required by //go:build or // +build directives}// Pos returns the position of the package declaration.// (Use FileStart for the start of the entire file.)func ( *File) () token.Pos { return .Package }// End returns the end of the last declaration in the file.// (Use FileEnd for the end of the entire file.)func ( *File) () token.Pos {if := len(.Decls); > 0 {return .Decls[-1].End() }return .Name.End()}// A Package node represents a set of source files// collectively building a Go package.typePackagestruct { Name string// package name Scope *Scope// package scope across all files Imports map[string]*Object// map of package id -> package object Files map[string]*File// Go source files by filename}func ( *Package) () token.Pos { returntoken.NoPos }func ( *Package) () token.Pos { returntoken.NoPos }// IsGenerated reports whether the file was generated by a program,// not handwritten, by detecting the special comment described// at https://go.dev/s/generatedcode.//// The syntax tree must have been parsed with the ParseComments flag.// Example://// f, err := parser.ParseFile(fset, filename, src, parser.ParseComments|parser.PackageClauseOnly)// if err != nil { ... }// gen := ast.IsGenerated(f)func ( *File) bool { , := generator()return}func generator( *File) (string, bool) {for , := range .Comments {for , := range .List {if .Pos() > .Package {break// after package declaration }// opt: check Contains first to avoid unnecessary array allocation in Split.const = "// Code generated "ifstrings.Contains(.Text, ) {for , := rangestrings.Split(.Text, "\n") {if , := strings.CutPrefix(, ); {if , := strings.CutSuffix(, " DO NOT EDIT."); {return , true } } } } } }return"", false}
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.