// 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 // 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 // Ordinary identifier scopes pkgScope *ast.Scope // pkgScope.Outer == nil topScope *ast.Scope // top-most scope; may be pkgScope unresolved []*ast.Ident // unresolved identifiers imports []*ast.ImportSpec // list of imports // Label scopes // (maintained by open/close LabelScope) labelScope *ast.Scope // label scope for current function targetStack [][]*ast.Ident // stack of unresolved labels } func ( *parser) ( *token.FileSet, string, []byte, Mode) { .file = .AddFile(, -1, len()) var scanner.Mode if &ParseComments != 0 { = scanner.ScanComments } := func( token.Position, string) { .errors.Add(, ) } .scanner.Init(.file, , , ) .mode = .trace = &Trace != 0 // for convenience (p.trace is used frequently) .next() } // ---------------------------------------------------------------------------- // Scoping support func ( *parser) () { .topScope = ast.NewScope(.topScope) } func ( *parser) () { .topScope = .topScope.Outer } func ( *parser) () { .labelScope = ast.NewScope(.labelScope) .targetStack = append(.targetStack, nil) } func ( *parser) () { // resolve labels := len(.targetStack) - 1 := .labelScope for , := range .targetStack[] { .Obj = .Lookup(.Name) if .Obj == nil && .mode&DeclarationErrors != 0 { .error(.Pos(), fmt.Sprintf("label %s undefined", .Name)) } } // pop label scope .targetStack = .targetStack[0:] .labelScope = .labelScope.Outer } func ( *parser) (, interface{}, *ast.Scope, ast.ObjKind, ...*ast.Ident) { for , := range { assert(.Obj == nil, "identifier already declared or resolved") := ast.NewObj(, .Name) // remember the corresponding declaration for redeclaration // errors and global variable resolution/typechecking phase .Decl = .Data = .Obj = if .Name != "_" { if := .Insert(); != nil && .mode&DeclarationErrors != 0 { := "" if := .Pos(); .IsValid() { = fmt.Sprintf("\n\tprevious declaration at %s", .file.Position()) } .error(.Pos(), fmt.Sprintf("%s redeclared in this block%s", .Name, )) } } } } func ( *parser) ( *ast.AssignStmt, []ast.Expr) { // Go spec: A short variable declaration may redeclare variables // provided they were originally declared in the same block with // the same type, and at least one of the non-blank variables is new. := 0 // number of new variables for , := range { if , := .(*ast.Ident); { assert(.Obj == nil, "identifier already declared or resolved") := ast.NewObj(ast.Var, .Name) // remember corresponding assignment for other tools .Decl = .Obj = if .Name != "_" { if := .topScope.Insert(); != nil { .Obj = // redeclaration } else { ++ // new declaration } } } else { .errorExpected(.Pos(), "identifier on left side of :=") } } if == 0 && .mode&DeclarationErrors != 0 { .error([0].Pos(), "no new variables on left side of :=") } } // The unresolved object is a sentinel to mark identifiers that have been added // to the list of unresolved identifiers. The sentinel is only used for verifying // internal consistency. var unresolved = new(ast.Object) // If x is an identifier, tryResolve attempts to resolve x by looking up // the object it denotes. If no object is found and collectUnresolved is // set, x is marked as unresolved and collected in the list of unresolved // identifiers. // func ( *parser) ( ast.Expr, bool) { // nothing to do if x is not an identifier or the blank identifier , := .(*ast.Ident) if == nil { return } assert(.Obj == nil, "identifier already declared or resolved") if .Name == "_" { return } // try to resolve the identifier for := .topScope; != nil; = .Outer { if := .Lookup(.Name); != nil { .Obj = return } } // all local scopes are known, so any unresolved identifier // must be found either in the file scope, package scope // (perhaps in another file), or universe scope --- collect // them so that they can be resolved later if { .Obj = unresolved .unresolved = append(.unresolved, ) } } func ( *parser) ( ast.Expr) { .tryResolve(, true) } // ---------------------------------------------------------------------------- // Parsing support func ( *parser) ( ...interface{}) { 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(")") } // 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() } } .pos, .tok, .lit = .scanner.Scan() } // 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.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. type bailout struct{} func ( *parser) ( token.Pos, string) { := .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() } func ( *parser) () { // 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: .next() default: .errorExpected(.pos, "';'") .advance(stmtStart) } } } 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.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) ( bool) ( []ast.Expr) { if .trace { defer un(trace(, "ExpressionList")) } = append(, .checkExpr(.parseExpr())) for .tok == token.COMMA { .next() = append(, .checkExpr(.parseExpr())) } return } func ( *parser) () []ast.Expr { := .inRhs .inRhs = false := .parseExprList(true) switch .tok { case token.DEFINE: // lhs of a short variable declaration // but doesn't enter scope until later: // caller must call p.shortVarDecl(p.makeIdentList(list)) // at appropriate time. case token.COLON: // lhs of a label declaration or a communication clause of a select // statement (parseLhsList is not called when parsing the case clause // of a switch statement): // - labels are declared by the caller of parseLhsList // - for communication clauses, if there is a stand-alone identifier // followed by a colon, we have a syntax error; there is no need // to resolve the identifier in that case default: // identifiers must be declared elsewhere for , := range { .resolve() } } .inRhs = return } func ( *parser) () []ast.Expr { := .inRhs .inRhs = true := .parseExprList(false) .inRhs = return } // ---------------------------------------------------------------------------- // Types func ( *parser) () ast.Expr { if .trace { defer un(trace(, "Type")) } := .tryType() if == nil { := .pos .errorExpected(, "type") .advance(exprEnd) return &ast.BadExpr{From: , To: .pos} } return } // If the result is an identifier, it is not resolved. func ( *parser) () ast.Expr { if .trace { defer un(trace(, "TypeName")) } := .parseIdent() // don't resolve ident yet - it may be a parameter or field name if .tok == token.PERIOD { // ident is a package name .next() .resolve() := .parseIdent() return &ast.SelectorExpr{X: , Sel: } } return } func ( *parser) () ast.Expr { if .trace { defer un(trace(, "ArrayType")) } := .expect(token.LBRACK) .exprLev++ var ast.Expr // always permit ellipsis for more fault-tolerant parsing if .tok == token.ELLIPSIS { = &ast.Ellipsis{Ellipsis: .pos} .next() } else if .tok != token.RBRACK { = .parseRhs() } .exprLev-- .expect(token.RBRACK) := .parseType() return &ast.ArrayType{Lbrack: , Len: , Elt: } } func ( *parser) ( []ast.Expr) []*ast.Ident { := make([]*ast.Ident, len()) for , := range { , := .(*ast.Ident) if ! { if , := .(*ast.BadExpr); ! { // only report error if it's a new one .errorExpected(.Pos(), "identifier") } = &ast.Ident{NamePos: .Pos(), Name: "_"} } [] = } return } func ( *parser) ( *ast.Scope) *ast.Field { if .trace { defer un(trace(, "FieldDecl")) } := .leadComment // 1st FieldDecl // A type name used as an anonymous field looks like a field identifier. var []ast.Expr for { = append(, .parseVarType(false)) if .tok != token.COMMA { break } .next() } := .tryVarType(false) // analyze case var []*ast.Ident if != nil { // IdentifierList Type = .makeIdentList() } else { // ["*"] TypeName (AnonymousField) = [0] // we always have at least one element if := len(); > 1 { .errorExpected(.pos, "type") = &ast.BadExpr{From: .pos, To: .pos} } else if !isTypeName(deref()) { .errorExpected(.Pos(), "anonymous field") = &ast.BadExpr{From: .Pos(), To: .safePos(.End())} } } // Tag var *ast.BasicLit if .tok == token.STRING { = &ast.BasicLit{ValuePos: .pos, Kind: .tok, Value: .lit} .next() } .expectSemi() // call before accessing p.linecomment := &ast.Field{Doc: , Names: , Type: , Tag: , Comment: .lineComment} .declare(, nil, , ast.Var, ...) .resolve() return } func ( *parser) () *ast.StructType { if .trace { defer un(trace(, "StructType")) } := .expect(token.STRUCT) := .expect(token.LBRACE) := ast.NewScope(nil) // struct scope 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: } } // If the result is an identifier, it is not resolved. func ( *parser) ( bool) ast.Expr { if && .tok == token.ELLIPSIS { := .pos .next() := .tryIdentOrType() // don't use parseType so we can provide better error message if != nil { .resolve() } else { .error(, "'...' parameter is missing type") = &ast.BadExpr{From: , To: .pos} } return &ast.Ellipsis{Ellipsis: , Elt: } } return .tryIdentOrType() } // If the result is an identifier, it is not resolved. func ( *parser) ( bool) ast.Expr { := .tryVarType() if == nil { := .pos .errorExpected(, "type") .next() // make progress = &ast.BadExpr{From: , To: .pos} } return } func ( *parser) ( *ast.Scope, bool) ( []*ast.Field) { if .trace { defer un(trace(, "ParameterList")) } // 1st ParameterDecl // A list of identifiers looks like a list of type names. var []ast.Expr for { = append(, .parseVarType()) if .tok != token.COMMA { break } .next() if .tok == token.RPAREN { break } } // analyze case if := .tryVarType(); != nil { // IdentifierList Type := .makeIdentList() := &ast.Field{Names: , Type: } = append(, ) // Go spec: The scope of an identifier denoting a function // parameter or result variable is the function body. .declare(, nil, , ast.Var, ...) .resolve() if !.atComma("parameter list", token.RPAREN) { return } .next() for .tok != token.RPAREN && .tok != token.EOF { := .parseIdentList() := .parseVarType() := &ast.Field{Names: , Type: } = append(, ) // Go spec: The scope of an identifier denoting a function // parameter or result variable is the function body. .declare(, nil, , ast.Var, ...) .resolve() if !.atComma("parameter list", token.RPAREN) { break } .next() } return } // Type { "," Type } (anonymous parameters) = make([]*ast.Field, len()) for , := range { .resolve() [] = &ast.Field{Type: } } return } func ( *parser) ( *ast.Scope, bool) *ast.FieldList { if .trace { defer un(trace(, "Parameters")) } var []*ast.Field := .expect(token.LPAREN) if .tok != token.RPAREN { = .parseParameterList(, ) } := .expect(token.RPAREN) return &ast.FieldList{Opening: , List: , Closing: } } func ( *parser) ( *ast.Scope) *ast.FieldList { if .trace { defer un(trace(, "Result")) } if .tok == token.LPAREN { return .parseParameters(, false) } := .tryType() if != nil { := make([]*ast.Field, 1) [0] = &ast.Field{Type: } return &ast.FieldList{List: } } return nil } func ( *parser) ( *ast.Scope) (, *ast.FieldList) { if .trace { defer un(trace(, "Signature")) } = .parseParameters(, true) = .parseResult() return } func ( *parser) () (*ast.FuncType, *ast.Scope) { if .trace { defer un(trace(, "FuncType")) } := .expect(token.FUNC) := ast.NewScope(.topScope) // function scope , := .parseSignature() return &ast.FuncType{Func: , Params: , Results: }, } func ( *parser) ( *ast.Scope) *ast.Field { if .trace { defer un(trace(, "MethodSpec")) } := .leadComment var []*ast.Ident var ast.Expr := .parseTypeName() if , := .(*ast.Ident); && .tok == token.LPAREN { // method = []*ast.Ident{} := ast.NewScope(nil) // method scope , := .parseSignature() = &ast.FuncType{Func: token.NoPos, Params: , Results: } } else { // embedded interface = .resolve() } .expectSemi() // call before accessing p.linecomment := &ast.Field{Doc: , Names: , Type: , Comment: .lineComment} .declare(, nil, , ast.Fun, ...) return } func ( *parser) () *ast.InterfaceType { if .trace { defer un(trace(, "InterfaceType")) } := .expect(token.INTERFACE) := .expect(token.LBRACE) := ast.NewScope(nil) // interface scope var []*ast.Field for .tok == token.IDENT { = append(, .parseMethodSpec()) } := .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: } } // If the result is an identifier, it is not resolved. func ( *parser) () ast.Expr { switch .tok { case token.IDENT: return .parseTypeName() case token.LBRACK: return .parseArrayType() case token.STRUCT: return .parseStructType() case token.MUL: return .parsePointerType() case token.FUNC: , := .parseFuncType() return 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 } func ( *parser) () ast.Expr { := .tryIdentOrType() if != nil { .resolve() } return } // ---------------------------------------------------------------------------- // 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.Scope) *ast.BlockStmt { if .trace { defer un(trace(, "Body")) } := .expect(token.LBRACE) .topScope = // open function scope .openLabelScope() := .parseStmtList() .closeLabelScope() .closeScope() := .expect2(token.RBRACE) return &ast.BlockStmt{Lbrace: , List: , Rbrace: } } func ( *parser) () *ast.BlockStmt { if .trace { defer un(trace(, "BlockStmt")) } := .expect(token.LBRACE) .openScope() := .parseStmtList() .closeScope() := .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. // If lhs is set and the result is an identifier, it is not resolved. // func ( *parser) ( bool) ast.Expr { if .trace { defer un(trace(, "Operand")) } switch .tok { case token.IDENT: := .parseIdent() if ! { .resolve() } 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++ := .parseRhsOrType() // types may be parenthesized: (some type) .exprLev-- := .expect(token.RPAREN) return &ast.ParenExpr{Lparen: , X: , Rparen: } case token.FUNC: return .parseFuncTypeOrLit() } if := .tryIdentOrType(); != nil { // 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(, "IndexOrSlice")) } const = 3 // change the 3 to 2 to disable 3-index slices := .expect(token.LBRACK) .exprLev++ var []ast.Expr var [ - 1]token.Pos if .tok != token.COLON { [0] = .parseRhs() } := 0 for .tok == token.COLON && < len() { [] = .pos ++ .next() if .tok != token.COLON && .tok != token.RBRACK && .tok != token.EOF { [] = .parseRhs() } } .exprLev-- := .expect(token.RBRACK) if > 0 { // slice expression := false if == 2 { = true // Check presence of 2nd and 3rd index here rather than during type-checking // to prevent erroneous programs from passing through gofmt (was issue 7305). if [1] == nil { .error([0], "2nd index required in 3-index slice") [1] = &ast.BadExpr{From: [0] + 1, To: [1]} } if [2] == nil { .error([1], "3rd 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: } } return &ast.IndexExpr{X: , Lbrack: , Index: [0], Rbrack: } } 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(, .parseRhsOrType()) // 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) ( bool) ast.Expr { if .trace { defer un(trace(, "Element")) } if .tok == token.LBRACE { return .parseLiteralValue(nil) } // Because the parser doesn't know the composite literal type, it cannot // know if a key that's an identifier is a struct field name or a name // denoting a value. The former is not resolved by the parser or the // resolver. // // Instead, _try_ to resolve such a key if possible. If it resolves, // it a) has correctly resolved, or b) incorrectly resolved because // the key is a struct field with a name matching another identifier. // In the former case we are done, and in the latter case we don't // care because the type checker will do a separate field lookup. // // If the key does not resolve, it a) must be defined at the top // level in another file of the same package, the universe scope, or be // undeclared; or b) it is a struct field. In the former case, the type // checker can do a top-level lookup, and in the latter case it will do // a separate field lookup. := .checkExpr(.parseExpr()) if { if .tok == token.COLON { // Try to resolve the key but don't collect it // as unresolved identifier if it fails so that // we don't get (possibly false) errors about // undeclared names. .tryResolve(, false) } else { // not a key .resolve() } } return } func ( *parser) () ast.Expr { if .trace { defer un(trace(, "Element")) } := .parseValue(true) if .tok == token.COLON { := .pos .next() = &ast.KeyValueExpr{Key: , Colon: , Value: .parseValue(false)} } 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: } } // checkExpr checks that x is an expression (and not a type). func ( *parser) ( ast.Expr) ast.Expr { switch unparen().(type) { case *ast.BadExpr: case *ast.Ident: case *ast.BasicLit: case *ast.FuncLit: case *ast.CompositeLit: case *ast.ParenExpr: panic("unreachable") case *ast.SelectorExpr: case *ast.IndexExpr: case *ast.SliceExpr: case *ast.TypeAssertExpr: // If t.Type == nil we have a type assertion of the form // y.(type), which is only allowed in type switch expressions. // It's hard to exclude those but for the case where we are in // a type switch. Instead be lenient and test this in the type // checker. case *ast.CallExpr: case *ast.StarExpr: case *ast.UnaryExpr: case *ast.BinaryExpr: default: // all other nodes are not proper expressions .errorExpected(.Pos(), "expression") = &ast.BadExpr{From: .Pos(), To: .safePos(.End())} } return } // isTypeName reports whether x is a (qualified) TypeName. func isTypeName( ast.Expr) bool { switch t := .(type) { case *ast.BadExpr: case *ast.Ident: case *ast.SelectorExpr: , := .X.(*ast.Ident) return default: return false // all other nodes are not type names } return true } // isLiteralType reports whether x is a legal composite literal type. func isLiteralType( ast.Expr) bool { switch t := .(type) { case *ast.BadExpr: case *ast.Ident: case *ast.SelectorExpr: , := .X.(*ast.Ident) return case *ast.ArrayType: case *ast.StructType: case *ast.MapType: default: return false // all other nodes are not legal composite literal types } return true } // If x is of the form *T, deref returns T, otherwise it returns x. func deref( ast.Expr) ast.Expr { if , := .(*ast.StarExpr); { = .X } return } // If x is of the form (T), unparen returns unparen(T), otherwise it returns x. func unparen( ast.Expr) ast.Expr { if , := .(*ast.ParenExpr); { = (.X) } return } // checkExprOrType checks that x is an expression or a type // (and not a raw type such as [...]T). // func ( *parser) ( ast.Expr) ast.Expr { switch t := unparen().(type) { case *ast.ParenExpr: panic("unreachable") case *ast.ArrayType: if , := .Len.(*ast.Ellipsis); { .error(.Pos(), "expected array length, found '...'") = &ast.BadExpr{From: .Pos(), To: .safePos(.End())} } } // all other nodes are expressions or types return } // If lhs is set and the result is an identifier, it is not resolved. func ( *parser) ( bool) ast.Expr { if .trace { defer un(trace(, "PrimaryExpr")) } := .parseOperand() : for { switch .tok { case token.PERIOD: .next() if { .resolve() } switch .tok { case token.IDENT: = .parseSelector(.checkExprOrType()) case token.LPAREN: = .parseTypeAssertion(.checkExpr()) default: := .pos .errorExpected(, "selector or type assertion") .next() // make progress := &ast.Ident{NamePos: , Name: "_"} = &ast.SelectorExpr{X: , Sel: } } case token.LBRACK: if { .resolve() } = .parseIndexOrSlice(.checkExpr()) case token.LPAREN: if { .resolve() } = .parseCallOrConversion(.checkExprOrType()) case token.LBRACE: if isLiteralType() && (.exprLev >= 0 || !isTypeName()) { if { .resolve() } = .parseLiteralValue() } else { break } default: break } = false // no need to try to resolve again } return } // If lhs is set and the result is an identifier, it is not resolved. func ( *parser) ( bool) ast.Expr { if .trace { defer un(trace(, "UnaryExpr")) } switch .tok { case token.ADD, token.SUB, token.NOT, token.XOR, token.AND: , := .pos, .tok .next() := .(false) return &ast.UnaryExpr{OpPos: , Op: , X: .checkExpr()} 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)) := .(false) // 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: .checkExpr()} case token.MUL: // pointer type or unary "*" expression := .pos .next() := .(false) return &ast.StarExpr{Star: , X: .checkExprOrType()} } return .parsePrimaryExpr() } func ( *parser) () (token.Token, int) { := .tok if .inRhs && == token.ASSIGN { = token.EQL } return , .Precedence() } // If lhs is set and the result is an identifier, it is not resolved. func ( *parser) ( bool, int) ast.Expr { if .trace { defer un(trace(, "BinaryExpr")) } := .parseUnaryExpr() for { , := .tokPrec() if < { return } := .expect() if { .resolve() = false } := .(false, +1) = &ast.BinaryExpr{X: .checkExpr(), OpPos: , Op: , Y: .checkExpr()} } } // If lhs is set and the result is an identifier, it is not resolved. // The result may be a type or even a raw type ([...]int). Callers must // check the result (using checkExpr or checkExprOrType), depending on // context. func ( *parser) ( bool) ast.Expr { if .trace { defer un(trace(, "Expression")) } return .parseBinaryExpr(, token.LowestPrec+1) } func ( *parser) () ast.Expr { := .inRhs .inRhs = true := .checkExpr(.parseExpr(false)) .inRhs = return } func ( *parser) () ast.Expr { := .inRhs .inRhs = true := .checkExprOrType(.parseExpr(false)) .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")) } := .parseLhsList() 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 { = .parseRhsList() } := &ast.AssignStmt{Lhs: , TokPos: , Tok: , Rhs: } if == token.DEFINE { .shortVarDecl(, ) } return , } 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()} .declare(, nil, .labelScope, ast.Lbl, ) 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 { := .parseRhsOrType() // could be a conversion: (some type)(x) if , := .(*ast.CallExpr); { return } if , := .(*ast.BadExpr); ! { // only report error if it's a new one .error(.safePos(.End()), fmt.Sprintf("function must be invoked in %s statement", )) } 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 { = .parseRhsList() } .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() // add to list of unresolved targets := len(.targetStack) - 1 .targetStack[] = append(.targetStack[], ) } .expectSemi() return &ast.BranchStmt{TokPos: , Tok: , Label: } } func ( *parser) ( ast.Stmt, string) ast.Expr { if == nil { return nil } if , := .(*ast.ExprStmt); { return .checkExpr(.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, fmt.Sprintf("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 { if .trace { defer un(trace(, "IfStmt")) } := .expect(token.IF) .openScope() defer .closeScope() , := .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.Expr) { if .trace { defer un(trace(, "TypeList")) } = append(, .parseType()) for .tok == token.COMMA { .next() = append(, .parseType()) } return } func ( *parser) ( bool) *ast.CaseClause { if .trace { defer un(trace(, "CaseClause")) } := .pos var []ast.Expr if .tok == token.CASE { .next() if { = .parseTypeList() } else { = .parseRhsList() } } else { .expect(token.DEFAULT) } := .expect(token.COLON) .openScope() := .parseStmtList() .closeScope() 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) .openScope() defer .closeScope() 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. .openScope() defer .closeScope() , _ = .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")) } .openScope() := .pos var ast.Stmt if .tok == token.CASE { .next() := .parseLhsList() 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{}} if == token.DEFINE { .shortVarDecl(, ) } = } 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() .closeScope() 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) .openScope() defer .closeScope() 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, X: , Body: , } } // regular for statement return &ast.ForStmt{ For: , Init: , Cond: .makeExpr(, "boolean or range expression"), Post: , Body: , } } func ( *parser) () ( ast.Stmt) { 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 isValidImport( string) bool { const = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD" , := strconv.Unquote() // go/scanner returns a legal string literal for , := range { if !unicode.IsGraphic() || unicode.IsSpace() || strings.ContainsRune(, ) { return false } } return != "" } func ( *parser) ( *ast.CommentGroup, token.Token, int) ast.Spec { if .trace { defer un(trace(, "ImportSpec")) } var *ast.Ident switch .tok { case token.PERIOD: = &ast.Ident{NamePos: .pos, Name: "."} .next() case token.IDENT: = .parseIdent() } := .pos var string if .tok == token.STRING { = .lit if !isValidImport() { .error(, "invalid import path: "+) } .next() } else { .expect(token.STRING) // use expect() error handling } .expectSemi() // call before accessing p.linecomment // collect imports := &ast.ImportSpec{ Doc: , Name: , Path: &ast.BasicLit{ValuePos: , Kind: token.STRING, Value: }, Comment: .lineComment, } .imports = append(.imports, ) return } func ( *parser) ( *ast.CommentGroup, token.Token, int) ast.Spec { if .trace { defer un(trace(, .String()+"Spec")) } := .pos := .parseIdentList() := .tryType() var []ast.Expr // always permit optional initialization for more tolerant parsing if .tok == token.ASSIGN { .next() = .parseRhsList() } .expectSemi() // call before accessing p.linecomment switch { case token.VAR: if == nil && == nil { .error(, "missing variable type or initialization") } case token.CONST: if == nil && ( == 0 || != nil) { .error(, "missing constant value") } } // Go spec: The scope of a constant or variable identifier declared inside // a function begins at the end of the ConstSpec or VarSpec and ends at // the end of the innermost containing block. // (Global identifiers are resolved in a separate phase after parsing.) := &ast.ValueSpec{ Doc: , Names: , Type: , Values: , Comment: .lineComment, } := ast.Con if == token.VAR { = ast.Var } .declare(, , .topScope, , ...) return } func ( *parser) ( *ast.CommentGroup, token.Token, int) ast.Spec { if .trace { defer un(trace(, "TypeSpec")) } := .parseIdent() // Go spec: The scope of a type identifier declared inside a function begins // at the identifier in the TypeSpec and ends at the end of the innermost // containing block. // (Global identifiers are resolved in a separate phase after parsing.) := &ast.TypeSpec{Doc: , Name: } .declare(, nil, .topScope, ast.Typ, ) if .tok == token.ASSIGN { .Assign = .pos .next() } .Type = .parseType() .expectSemi() // call before accessing p.linecomment .Comment = .lineComment return } 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) := ast.NewScope(.topScope) // function scope var *ast.FieldList if .tok == token.LPAREN { = .parseParameters(, false) } := .parseIdent() , := .parseSignature() var *ast.BlockStmt if .tok == token.LBRACE { = .parseBody() .expectSemi() } else if .tok == token.SEMICOLON { .next() if .tok == token.LBRACE { // opening { of function declaration on next line .error(.pos, "unexpected semicolon or newline before {") = .parseBody() .expectSemi() } } else { .expectSemi() } := &ast.FuncDecl{ Doc: , Recv: , Name: , Type: &ast.FuncType{ Func: , Params: , Results: , }, Body: , } if == nil { // Go spec: The scope of an identifier denoting a constant, type, // variable, or function (but not method) declared at top level // (outside any function) is the package block. // // init() functions cannot be referred to and there may // be more than one - don't put them in the pkgScope if .Name != "init" { .declare(, nil, .pkgScope, ast.Fun, ) } } return } func ( *parser) ( map[token.Token]bool) ast.Decl { if .trace { defer un(trace(, "Declaration")) } var parseSpecFunction switch .tok { 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 } .openScope() .pkgScope = .topScope 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 for .tok != token.EOF { = append(, .parseDecl(declStart)) } } } .closeScope() assert(.topScope == nil, "unbalanced scopes") assert(.labelScope == nil, "unbalanced label scopes") // resolve global identifiers within the same file := 0 for , := range .unresolved { // i <= index for current ident assert(.Obj == unresolved, "object already resolved") .Obj = .pkgScope.Lookup(.Name) // also removes unresolved sentinel if .Obj == nil { .unresolved[] = ++ } } return &ast.File{ Doc: , Package: , Name: , Decls: , Scope: .pkgScope, Imports: .imports, Unresolved: .unresolved[0:], Comments: .comments, } }