Source File
parser.go
Belonging Package
go/parser
package parser
import (
)
comments []*ast.CommentGroup
leadComment *ast.CommentGroup // last lead comment
lineComment *ast.CommentGroup // last line comment
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()
}
func ( *parser) () {
.topScope = ast.NewScope(.topScope)
}
func ( *parser) () {
.topScope = .topScope.Outer
}
func ( *parser) () {
.labelScope = ast.NewScope(.labelScope)
.targetStack = append(.targetStack, nil)
}
:= len(.targetStack) - 1
:= .labelScope
for , := range .targetStack[] {
.Obj = .Lookup(.Name)
if .Obj == nil && .mode&DeclarationErrors != 0 {
.error(.Pos(), fmt.Sprintf("label %s undefined", .Name))
}
.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")
var unresolved = new(ast.Object)
if {
.Obj = unresolved
.unresolved = append(.unresolved, )
}
}
func ( *parser) ( ast.Expr) {
.tryResolve(, true)
}
func ( *parser) {
.indent--
.printTrace(")")
}
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()
}
func ( *parser) () {
.leadComment = nil
.lineComment = nil
:= .pos
.next0()
if .tok == token.COMMENT {
var *ast.CommentGroup
var int
, = .consumeCommentGroup(0)
.lineComment =
}
}
= -1
for .tok == token.COMMENT {
, = .consumeCommentGroup(1)
}
.leadComment =
}
}
}
.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 ( bool, string) {
if ! {
panic("go/parser internal error: " + )
}
}
}
}
}
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,
}
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
}
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 {
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 ! {
= .makeIdentList()
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
= 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) ( 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()
}
:= .makeIdentList()
:= &ast.Field{Names: , Type: }
= 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()
=
.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: }
}
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: }
}
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: }
}
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()
}
:= .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
.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)
:= false
if == 2 {
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)
}
.tryResolve(, false)
.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: }
}
return
}
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
}
:= .(false)
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
}
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,
, := .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 {
}
switch .tok {
.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 {
:= 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())}
}
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")
}
}
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 ( ast.Expr) bool {
, := .(*ast.TypeAssertExpr)
return && .Type == nil
}
func ( *parser) ( ast.Stmt) bool {
switch t := .(type) {
return isTypeSwitchAssert(.X)
.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
.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 len() > 1 {
if len() > 2 {
if len() > 1 {
}
= &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 {
:= .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 {
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()
type parseSpecFunction func(doc *ast.CommentGroup, keyword token.Token, iota int) ast.Spec
func ( 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
:= &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()
:= &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 .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, )
}
:= .leadComment
:= .parseIdent()
if .Name == "_" && .mode&DeclarationErrors != 0 {
.error(.pos, "invalid package name _")
}
.expectSemi()
for .tok == token.IMPORT {
= append(, .parseGenDecl(token.IMPORT, .parseImportSpec))
}
:= 0
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,
}
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |