// 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 parser implements a parser for Go source files. Input may be // provided in a variety of forms (see the various Parse* functions); the // output is an abstract syntax tree (AST) representing the Go source. The // parser is invoked through one of the Parse* functions. // // The parser accepts a larger language than is syntactically permitted by // the Go spec, for simplicity, and for improved robustness in the presence // of syntax errors. For instance, in method declarations, the receiver is // treated like an ordinary parameter list and thus may contain multiple // entries where the spec permits exactly one. Consequently, the corresponding // field in the AST (ast.FuncDecl.Recv) field is not restricted to one entry.
package parser import ( ) // The parser structure holds the parser's internal state. type parser struct { file *token.File errors scanner.ErrorList scanner scanner.Scanner // Tracing/debugging mode Mode // parsing mode trace bool // == (mode&Trace != 0) indent int // indentation used for tracing output // Comments comments []*ast.CommentGroup leadComment *ast.CommentGroup // last lead comment lineComment *ast.CommentGroup // last line comment top bool // in top of file (before package clause) goVersion string // minimum Go version found in //go:build comment // Next token pos token.Pos // token position tok token.Token // one token look-ahead lit string // token literal // Error recovery // (used to limit the number of calls to parser.advance // w/o making scanning progress - avoids potential endless // loops across multiple parser functions during error recovery) syncPos token.Pos // last synchronization position syncCnt int // number of parser.advance calls without progress // Non-syntactic parser control exprLev int // < 0: in control clause, >= 0: in expression inRhs bool // if set, the parser is parsing a rhs expression imports []*ast.ImportSpec // list of imports // nestLev is used to track and limit the recursion depth // during parsing. nestLev int } func ( *parser) ( *token.FileSet, string, []byte, Mode) { .file = .AddFile(, -1, len()) := func( token.Position, string) { .errors.Add(, ) } .scanner.Init(.file, , , scanner.ScanComments) .top = true .mode = .trace = &Trace != 0 // for convenience (p.trace is used frequently) .next() } // ---------------------------------------------------------------------------- // Parsing support func ( *parser) ( ...any) { const = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " const = len() := .file.Position(.pos) fmt.Printf("%5d:%3d: ", .Line, .Column) := 2 * .indent for > { fmt.Print() -= } // i <= n fmt.Print([0:]) fmt.Println(...) } func trace( *parser, string) *parser { .printTrace(, "(") .indent++ return } // Usage pattern: defer un(trace(p, "...")) func un( *parser) { .indent-- .printTrace(")") } // maxNestLev is the deepest we're willing to recurse during parsing const maxNestLev int = 1e5 func incNestLev( *parser) *parser { .nestLev++ if .nestLev > maxNestLev { .error(.pos, "exceeded max nesting depth") panic(bailout{}) } return } // decNestLev is used to track nesting depth during parsing to prevent stack exhaustion. // It is used along with incNestLev in a similar fashion to how un and trace are used. func decNestLev( *parser) { .nestLev-- } // Advance to the next token. func ( *parser) () { // Because of one-token look-ahead, print the previous token // when tracing as it provides a more readable output. The // very first token (!p.pos.IsValid()) is not initialized // (it is token.ILLEGAL), so don't print it. if .trace && .pos.IsValid() { := .tok.String() switch { case .tok.IsLiteral(): .printTrace(, .lit) case .tok.IsOperator(), .tok.IsKeyword(): .printTrace("\"" + + "\"") default: .printTrace() } } for { .pos, .tok, .lit = .scanner.Scan() if .tok == token.COMMENT { if .top && strings.HasPrefix(.lit, "//go:build") { if , := constraint.Parse(.lit); == nil { .goVersion = constraint.GoVersion() } } if .mode&ParseComments == 0 { continue } } else { // Found a non-comment; top of file is over. .top = false } break } } // Consume a comment and return it and the line on which it ends. func ( *parser) () ( *ast.Comment, int) { // /*-style comments may end on a different line than where they start. // Scan the comment for '\n' chars and adjust endline accordingly. = .file.Line(.pos) if .lit[1] == '*' { // don't use range here - no need to decode Unicode code points for := 0; < len(.lit); ++ { if .lit[] == '\n' { ++ } } } = &ast.Comment{Slash: .pos, Text: .lit} .next0() return } // Consume a group of adjacent comments, add it to the parser's // comments list, and return it together with the line at which // the last comment in the group ends. A non-comment token or n // empty lines terminate a comment group. func ( *parser) ( int) ( *ast.CommentGroup, int) { var []*ast.Comment = .file.Line(.pos) for .tok == token.COMMENT && .file.Line(.pos) <= + { var *ast.Comment , = .consumeComment() = append(, ) } // add comment group to the comments list = &ast.CommentGroup{List: } .comments = append(.comments, ) return } // Advance to the next non-comment token. In the process, collect // any comment groups encountered, and remember the last lead and // line comments. // // A lead comment is a comment group that starts and ends in a // line without any other tokens and that is followed by a non-comment // token on the line immediately after the comment group. // // A line comment is a comment group that follows a non-comment // token on the same line, and that has no tokens after it on the line // where it ends. // // Lead and line comments may be considered documentation that is // stored in the AST. func ( *parser) () { .leadComment = nil .lineComment = nil := .pos .next0() if .tok == token.COMMENT { var *ast.CommentGroup var int if .file.Line(.pos) == .file.Line() { // The comment is on same line as the previous token; it // cannot be a lead comment but may be a line comment. , = .consumeCommentGroup(0) if .file.Line(.pos) != || .tok == token.SEMICOLON || .tok == token.EOF { // The next token is on a different line, thus // the last comment group is a line comment. .lineComment = } } // consume successor comments, if any = -1 for .tok == token.COMMENT { , = .consumeCommentGroup(1) } if +1 == .file.Line(.pos) { // The next token is following on the line immediately after the // comment group, thus the last comment group is a lead comment. .leadComment = } } } // A bailout panic is raised to indicate early termination. pos and msg are // only populated when bailing out of object resolution. type bailout struct { pos token.Pos msg string } func ( *parser) ( token.Pos, string) { if .trace { defer un(trace(, "error: "+)) } := .file.Position() // If AllErrors is not set, discard errors reported on the same line // as the last recorded error and stop parsing if there are more than // 10 errors. if .mode&AllErrors == 0 { := len(.errors) if > 0 && .errors[-1].Pos.Line == .Line { return // discard - likely a spurious error } if > 10 { panic(bailout{}) } } .errors.Add(, ) } func ( *parser) ( token.Pos, string) { = "expected " + if == .pos { // the error happened at the current position; // make the error message more specific switch { case .tok == token.SEMICOLON && .lit == "\n": += ", found newline" case .tok.IsLiteral(): // print 123 rather than 'INT', etc. += ", found " + .lit default: += ", found '" + .tok.String() + "'" } } .error(, ) } func ( *parser) ( token.Token) token.Pos { := .pos if .tok != { .errorExpected(, "'"+.String()+"'") } .next() // make progress return } // expect2 is like expect, but it returns an invalid position // if the expected token is not found. func ( *parser) ( token.Token) ( token.Pos) { if .tok == { = .pos } else { .errorExpected(.pos, "'"+.String()+"'") } .next() // make progress return } // expectClosing is like expect but provides a better error message // for the common case of a missing comma before a newline. func ( *parser) ( token.Token, string) token.Pos { if .tok != && .tok == token.SEMICOLON && .lit == "\n" { .error(.pos, "missing ',' before newline in "+) .next() } return .expect() } // expectSemi consumes a semicolon and returns the applicable line comment. func ( *parser) () ( *ast.CommentGroup) { // semicolon is optional before a closing ')' or '}' if .tok != token.RPAREN && .tok != token.RBRACE { switch .tok { case token.COMMA: // permit a ',' instead of a ';' but complain .errorExpected(.pos, "';'") fallthrough case token.SEMICOLON: if .lit == ";" { // explicit semicolon .next() = .lineComment // use following comments } else { // artificial semicolon = .lineComment // use preceding comments .next() } return default: .errorExpected(.pos, "';'") .advance(stmtStart) } } return nil } func ( *parser) ( string, token.Token) bool { if .tok == token.COMMA { return true } if .tok != { := "missing ','" if .tok == token.SEMICOLON && .lit == "\n" { += " before newline" } .error(.pos, +" in "+) return true // "insert" comma and continue } return false } func assert( bool, string) { if ! { panic("go/parser internal error: " + ) } } // advance consumes tokens until the current token p.tok // is in the 'to' set, or token.EOF. For error recovery. func ( *parser) ( map[token.Token]bool) { for ; .tok != token.EOF; .next() { if [.tok] { // Return only if parser made some progress since last // sync or if it has not reached 10 advance calls without // progress. Otherwise consume at least one token to // avoid an endless parser loop (it is possible that // both parseOperand and parseStmt call advance and // correctly do not advance, thus the need for the // invocation limit p.syncCnt). if .pos == .syncPos && .syncCnt < 10 { .syncCnt++ return } if .pos > .syncPos { .syncPos = .pos .syncCnt = 0 return } // Reaching here indicates a parser bug, likely an // incorrect token list in this function, but it only // leads to skipping of possibly correct code if a // previous error is present, and thus is preferred // over a non-terminating parse. } } } var stmtStart = map[token.Token]bool{ token.BREAK: true, token.CONST: true, token.CONTINUE: true, token.DEFER: true, token.FALLTHROUGH: true, token.FOR: true, token.GO: true, token.GOTO: true, token.IF: true, token.RETURN: true, token.SELECT: true, token.SWITCH: true, token.TYPE: true, token.VAR: true, } var declStart = map[token.Token]bool{ token.IMPORT: true, token.CONST: true, token.TYPE: true, token.VAR: true, } var exprEnd = map[token.Token]bool{ token.COMMA: true, token.COLON: true, token.SEMICOLON: true, token.RPAREN: true, token.RBRACK: true, token.RBRACE: true, } // safePos returns a valid file position for a given position: If pos // is valid to begin with, safePos returns pos. If pos is out-of-range, // safePos returns the EOF position. // // This is hack to work around "artificial" end positions in the AST which // are computed by adding 1 to (presumably valid) token positions. If the // token positions are invalid due to parse errors, the resulting end position // may be past the file's EOF position, which would lead to panics if used // later on. func ( *parser) ( token.Pos) ( token.Pos) { defer func() { if recover() != nil { = token.Pos(.file.Base() + .file.Size()) // EOF position } }() _ = .file.Offset() // trigger a panic if position is out-of-range return } // ---------------------------------------------------------------------------- // Identifiers func ( *parser) () *ast.Ident { := .pos := "_" if .tok == token.IDENT { = .lit .next() } else { .expect(token.IDENT) // use expect() error handling } return &ast.Ident{NamePos: , Name: } } func ( *parser) () ( []*ast.Ident) { if .trace { defer un(trace(, "IdentList")) } = append(, .parseIdent()) for .tok == token.COMMA { .next() = append(, .parseIdent()) } return } // ---------------------------------------------------------------------------- // Common productions // If lhs is set, result list elements which are identifiers are not resolved. func ( *parser) () ( []ast.Expr) { if .trace { defer un(trace(, "ExpressionList")) } = append(, .parseExpr()) for .tok == token.COMMA { .next() = append(, .parseExpr()) } return } func ( *parser) ( bool) []ast.Expr { := .inRhs .inRhs = := .parseExprList() .inRhs = return } // ---------------------------------------------------------------------------- // Types func ( *parser) () ast.Expr { if .trace { defer un(trace(, "Type")) } := .tryIdentOrType() if == nil { := .pos .errorExpected(, "type") .advance(exprEnd) return &ast.BadExpr{From: , To: .pos} } return } func ( *parser) ( *ast.Ident) ast.Expr { if .trace { defer un(trace(, "QualifiedIdent")) } := .parseTypeName() if .tok == token.LBRACK { = .parseTypeInstance() } return } // If the result is an identifier, it is not resolved. func ( *parser) ( *ast.Ident) ast.Expr { if .trace { defer un(trace(, "TypeName")) } if == nil { = .parseIdent() } if .tok == token.PERIOD { // ident is a package name .next() := .parseIdent() return &ast.SelectorExpr{X: , Sel: } } return } // "[" has already been consumed, and lbrack is its position. // If len != nil it is the already consumed array length. func ( *parser) ( token.Pos, ast.Expr) *ast.ArrayType { if .trace { defer un(trace(, "ArrayType")) } if == nil { .exprLev++ // always permit ellipsis for more fault-tolerant parsing if .tok == token.ELLIPSIS { = &ast.Ellipsis{Ellipsis: .pos} .next() } else if .tok != token.RBRACK { = .parseRhs() } .exprLev-- } if .tok == token.COMMA { // Trailing commas are accepted in type parameter // lists but not in array type declarations. // Accept for better error handling but complain. .error(.pos, "unexpected comma; expecting ]") .next() } .expect(token.RBRACK) := .parseType() return &ast.ArrayType{Lbrack: , Len: , Elt: } } func ( *parser) ( *ast.Ident) (*ast.Ident, ast.Expr) { if .trace { defer un(trace(, "ArrayFieldOrTypeInstance")) } := .expect(token.LBRACK) := token.NoPos // if valid, the position of a trailing comma preceding the ']' var []ast.Expr if .tok != token.RBRACK { .exprLev++ = append(, .parseRhs()) for .tok == token.COMMA { := .pos .next() if .tok == token.RBRACK { = break } = append(, .parseRhs()) } .exprLev-- } := .expect(token.RBRACK) if len() == 0 { // x []E := .parseType() return , &ast.ArrayType{Lbrack: , Elt: } } // x [P]E or x[P] if len() == 1 { := .tryIdentOrType() if != nil { // x [P]E if .IsValid() { // Trailing commas are invalid in array type fields. .error(, "unexpected comma; expecting ]") } return , &ast.ArrayType{Lbrack: , Len: [0], Elt: } } } // x[P], x[P1, P2], ... return nil, typeparams.PackIndexExpr(, , , ) } func ( *parser) () *ast.Field { if .trace { defer un(trace(, "FieldDecl")) } := .leadComment var []*ast.Ident var ast.Expr switch .tok { case token.IDENT: := .parseIdent() if .tok == token.PERIOD || .tok == token.STRING || .tok == token.SEMICOLON || .tok == token.RBRACE { // embedded type = if .tok == token.PERIOD { = .parseQualifiedIdent() } } else { // name1, name2, ... T = []*ast.Ident{} for .tok == token.COMMA { .next() = append(, .parseIdent()) } // Careful dance: We don't know if we have an embedded instantiated // type T[P1, P2, ...] or a field T of array type []E or [P]E. if len() == 1 && .tok == token.LBRACK { , = .parseArrayFieldOrTypeInstance() if == nil { = nil } } else { // T P = .parseType() } } case token.MUL: := .pos .next() if .tok == token.LPAREN { // *(T) .error(.pos, "cannot parenthesize embedded type") .next() = .parseQualifiedIdent(nil) // expect closing ')' but no need to complain if missing if .tok == token.RPAREN { .next() } } else { // *T = .parseQualifiedIdent(nil) } = &ast.StarExpr{Star: , X: } case token.LPAREN: .error(.pos, "cannot parenthesize embedded type") .next() if .tok == token.MUL { // (*T) := .pos .next() = &ast.StarExpr{Star: , X: .parseQualifiedIdent(nil)} } else { // (T) = .parseQualifiedIdent(nil) } // expect closing ')' but no need to complain if missing if .tok == token.RPAREN { .next() } default: := .pos .errorExpected(, "field name or embedded type") .advance(exprEnd) = &ast.BadExpr{From: , To: .pos} } var *ast.BasicLit if .tok == token.STRING { = &ast.BasicLit{ValuePos: .pos, Kind: .tok, Value: .lit} .next() } := .expectSemi() := &ast.Field{Doc: , Names: , Type: , Tag: , Comment: } return } func ( *parser) () *ast.StructType { if .trace { defer un(trace(, "StructType")) } := .expect(token.STRUCT) := .expect(token.LBRACE) var []*ast.Field for .tok == token.IDENT || .tok == token.MUL || .tok == token.LPAREN { // a field declaration cannot start with a '(' but we accept // it here for more robust parsing and better error messages // (parseFieldDecl will check and complain if necessary) = append(, .parseFieldDecl()) } := .expect(token.RBRACE) return &ast.StructType{ Struct: , Fields: &ast.FieldList{ Opening: , List: , Closing: , }, } } func ( *parser) () *ast.StarExpr { if .trace { defer un(trace(, "PointerType")) } := .expect(token.MUL) := .parseType() return &ast.StarExpr{Star: , X: } } func ( *parser) () *ast.Ellipsis { if .trace { defer un(trace(, "DotsType")) } := .expect(token.ELLIPSIS) := .parseType() return &ast.Ellipsis{Ellipsis: , Elt: } } type field struct { name *ast.Ident typ ast.Expr } func ( *parser) ( *ast.Ident, bool) ( field) { // TODO(rFindley) refactor to be more similar to paramDeclOrNil in the syntax // package if .trace { defer un(trace(, "ParamDeclOrNil")) } := .tok if != nil { .tok = token.IDENT // force token.IDENT case in switch below } else if && .tok == token.TILDE { // "~" ... return field{nil, .embeddedElem(nil)} } switch .tok { case token.IDENT: // name if != nil { .name = .tok = } else { .name = .parseIdent() } switch .tok { case token.IDENT, token.MUL, token.ARROW, token.FUNC, token.CHAN, token.MAP, token.STRUCT, token.INTERFACE, token.LPAREN: // name type .typ = .parseType() case token.LBRACK: // name "[" type1, ..., typeN "]" or name "[" n "]" type .name, .typ = .parseArrayFieldOrTypeInstance(.name) case token.ELLIPSIS: // name "..." type .typ = .parseDotsType() return // don't allow ...type "|" ... case token.PERIOD: // name "." ... .typ = .parseQualifiedIdent(.name) .name = nil case token.TILDE: if { .typ = .embeddedElem(nil) return } case token.OR: if { // name "|" typeset .typ = .embeddedElem(.name) .name = nil return } } case token.MUL, token.ARROW, token.FUNC, token.LBRACK, token.CHAN, token.MAP, token.STRUCT, token.INTERFACE, token.LPAREN: // type .typ = .parseType() case token.ELLIPSIS: // "..." type // (always accepted) .typ = .parseDotsType() return // don't allow ...type "|" ... default: // TODO(rfindley): this is incorrect in the case of type parameter lists // (should be "']'" in that case) .errorExpected(.pos, "')'") .advance(exprEnd) } // [name] type "|" if && .tok == token.OR && .typ != nil { .typ = .embeddedElem(.typ) } return } func ( *parser) ( *ast.Ident, ast.Expr, token.Token) ( []*ast.Field) { if .trace { defer un(trace(, "ParameterList")) } // Type parameters are the only parameter list closed by ']'. := == token.RBRACK := .pos if != nil { = .Pos() } else if != nil { = .Pos() } // Note: The code below matches the corresponding code in the syntax // parser closely. Changes must be reflected in either parser. // For the code to match, we use the local []field list that // corresponds to []syntax.Field. At the end, the list must be // converted into an []*ast.Field. var []field var int // number of parameters that have an explicit name and type var int // number of parameters that have an explicit type for != nil || .tok != && .tok != token.EOF { var field if != nil { if { = .embeddedElem() } = field{, } } else { = .parseParamDecl(, ) } = nil // 1st name was consumed if present = nil // 1st typ was consumed if present if .name != nil || .typ != nil { = append(, ) if .name != nil && .typ != nil { ++ } if .typ != nil { ++ } } if !.atComma("parameter list", ) { break } .next() } if len() == 0 { return // not uncommon } // distribute parameter types (len(list) > 0) if == 0 { // all unnamed => found names are type names for := 0; < len(); ++ { := &[] if := .name; != nil { .typ = .name = nil } } if { // This is the same error handling as below, adjusted for type parameters only. // See comment below for details. (go.dev/issue/64534) var token.Pos var string if == /* same as typed == 0 */ { = .pos // position error at closing ] = "missing type constraint" } else { = // position at opening [ or first name = "missing type parameter name" if len() == 1 { += " or invalid array length" } } .error(, ) } } else if != len() { // some named or we're in a type parameter list => all must be named var token.Pos // left-most error position (or invalid) var ast.Expr // current type (from right to left) for := len() - 1; >= 0; -- { if := &[]; .typ != nil { = .typ if .name == nil { = .Pos() := ast.NewIdent("_") .NamePos = // correct position .name = } } else if != nil { .typ = } else { // par.typ == nil && typ == nil => we only have a par.name = .name.Pos() .typ = &ast.BadExpr{From: , To: .pos} } } if .IsValid() { var string if { // Not all parameters are named because named != len(list). // If named == typed we must have parameters that have no types, // and they must be at the end of the parameter list, otherwise // the types would have been filled in by the right-to-left sweep // above and we wouldn't have an error. Since we are in a type // parameter list, the missing types are constraints. if == { = .pos // position error at closing ] = "missing type constraint" } else { = "missing type parameter name" // go.dev/issue/60812 if len() == 1 { += " or invalid array length" } } } else { = "mixed named and unnamed parameters" } .error(, ) } } // Convert list to []*ast.Field. // If list contains types only, each type gets its own ast.Field. if == 0 { // parameter list consists of types only for , := range { assert(.typ != nil, "nil type in unnamed parameter list") = append(, &ast.Field{Type: .typ}) } return } // If the parameter list consists of named parameters with types, // collect all names with the same types into a single ast.Field. var []*ast.Ident var ast.Expr := func() { assert( != nil, "nil type in named parameter list") := &ast.Field{Names: , Type: } = append(, ) = nil } for , := range { if .typ != { if len() > 0 { () } = .typ } = append(, .name) } if len() > 0 { () } return } func ( *parser) ( bool) (, *ast.FieldList) { if .trace { defer un(trace(, "Parameters")) } if && .tok == token.LBRACK { := .pos .next() // [T any](params) syntax := .parseParameterList(nil, nil, token.RBRACK) := .expect(token.RBRACK) = &ast.FieldList{Opening: , List: , Closing: } // Type parameter lists must not be empty. if .NumFields() == 0 { .error(.Closing, "empty type parameter list") = nil // avoid follow-on errors } } := .expect(token.LPAREN) var []*ast.Field if .tok != token.RPAREN { = .parseParameterList(nil, nil, token.RPAREN) } := .expect(token.RPAREN) = &ast.FieldList{Opening: , List: , Closing: } return } func ( *parser) () *ast.FieldList { if .trace { defer un(trace(, "Result")) } if .tok == token.LPAREN { , := .parseParameters(false) return } := .tryIdentOrType() if != nil { := make([]*ast.Field, 1) [0] = &ast.Field{Type: } return &ast.FieldList{List: } } return nil } func ( *parser) () *ast.FuncType { if .trace { defer un(trace(, "FuncType")) } := .expect(token.FUNC) , := .parseParameters(true) if != nil { .error(.Pos(), "function type must have no type parameters") } := .parseResult() return &ast.FuncType{Func: , Params: , Results: } } func ( *parser) () *ast.Field { if .trace { defer un(trace(, "MethodSpec")) } := .leadComment var []*ast.Ident var ast.Expr := .parseTypeName(nil) if , := .(*ast.Ident); != nil { switch { case .tok == token.LBRACK: // generic method or embedded instantiated type := .pos .next() .exprLev++ := .parseExpr() .exprLev-- if , := .(*ast.Ident); != nil && .tok != token.COMMA && .tok != token.RBRACK { // generic method m[T any] // // Interface methods do not have type parameters. We parse them for a // better error message and improved error recovery. _ = .parseParameterList(, nil, token.RBRACK) _ = .expect(token.RBRACK) .error(, "interface method must have no type parameters") // TODO(rfindley) refactor to share code with parseFuncType. , := .parseParameters(false) := .parseResult() = []*ast.Ident{} = &ast.FuncType{ Func: token.NoPos, Params: , Results: , } } else { // embedded instantiated type // TODO(rfindley) should resolve all identifiers in x. := []ast.Expr{} if .atComma("type argument list", token.RBRACK) { .exprLev++ .next() for .tok != token.RBRACK && .tok != token.EOF { = append(, .parseType()) if !.atComma("type argument list", token.RBRACK) { break } .next() } .exprLev-- } := .expectClosing(token.RBRACK, "type argument list") = typeparams.PackIndexExpr(, , , ) } case .tok == token.LPAREN: // ordinary method // TODO(rfindley) refactor to share code with parseFuncType. , := .parseParameters(false) := .parseResult() = []*ast.Ident{} = &ast.FuncType{Func: token.NoPos, Params: , Results: } default: // embedded type = } } else { // embedded, possibly instantiated type = if .tok == token.LBRACK { // embedded instantiated interface = .parseTypeInstance() } } // Comment is added at the callsite: the field below may joined with // additional type specs using '|'. // TODO(rfindley) this should be refactored. // TODO(rfindley) add more tests for comment handling. return &ast.Field{Doc: , Names: , Type: } } func ( *parser) ( ast.Expr) ast.Expr { if .trace { defer un(trace(, "EmbeddedElem")) } if == nil { = .embeddedTerm() } for .tok == token.OR { := new(ast.BinaryExpr) .OpPos = .pos .Op = token.OR .next() .X = .Y = .embeddedTerm() = } return } func ( *parser) () ast.Expr { if .trace { defer un(trace(, "EmbeddedTerm")) } if .tok == token.TILDE { := new(ast.UnaryExpr) .OpPos = .pos .Op = token.TILDE .next() .X = .parseType() return } := .tryIdentOrType() if == nil { := .pos .errorExpected(, "~ term or type") .advance(exprEnd) return &ast.BadExpr{From: , To: .pos} } return } func ( *parser) () *ast.InterfaceType { if .trace { defer un(trace(, "InterfaceType")) } := .expect(token.INTERFACE) := .expect(token.LBRACE) var []*ast.Field : for { switch { case .tok == token.IDENT: := .parseMethodSpec() if .Names == nil { .Type = .embeddedElem(.Type) } .Comment = .expectSemi() = append(, ) case .tok == token.TILDE: := .embeddedElem(nil) := .expectSemi() = append(, &ast.Field{Type: , Comment: }) default: if := .tryIdentOrType(); != nil { := .embeddedElem() := .expectSemi() = append(, &ast.Field{Type: , Comment: }) } else { break } } } // TODO(rfindley): the error produced here could be improved, since we could // accept an identifier, 'type', or a '}' at this point. := .expect(token.RBRACE) return &ast.InterfaceType{ Interface: , Methods: &ast.FieldList{ Opening: , List: , Closing: , }, } } func ( *parser) () *ast.MapType { if .trace { defer un(trace(, "MapType")) } := .expect(token.MAP) .expect(token.LBRACK) := .parseType() .expect(token.RBRACK) := .parseType() return &ast.MapType{Map: , Key: , Value: } } func ( *parser) () *ast.ChanType { if .trace { defer un(trace(, "ChanType")) } := .pos := ast.SEND | ast.RECV var token.Pos if .tok == token.CHAN { .next() if .tok == token.ARROW { = .pos .next() = ast.SEND } } else { = .expect(token.ARROW) .expect(token.CHAN) = ast.RECV } := .parseType() return &ast.ChanType{Begin: , Arrow: , Dir: , Value: } } func ( *parser) ( ast.Expr) ast.Expr { if .trace { defer un(trace(, "TypeInstance")) } := .expect(token.LBRACK) .exprLev++ var []ast.Expr for .tok != token.RBRACK && .tok != token.EOF { = append(, .parseType()) if !.atComma("type argument list", token.RBRACK) { break } .next() } .exprLev-- := .expectClosing(token.RBRACK, "type argument list") if len() == 0 { .errorExpected(, "type argument list") return &ast.IndexExpr{ X: , Lbrack: , Index: &ast.BadExpr{From: + 1, To: }, Rbrack: , } } return typeparams.PackIndexExpr(, , , ) } func ( *parser) () ast.Expr { defer decNestLev(incNestLev()) switch .tok { case token.IDENT: := .parseTypeName(nil) if .tok == token.LBRACK { = .parseTypeInstance() } return case token.LBRACK: := .expect(token.LBRACK) return .parseArrayType(, nil) case token.STRUCT: return .parseStructType() case token.MUL: return .parsePointerType() case token.FUNC: return .parseFuncType() case token.INTERFACE: return .parseInterfaceType() case token.MAP: return .parseMapType() case token.CHAN, token.ARROW: return .parseChanType() case token.LPAREN: := .pos .next() := .parseType() := .expect(token.RPAREN) return &ast.ParenExpr{Lparen: , X: , Rparen: } } // no type found return nil } // ---------------------------------------------------------------------------- // Blocks func ( *parser) () ( []ast.Stmt) { if .trace { defer un(trace(, "StatementList")) } for .tok != token.CASE && .tok != token.DEFAULT && .tok != token.RBRACE && .tok != token.EOF { = append(, .parseStmt()) } return } func ( *parser) () *ast.BlockStmt { if .trace { defer un(trace(, "Body")) } := .expect(token.LBRACE) := .parseStmtList() := .expect2(token.RBRACE) return &ast.BlockStmt{Lbrace: , List: , Rbrace: } } func ( *parser) () *ast.BlockStmt { if .trace { defer un(trace(, "BlockStmt")) } := .expect(token.LBRACE) := .parseStmtList() := .expect2(token.RBRACE) return &ast.BlockStmt{Lbrace: , List: , Rbrace: } } // ---------------------------------------------------------------------------- // Expressions func ( *parser) () ast.Expr { if .trace { defer un(trace(, "FuncTypeOrLit")) } := .parseFuncType() if .tok != token.LBRACE { // function type only return } .exprLev++ := .parseBody() .exprLev-- return &ast.FuncLit{Type: , Body: } } // parseOperand may return an expression or a raw type (incl. array // types of the form [...]T). Callers must verify the result. func ( *parser) () ast.Expr { if .trace { defer un(trace(, "Operand")) } switch .tok { case token.IDENT: := .parseIdent() return case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING: := &ast.BasicLit{ValuePos: .pos, Kind: .tok, Value: .lit} .next() return case token.LPAREN: := .pos .next() .exprLev++ := .parseRhs() // types may be parenthesized: (some type) .exprLev-- := .expect(token.RPAREN) return &ast.ParenExpr{Lparen: , X: , Rparen: } case token.FUNC: return .parseFuncTypeOrLit() } if := .tryIdentOrType(); != nil { // do not consume trailing type parameters // could be type for composite literal or conversion , := .(*ast.Ident) assert(!, "type cannot be identifier") return } // we have an error := .pos .errorExpected(, "operand") .advance(stmtStart) return &ast.BadExpr{From: , To: .pos} } func ( *parser) ( ast.Expr) ast.Expr { if .trace { defer un(trace(, "Selector")) } := .parseIdent() return &ast.SelectorExpr{X: , Sel: } } func ( *parser) ( ast.Expr) ast.Expr { if .trace { defer un(trace(, "TypeAssertion")) } := .expect(token.LPAREN) var ast.Expr if .tok == token.TYPE { // type switch: typ == nil .next() } else { = .parseType() } := .expect(token.RPAREN) return &ast.TypeAssertExpr{X: , Type: , Lparen: , Rparen: } } func ( *parser) ( ast.Expr) ast.Expr { if .trace { defer un(trace(, "parseIndexOrSliceOrInstance")) } := .expect(token.LBRACK) if .tok == token.RBRACK { // empty index, slice or index expressions are not permitted; // accept them for parsing tolerance, but complain .errorExpected(.pos, "operand") := .pos .next() return &ast.IndexExpr{ X: , Lbrack: , Index: &ast.BadExpr{From: , To: }, Rbrack: , } } .exprLev++ const = 3 // change the 3 to 2 to disable 3-index slices var []ast.Expr var []ast.Expr var [ - 1]token.Pos if .tok != token.COLON { // We can't know if we have an index expression or a type instantiation; // so even if we see a (named) type we are not going to be in type context. [0] = .parseRhs() } := 0 switch .tok { case token.COLON: // slice expression for .tok == token.COLON && < len() { [] = .pos ++ .next() if .tok != token.COLON && .tok != token.RBRACK && .tok != token.EOF { [] = .parseRhs() } } case token.COMMA: // instance expression = append(, [0]) for .tok == token.COMMA { .next() if .tok != token.RBRACK && .tok != token.EOF { = append(, .parseType()) } } } .exprLev-- := .expect(token.RBRACK) if > 0 { // slice expression := false if == 2 { = true // Check presence of middle and final index here rather than during type-checking // to prevent erroneous programs from passing through gofmt (was go.dev/issue/7305). if [1] == nil { .error([0], "middle index required in 3-index slice") [1] = &ast.BadExpr{From: [0] + 1, To: [1]} } if [2] == nil { .error([1], "final index required in 3-index slice") [2] = &ast.BadExpr{From: [1] + 1, To: } } } return &ast.SliceExpr{X: , Lbrack: , Low: [0], High: [1], Max: [2], Slice3: , Rbrack: } } if len() == 0 { // index expression return &ast.IndexExpr{X: , Lbrack: , Index: [0], Rbrack: } } // instance expression return typeparams.PackIndexExpr(, , , ) } func ( *parser) ( ast.Expr) *ast.CallExpr { if .trace { defer un(trace(, "CallOrConversion")) } := .expect(token.LPAREN) .exprLev++ var []ast.Expr var token.Pos for .tok != token.RPAREN && .tok != token.EOF && !.IsValid() { = append(, .parseRhs()) // builtins may expect a type: make(some type, ...) if .tok == token.ELLIPSIS { = .pos .next() } if !.atComma("argument list", token.RPAREN) { break } .next() } .exprLev-- := .expectClosing(token.RPAREN, "argument list") return &ast.CallExpr{Fun: , Lparen: , Args: , Ellipsis: , Rparen: } } func ( *parser) () ast.Expr { if .trace { defer un(trace(, "Element")) } if .tok == token.LBRACE { return .parseLiteralValue(nil) } := .parseExpr() return } func ( *parser) () ast.Expr { if .trace { defer un(trace(, "Element")) } := .parseValue() if .tok == token.COLON { := .pos .next() = &ast.KeyValueExpr{Key: , Colon: , Value: .parseValue()} } return } func ( *parser) () ( []ast.Expr) { if .trace { defer un(trace(, "ElementList")) } for .tok != token.RBRACE && .tok != token.EOF { = append(, .parseElement()) if !.atComma("composite literal", token.RBRACE) { break } .next() } return } func ( *parser) ( ast.Expr) ast.Expr { if .trace { defer un(trace(, "LiteralValue")) } := .expect(token.LBRACE) var []ast.Expr .exprLev++ if .tok != token.RBRACE { = .parseElementList() } .exprLev-- := .expectClosing(token.RBRACE, "composite literal") return &ast.CompositeLit{Type: , Lbrace: , Elts: , Rbrace: } } func ( *parser) ( ast.Expr) ast.Expr { if .trace { defer un(trace(, "PrimaryExpr")) } if == nil { = .parseOperand() } // We track the nesting here rather than at the entry for the function, // since it can iteratively produce a nested output, and we want to // limit how deep a structure we generate. var int defer func() { .nestLev -= }() for = 1; ; ++ { incNestLev() switch .tok { case token.PERIOD: .next() switch .tok { case token.IDENT: = .parseSelector() case token.LPAREN: = .parseTypeAssertion() default: := .pos .errorExpected(, "selector or type assertion") // TODO(rFindley) The check for token.RBRACE below is a targeted fix // to error recovery sufficient to make the x/tools tests to // pass with the new parsing logic introduced for type // parameters. Remove this once error recovery has been // more generally reconsidered. if .tok != token.RBRACE { .next() // make progress } := &ast.Ident{NamePos: , Name: "_"} = &ast.SelectorExpr{X: , Sel: } } case token.LBRACK: = .parseIndexOrSliceOrInstance() case token.LPAREN: = .parseCallOrConversion() case token.LBRACE: // operand may have returned a parenthesized complit // type; accept it but complain if we have a complit := ast.Unparen() // determine if '{' belongs to a composite literal or a block statement switch .(type) { case *ast.BadExpr, *ast.Ident, *ast.SelectorExpr: if .exprLev < 0 { return } // x is possibly a composite literal type case *ast.IndexExpr, *ast.IndexListExpr: if .exprLev < 0 { return } // x is possibly a composite literal type case *ast.ArrayType, *ast.StructType, *ast.MapType: // x is a composite literal type default: return } if != { .error(.Pos(), "cannot parenthesize type in composite literal") // already progressed, no need to advance } = .parseLiteralValue() default: return } } } func ( *parser) () ast.Expr { defer decNestLev(incNestLev()) if .trace { defer un(trace(, "UnaryExpr")) } switch .tok { case token.ADD, token.SUB, token.NOT, token.XOR, token.AND, token.TILDE: , := .pos, .tok .next() := .() return &ast.UnaryExpr{OpPos: , Op: , X: } case token.ARROW: // channel type or receive expression := .pos .next() // If the next token is token.CHAN we still don't know if it // is a channel type or a receive operation - we only know // once we have found the end of the unary expression. There // are two cases: // // <- type => (<-type) must be channel type // <- expr => <-(expr) is a receive from an expression // // In the first case, the arrow must be re-associated with // the channel type parsed already: // // <- (chan type) => (<-chan type) // <- (chan<- type) => (<-chan (<-type)) := .() // determine which case we have if , := .(*ast.ChanType); { // (<-type) // re-associate position info and <- := ast.SEND for && == ast.SEND { if .Dir == ast.RECV { // error: (<-type) is (<-(<-chan T)) .errorExpected(.Arrow, "'chan'") } , .Begin, .Arrow = .Arrow, , , .Dir = .Dir, ast.RECV , = .Value.(*ast.ChanType) } if == ast.SEND { .errorExpected(, "channel type") } return } // <-(expr) return &ast.UnaryExpr{OpPos: , Op: token.ARROW, X: } case token.MUL: // pointer type or unary "*" expression := .pos .next() := .() return &ast.StarExpr{Star: , X: } } return .parsePrimaryExpr(nil) } func ( *parser) () (token.Token, int) { := .tok if .inRhs && == token.ASSIGN { = token.EQL } return , .Precedence() } // parseBinaryExpr parses a (possibly) binary expression. // If x is non-nil, it is used as the left operand. // // TODO(rfindley): parseBinaryExpr has become overloaded. Consider refactoring. func ( *parser) ( ast.Expr, int) ast.Expr { if .trace { defer un(trace(, "BinaryExpr")) } if == nil { = .parseUnaryExpr() } // We track the nesting here rather than at the entry for the function, // since it can iteratively produce a nested output, and we want to // limit how deep a structure we generate. var int defer func() { .nestLev -= }() for = 1; ; ++ { incNestLev() , := .tokPrec() if < { return } := .expect() := .(nil, +1) = &ast.BinaryExpr{X: , OpPos: , Op: , Y: } } } // The result may be a type or even a raw type ([...]int). func ( *parser) () ast.Expr { if .trace { defer un(trace(, "Expression")) } return .parseBinaryExpr(nil, token.LowestPrec+1) } func ( *parser) () ast.Expr { := .inRhs .inRhs = true := .parseExpr() .inRhs = return } // ---------------------------------------------------------------------------- // Statements // Parsing modes for parseSimpleStmt. const ( basic = iota labelOk rangeOk ) // parseSimpleStmt returns true as 2nd result if it parsed the assignment // of a range clause (with mode == rangeOk). The returned statement is an // assignment with a right-hand side that is a single unary expression of // the form "range x". No guarantees are given for the left-hand side. func ( *parser) ( int) (ast.Stmt, bool) { if .trace { defer un(trace(, "SimpleStmt")) } := .parseList(false) switch .tok { case token.DEFINE, token.ASSIGN, token.ADD_ASSIGN, token.SUB_ASSIGN, token.MUL_ASSIGN, token.QUO_ASSIGN, token.REM_ASSIGN, token.AND_ASSIGN, token.OR_ASSIGN, token.XOR_ASSIGN, token.SHL_ASSIGN, token.SHR_ASSIGN, token.AND_NOT_ASSIGN: // assignment statement, possibly part of a range clause , := .pos, .tok .next() var []ast.Expr := false if == rangeOk && .tok == token.RANGE && ( == token.DEFINE || == token.ASSIGN) { := .pos .next() = []ast.Expr{&ast.UnaryExpr{OpPos: , Op: token.RANGE, X: .parseRhs()}} = true } else { = .parseList(true) } return &ast.AssignStmt{Lhs: , TokPos: , Tok: , Rhs: }, } if len() > 1 { .errorExpected([0].Pos(), "1 expression") // continue with first expression } switch .tok { case token.COLON: // labeled statement := .pos .next() if , := [0].(*ast.Ident); == labelOk && { // Go spec: The scope of a label is the body of the function // in which it is declared and excludes the body of any nested // function. := &ast.LabeledStmt{Label: , Colon: , Stmt: .parseStmt()} return , false } // The label declaration typically starts at x[0].Pos(), but the label // declaration may be erroneous due to a token after that position (and // before the ':'). If SpuriousErrors is not set, the (only) error // reported for the line is the illegal label error instead of the token // before the ':' that caused the problem. Thus, use the (latest) colon // position for error reporting. .error(, "illegal label declaration") return &ast.BadStmt{From: [0].Pos(), To: + 1}, false case token.ARROW: // send statement := .pos .next() := .parseRhs() return &ast.SendStmt{Chan: [0], Arrow: , Value: }, false case token.INC, token.DEC: // increment or decrement := &ast.IncDecStmt{X: [0], TokPos: .pos, Tok: .tok} .next() return , false } // expression return &ast.ExprStmt{X: [0]}, false } func ( *parser) ( string) *ast.CallExpr { := .parseRhs() // could be a conversion: (some type)(x) if := ast.Unparen(); != { .error(.Pos(), fmt.Sprintf("expression in %s must not be parenthesized", )) = } if , := .(*ast.CallExpr); { return } if , := .(*ast.BadExpr); ! { // only report error if it's a new one .error(.safePos(.End()), fmt.Sprintf("expression in %s must be function call", )) } return nil } func ( *parser) () ast.Stmt { if .trace { defer un(trace(, "GoStmt")) } := .expect(token.GO) := .parseCallExpr("go") .expectSemi() if == nil { return &ast.BadStmt{From: , To: + 2} // len("go") } return &ast.GoStmt{Go: , Call: } } func ( *parser) () ast.Stmt { if .trace { defer un(trace(, "DeferStmt")) } := .expect(token.DEFER) := .parseCallExpr("defer") .expectSemi() if == nil { return &ast.BadStmt{From: , To: + 5} // len("defer") } return &ast.DeferStmt{Defer: , Call: } } func ( *parser) () *ast.ReturnStmt { if .trace { defer un(trace(, "ReturnStmt")) } := .pos .expect(token.RETURN) var []ast.Expr if .tok != token.SEMICOLON && .tok != token.RBRACE { = .parseList(true) } .expectSemi() return &ast.ReturnStmt{Return: , Results: } } func ( *parser) ( token.Token) *ast.BranchStmt { if .trace { defer un(trace(, "BranchStmt")) } := .expect() var *ast.Ident if != token.FALLTHROUGH && .tok == token.IDENT { = .parseIdent() } .expectSemi() return &ast.BranchStmt{TokPos: , Tok: , Label: } } func ( *parser) ( ast.Stmt, string) ast.Expr { if == nil { return nil } if , := .(*ast.ExprStmt); { return .X } := "simple statement" if , := .(*ast.AssignStmt); { = "assignment" } .error(.Pos(), fmt.Sprintf("expected %s, found %s (missing parentheses around composite literal?)", , )) return &ast.BadExpr{From: .Pos(), To: .safePos(.End())} } // parseIfHeader is an adjusted version of parser.header // in cmd/compile/internal/syntax/parser.go, which has // been tuned for better error handling. func ( *parser) () ( ast.Stmt, ast.Expr) { if .tok == token.LBRACE { .error(.pos, "missing condition in if statement") = &ast.BadExpr{From: .pos, To: .pos} return } // p.tok != token.LBRACE := .exprLev .exprLev = -1 if .tok != token.SEMICOLON { // accept potential variable declaration but complain if .tok == token.VAR { .next() .error(.pos, "var declaration not allowed in if initializer") } , _ = .parseSimpleStmt(basic) } var ast.Stmt var struct { token.Pos string // ";" or "\n"; valid if pos.IsValid() } if .tok != token.LBRACE { if .tok == token.SEMICOLON { . = .pos . = .lit .next() } else { .expect(token.SEMICOLON) } if .tok != token.LBRACE { , _ = .parseSimpleStmt(basic) } } else { = = nil } if != nil { = .makeExpr(, "boolean expression") } else if ..IsValid() { if . == "\n" { .error(., "unexpected newline, expecting { after if clause") } else { .error(., "missing condition in if statement") } } // make sure we have a valid AST if == nil { = &ast.BadExpr{From: .pos, To: .pos} } .exprLev = return } func ( *parser) () *ast.IfStmt { defer decNestLev(incNestLev()) if .trace { defer un(trace(, "IfStmt")) } := .expect(token.IF) , := .parseIfHeader() := .parseBlockStmt() var ast.Stmt if .tok == token.ELSE { .next() switch .tok { case token.IF: = .() case token.LBRACE: = .parseBlockStmt() .expectSemi() default: .errorExpected(.pos, "if statement or block") = &ast.BadStmt{From: .pos, To: .pos} } } else { .expectSemi() } return &ast.IfStmt{If: , Init: , Cond: , Body: , Else: } } func ( *parser) () *ast.CaseClause { if .trace { defer un(trace(, "CaseClause")) } := .pos var []ast.Expr if .tok == token.CASE { .next() = .parseList(true) } else { .expect(token.DEFAULT) } := .expect(token.COLON) := .parseStmtList() return &ast.CaseClause{Case: , List: , Colon: , Body: } } func isTypeSwitchAssert( ast.Expr) bool { , := .(*ast.TypeAssertExpr) return && .Type == nil } func ( *parser) ( ast.Stmt) bool { switch t := .(type) { case *ast.ExprStmt: // x.(type) return isTypeSwitchAssert(.X) case *ast.AssignStmt: // v := x.(type) if len(.Lhs) == 1 && len(.Rhs) == 1 && isTypeSwitchAssert(.Rhs[0]) { switch .Tok { case token.ASSIGN: // permit v = x.(type) but complain .error(.TokPos, "expected ':=', found '='") fallthrough case token.DEFINE: return true } } } return false } func ( *parser) () ast.Stmt { if .trace { defer un(trace(, "SwitchStmt")) } := .expect(token.SWITCH) var , ast.Stmt if .tok != token.LBRACE { := .exprLev .exprLev = -1 if .tok != token.SEMICOLON { , _ = .parseSimpleStmt(basic) } if .tok == token.SEMICOLON { .next() = = nil if .tok != token.LBRACE { // A TypeSwitchGuard may declare a variable in addition // to the variable declared in the initial SimpleStmt. // Introduce extra scope to avoid redeclaration errors: // // switch t := 0; t := x.(T) { ... } // // (this code is not valid Go because the first t // cannot be accessed and thus is never used, the extra // scope is needed for the correct error message). // // If we don't have a type switch, s2 must be an expression. // Having the extra nested but empty scope won't affect it. , _ = .parseSimpleStmt(basic) } } .exprLev = } := .isTypeSwitchGuard() := .expect(token.LBRACE) var []ast.Stmt for .tok == token.CASE || .tok == token.DEFAULT { = append(, .parseCaseClause()) } := .expect(token.RBRACE) .expectSemi() := &ast.BlockStmt{Lbrace: , List: , Rbrace: } if { return &ast.TypeSwitchStmt{Switch: , Init: , Assign: , Body: } } return &ast.SwitchStmt{Switch: , Init: , Tag: .makeExpr(, "switch expression"), Body: } } func ( *parser) () *ast.CommClause { if .trace { defer un(trace(, "CommClause")) } := .pos var ast.Stmt if .tok == token.CASE { .next() := .parseList(false) if .tok == token.ARROW { // SendStmt if len() > 1 { .errorExpected([0].Pos(), "1 expression") // continue with first expression } := .pos .next() := .parseRhs() = &ast.SendStmt{Chan: [0], Arrow: , Value: } } else { // RecvStmt if := .tok; == token.ASSIGN || == token.DEFINE { // RecvStmt with assignment if len() > 2 { .errorExpected([0].Pos(), "1 or 2 expressions") // continue with first two expressions = [0:2] } := .pos .next() := .parseRhs() = &ast.AssignStmt{Lhs: , TokPos: , Tok: , Rhs: []ast.Expr{}} } else { // lhs must be single receive operation if len() > 1 { .errorExpected([0].Pos(), "1 expression") // continue with first expression } = &ast.ExprStmt{X: [0]} } } } else { .expect(token.DEFAULT) } := .expect(token.COLON) := .parseStmtList() return &ast.CommClause{Case: , Comm: , Colon: , Body: } } func ( *parser) () *ast.SelectStmt { if .trace { defer un(trace(, "SelectStmt")) } := .expect(token.SELECT) := .expect(token.LBRACE) var []ast.Stmt for .tok == token.CASE || .tok == token.DEFAULT { = append(, .parseCommClause()) } := .expect(token.RBRACE) .expectSemi() := &ast.BlockStmt{Lbrace: , List: , Rbrace: } return &ast.SelectStmt{Select: , Body: } } func ( *parser) () ast.Stmt { if .trace { defer un(trace(, "ForStmt")) } := .expect(token.FOR) var , , ast.Stmt var bool if .tok != token.LBRACE { := .exprLev .exprLev = -1 if .tok != token.SEMICOLON { if .tok == token.RANGE { // "for range x" (nil lhs in assignment) := .pos .next() := []ast.Expr{&ast.UnaryExpr{OpPos: , Op: token.RANGE, X: .parseRhs()}} = &ast.AssignStmt{Rhs: } = true } else { , = .parseSimpleStmt(rangeOk) } } if ! && .tok == token.SEMICOLON { .next() = = nil if .tok != token.SEMICOLON { , _ = .parseSimpleStmt(basic) } .expectSemi() if .tok != token.LBRACE { , _ = .parseSimpleStmt(basic) } } .exprLev = } := .parseBlockStmt() .expectSemi() if { := .(*ast.AssignStmt) // check lhs var , ast.Expr switch len(.Lhs) { case 0: // nothing to do case 1: = .Lhs[0] case 2: , = .Lhs[0], .Lhs[1] default: .errorExpected(.Lhs[len(.Lhs)-1].Pos(), "at most 2 expressions") return &ast.BadStmt{From: , To: .safePos(.End())} } // parseSimpleStmt returned a right-hand side that // is a single unary expression of the form "range x" := .Rhs[0].(*ast.UnaryExpr).X return &ast.RangeStmt{ For: , Key: , Value: , TokPos: .TokPos, Tok: .Tok, Range: .Rhs[0].Pos(), X: , Body: , } } // regular for statement return &ast.ForStmt{ For: , Init: , Cond: .makeExpr(, "boolean or range expression"), Post: , Body: , } } func ( *parser) () ( ast.Stmt) { defer decNestLev(incNestLev()) if .trace { defer un(trace(, "Statement")) } switch .tok { case token.CONST, token.TYPE, token.VAR: = &ast.DeclStmt{Decl: .parseDecl(stmtStart)} case // tokens that may start an expression token.IDENT, token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operands token.LBRACK, token.STRUCT, token.MAP, token.CHAN, token.INTERFACE, // composite types token.ADD, token.SUB, token.MUL, token.AND, token.XOR, token.ARROW, token.NOT: // unary operators , _ = .parseSimpleStmt(labelOk) // because of the required look-ahead, labeled statements are // parsed by parseSimpleStmt - don't expect a semicolon after // them if , := .(*ast.LabeledStmt); ! { .expectSemi() } case token.GO: = .parseGoStmt() case token.DEFER: = .parseDeferStmt() case token.RETURN: = .parseReturnStmt() case token.BREAK, token.CONTINUE, token.GOTO, token.FALLTHROUGH: = .parseBranchStmt(.tok) case token.LBRACE: = .parseBlockStmt() .expectSemi() case token.IF: = .parseIfStmt() case token.SWITCH: = .parseSwitchStmt() case token.SELECT: = .parseSelectStmt() case token.FOR: = .parseForStmt() case token.SEMICOLON: // Is it ever possible to have an implicit semicolon // producing an empty statement in a valid program? // (handle correctly anyway) = &ast.EmptyStmt{Semicolon: .pos, Implicit: .lit == "\n"} .next() case token.RBRACE: // a semicolon may be omitted before a closing "}" = &ast.EmptyStmt{Semicolon: .pos, Implicit: true} default: // no statement found := .pos .errorExpected(, "statement") .advance(stmtStart) = &ast.BadStmt{From: , To: .pos} } return } // ---------------------------------------------------------------------------- // Declarations type parseSpecFunction func(doc *ast.CommentGroup, keyword token.Token, iota int) ast.Spec func ( *parser) ( *ast.CommentGroup, token.Token, int) ast.Spec { if .trace { defer un(trace(, "ImportSpec")) } var *ast.Ident switch .tok { case token.IDENT: = .parseIdent() case token.PERIOD: = &ast.Ident{NamePos: .pos, Name: "."} .next() } := .pos var string if .tok == token.STRING { = .lit .next() } else if .tok.IsLiteral() { .error(, "import path must be a string") .next() } else { .error(, "missing import path") .advance(exprEnd) } := .expectSemi() // collect imports := &ast.ImportSpec{ Doc: , Name: , Path: &ast.BasicLit{ValuePos: , Kind: token.STRING, Value: }, Comment: , } .imports = append(.imports, ) return } func ( *parser) ( *ast.CommentGroup, token.Token, int) ast.Spec { if .trace { defer un(trace(, .String()+"Spec")) } := .parseIdentList() var ast.Expr var []ast.Expr switch { case token.CONST: // always permit optional type and initialization for more tolerant parsing if .tok != token.EOF && .tok != token.SEMICOLON && .tok != token.RPAREN { = .tryIdentOrType() if .tok == token.ASSIGN { .next() = .parseList(true) } } case token.VAR: if .tok != token.ASSIGN { = .parseType() } if .tok == token.ASSIGN { .next() = .parseList(true) } default: panic("unreachable") } := .expectSemi() := &ast.ValueSpec{ Doc: , Names: , Type: , Values: , Comment: , } return } func ( *parser) ( *ast.TypeSpec, token.Pos, *ast.Ident, ast.Expr) { if .trace { defer un(trace(, "parseGenericType")) } := .parseParameterList(, , token.RBRACK) := .expect(token.RBRACK) .TypeParams = &ast.FieldList{Opening: , List: , Closing: } // Let the type checker decide whether to accept type parameters on aliases: // see go.dev/issue/46477. if .tok == token.ASSIGN { // type alias .Assign = .pos .next() } .Type = .parseType() } func ( *parser) ( *ast.CommentGroup, token.Token, int) ast.Spec { if .trace { defer un(trace(, "TypeSpec")) } := .parseIdent() := &ast.TypeSpec{Doc: , Name: } if .tok == token.LBRACK { // spec.Name "[" ... // array/slice type or type parameter list := .pos .next() if .tok == token.IDENT { // We may have an array type or a type parameter list. // In either case we expect an expression x (which may // just be a name, or a more complex expression) which // we can analyze further. // // A type parameter list may have a type bound starting // with a "[" as in: P []E. In that case, simply parsing // an expression would lead to an error: P[] is invalid. // But since index or slice expressions are never constant // and thus invalid array length expressions, if the name // is followed by "[" it must be the start of an array or // slice constraint. Only if we don't see a "[" do we // need to parse a full expression. Notably, name <- x // is not a concern because name <- x is a statement and // not an expression. var ast.Expr = .parseIdent() if .tok != token.LBRACK { // To parse the expression starting with name, expand // the call sequence we would get by passing in name // to parser.expr, and pass in name to parsePrimaryExpr. .exprLev++ := .parsePrimaryExpr() = .parseBinaryExpr(, token.LowestPrec+1) .exprLev-- } // Analyze expression x. If we can split x into a type parameter // name, possibly followed by a type parameter type, we consider // this the start of a type parameter list, with some caveats: // a single name followed by "]" tilts the decision towards an // array declaration; a type parameter type that could also be // an ordinary expression but which is followed by a comma tilts // the decision towards a type parameter list. if , := extractName(, .tok == token.COMMA); != nil && ( != nil || .tok != token.RBRACK) { // spec.Name "[" pname ... // spec.Name "[" pname ptype ... // spec.Name "[" pname ptype "," ... .parseGenericType(, , , ) // ptype may be nil } else { // spec.Name "[" pname "]" ... // spec.Name "[" x ... .Type = .parseArrayType(, ) } } else { // array type .Type = .parseArrayType(, nil) } } else { // no type parameters if .tok == token.ASSIGN { // type alias .Assign = .pos .next() } .Type = .parseType() } .Comment = .expectSemi() return } // extractName splits the expression x into (name, expr) if syntactically // x can be written as name expr. The split only happens if expr is a type // element (per the isTypeElem predicate) or if force is set. // If x is just a name, the result is (name, nil). If the split succeeds, // the result is (name, expr). Otherwise the result is (nil, x). // Examples: // // x force name expr // ------------------------------------ // P*[]int T/F P *[]int // P*E T P *E // P*E F nil P*E // P([]int) T/F P []int // P(E) T P E // P(E) F nil P(E) // P*E|F|~G T/F P *E|F|~G // P*E|F|G T P *E|F|G // P*E|F|G F nil P*E|F|G func extractName( ast.Expr, bool) (*ast.Ident, ast.Expr) { switch x := .(type) { case *ast.Ident: return , nil case *ast.BinaryExpr: switch .Op { case token.MUL: if , := .X.(*ast.Ident); != nil && ( || isTypeElem(.Y)) { // x = name *x.Y return , &ast.StarExpr{Star: .OpPos, X: .Y} } case token.OR: if , := (.X, || isTypeElem(.Y)); != nil && != nil { // x = name lhs|x.Y := * .X = return , & } } case *ast.CallExpr: if , := .Fun.(*ast.Ident); != nil { if len(.Args) == 1 && .Ellipsis == token.NoPos && ( || isTypeElem(.Args[0])) { // x = name "(" x.ArgList[0] ")" return , .Args[0] } } } return nil, } // isTypeElem reports whether x is a (possibly parenthesized) type element expression. // The result is false if x could be a type element OR an ordinary (value) expression. func isTypeElem( ast.Expr) bool { switch x := .(type) { case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType, *ast.MapType, *ast.ChanType: return true case *ast.BinaryExpr: return (.X) || (.Y) case *ast.UnaryExpr: return .Op == token.TILDE case *ast.ParenExpr: return (.X) } return false } func ( *parser) ( token.Token, parseSpecFunction) *ast.GenDecl { if .trace { defer un(trace(, "GenDecl("+.String()+")")) } := .leadComment := .expect() var , token.Pos var []ast.Spec if .tok == token.LPAREN { = .pos .next() for := 0; .tok != token.RPAREN && .tok != token.EOF; ++ { = append(, (.leadComment, , )) } = .expect(token.RPAREN) .expectSemi() } else { = append(, (nil, , 0)) } return &ast.GenDecl{ Doc: , TokPos: , Tok: , Lparen: , Specs: , Rparen: , } } func ( *parser) () *ast.FuncDecl { if .trace { defer un(trace(, "FunctionDecl")) } := .leadComment := .expect(token.FUNC) var *ast.FieldList if .tok == token.LPAREN { _, = .parseParameters(false) } := .parseIdent() , := .parseParameters(true) if != nil && != nil { // Method declarations do not have type parameters. We parse them for a // better error message and improved error recovery. .error(.Opening, "method must have no type parameters") = nil } := .parseResult() var *ast.BlockStmt switch .tok { case token.LBRACE: = .parseBody() .expectSemi() case token.SEMICOLON: .next() if .tok == token.LBRACE { // opening { of function declaration on next line .error(.pos, "unexpected semicolon or newline before {") = .parseBody() .expectSemi() } default: .expectSemi() } := &ast.FuncDecl{ Doc: , Recv: , Name: , Type: &ast.FuncType{ Func: , TypeParams: , Params: , Results: , }, Body: , } return } func ( *parser) ( map[token.Token]bool) ast.Decl { if .trace { defer un(trace(, "Declaration")) } var parseSpecFunction switch .tok { case token.IMPORT: = .parseImportSpec case token.CONST, token.VAR: = .parseValueSpec case token.TYPE: = .parseTypeSpec case token.FUNC: return .parseFuncDecl() default: := .pos .errorExpected(, "declaration") .advance() return &ast.BadDecl{From: , To: .pos} } return .parseGenDecl(.tok, ) } // ---------------------------------------------------------------------------- // Source files func ( *parser) () *ast.File { if .trace { defer un(trace(, "File")) } // Don't bother parsing the rest if we had errors scanning the first token. // Likely not a Go source file at all. if .errors.Len() != 0 { return nil } // package clause := .leadComment := .expect(token.PACKAGE) // Go spec: The package clause is not a declaration; // the package name does not appear in any scope. := .parseIdent() if .Name == "_" && .mode&DeclarationErrors != 0 { .error(.pos, "invalid package name _") } .expectSemi() // Don't bother parsing the rest if we had errors parsing the package clause. // Likely not a Go source file at all. if .errors.Len() != 0 { return nil } var []ast.Decl if .mode&PackageClauseOnly == 0 { // import decls for .tok == token.IMPORT { = append(, .parseGenDecl(token.IMPORT, .parseImportSpec)) } if .mode&ImportsOnly == 0 { // rest of package body := token.IMPORT for .tok != token.EOF { // Continue to accept import declarations for error tolerance, but complain. if .tok == token.IMPORT && != token.IMPORT { .error(.pos, "imports must appear before other declarations") } = .tok = append(, .parseDecl(declStart)) } } } := &ast.File{ Doc: , Package: , Name: , Decls: , FileStart: token.Pos(.file.Base()), FileEnd: token.Pos(.file.Base() + .file.Size()), Imports: .imports, Comments: .comments, GoVersion: .goVersion, } var func(token.Pos, string) if .mode&DeclarationErrors != 0 { = .error } if .mode&SkipObjectResolution == 0 { resolveFile(, .file, ) } return }