func (p *parser) tryVarType(isParam bool) ast.Expr {
	if isParam && p.tok == token.ELLIPSIS {
		pos := p.pos
		p.next()
		typ, _ := p.tryIdentOrType(stateType, nil)  
		if typ != nil {
			p.resolve(typ)
		} else {
			p.error(pos, "'...' parameter is missing type")
			typ = &ast.BadExpr{From: pos, To: p.pos}
		}
		return &ast.Ellipsis{Ellipsis: pos, Elt: typ}
	}
	typ, _ := p.tryIdentOrType(stateType, nil)
	return typ
}
If the result is an identifier, it is not resolved.
package parser
import (
	"fmt"
	"strconv"
	"strings"
	"unicode"
	"github.com/goplus/gop/ast"
	"github.com/goplus/gop/scanner"
	"github.com/goplus/gop/token"
	"github.com/qiniu/x/log"
)
type parser struct {
	file    *token.File
	errors  scanner.ErrorList
	scanner scanner.Scanner
	mode   Mode  
	trace  bool  
	indent int   
	comments    []*ast.CommentGroup
	leadComment *ast.CommentGroup  
	lineComment *ast.CommentGroup  
	pos token.Pos    
	tok token.Token  
	lit string       
	old struct {
		pos token.Pos
		tok token.Token
		lit string
	}
	syncPos token.Pos  
	syncCnt int        
	exprLev int   
	inRHS   bool  
	pkgScope   *ast.Scope         
	topScope   *ast.Scope         
	unresolved []*ast.Ident       
	imports    []*ast.ImportSpec  
	labelScope  *ast.Scope      
	targetStack [][]*ast.Ident  
}
func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode Mode) {
	p.file = fset.AddFile(filename, -1, len(src))
	var m scanner.Mode
	if mode&ParseComments != 0 {
		m = scanner.ScanComments
	}
	eh := func(pos token.Position, msg string) { p.errors.Add(pos, msg) }
	p.scanner.Init(p.file, src, eh, m)
	p.mode = mode
	p.trace = mode&Trace != 0  
	p.next()
}
func (p *parser) openScope() {
	p.topScope = ast.NewScope(p.topScope)
}
func (p *parser) closeScope() {
	p.topScope = p.topScope.Outer
}
func (p *parser) openLabelScope() {
	p.labelScope = ast.NewScope(p.labelScope)
	p.targetStack = append(p.targetStack, nil)
}
func (p *parser) closeLabelScope() {
	n := len(p.targetStack) - 1
	scope := p.labelScope
	for _, ident := range p.targetStack[n] {
		ident.Obj = scope.Lookup(ident.Name)
		if ident.Obj == nil && p.mode&DeclarationErrors != 0 {
			p.error(ident.Pos(), fmt.Sprintf("label %s undefined", ident.Name))
		}
	}
	p.targetStack = p.targetStack[0:n]
	p.labelScope = p.labelScope.Outer
}
func (p *parser) declare(decl, data interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) {
	for _, ident := range idents {
		assert(ident.Obj == nil, "identifier already declared or resolved")
		obj := ast.NewObj(kind, ident.Name)
		obj.Decl = decl
		obj.Data = data
		ident.Obj = obj
		if ident.Name != "_" {
			if alt := scope.Insert(obj); alt != nil && p.mode&DeclarationErrors != 0 {
				prevDecl := ""
				if pos := alt.Pos(); pos.IsValid() {
					prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", p.file.Position(pos))
				}
				p.error(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl))
			}
		}
	}
}
func (p *parser) shortVarDecl(decl *ast.AssignStmt, list []ast.Expr) {
	n := 0  
	for _, x := range list {
		if ident, isIdent := x.(*ast.Ident); isIdent {
			assert(ident.Obj == nil, "identifier already declared or resolved")
			obj := ast.NewObj(ast.Var, ident.Name)
			obj.Decl = decl
			ident.Obj = obj
			if ident.Name != "_" {
				if alt := p.topScope.Insert(obj); alt != nil {
					ident.Obj = alt  
				} else {
					n++  
				}
			}
		} else {
			p.errorExpected(x.Pos(), "identifier on left side of :=", 2)
		}
	}
	if n == 0 && p.mode&DeclarationErrors != 0 {
		p.error(list[0].Pos(), "no new variables on left side of :=")
	}
}
var unresolved = new(ast.Object)
func (p *parser) tryResolve(x ast.Expr, collectUnresolved bool) {
	ident, _ := x.(*ast.Ident)
	if ident == nil {
		return
	}
	assert(ident.Obj == nil, "identifier already declared or resolved")
	if ident.Name == "_" {
		return
	}
	for s := p.topScope; s != nil; s = s.Outer {
		if obj := s.Lookup(ident.Name); obj != nil {
			ident.Obj = obj
			return
		}
	}
	if collectUnresolved {
		ident.Obj = unresolved
		p.unresolved = append(p.unresolved, ident)
	}
}
func (p *parser) resolve(x ast.Expr) {
	p.tryResolve(x, true)
}
func (p *parser) printTrace(a ...interface{}) {
	const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
	const n = len(dots)
	pos := p.file.Position(p.pos)
	fmt.Printf("%5d:%3d: ", pos.Line, pos.Column)
	i := 2 * p.indent
	for i > n {
		fmt.Print(dots)
		i -= n
	}
	fmt.Print(dots[0:i])
	fmt.Println(a...)
}
func trace(p *parser, msg string) *parser {
	p.printTrace(msg, "(")
	p.indent++
	return p
}
func un(p *parser) {
	p.indent--
	p.printTrace(")")
}
func (p *parser) unget(pos token.Pos, tok token.Token, lit string) {
	p.old.pos, p.old.tok, p.old.lit = p.pos, p.tok, p.lit
	p.pos, p.tok, p.lit = pos, tok, lit
}
func (p *parser) next0() {
	if p.old.pos != 0 {  
		p.pos, p.tok, p.lit = p.old.pos, p.old.tok, p.old.lit
		p.old.pos = 0
		return
	}
	if p.trace && p.pos.IsValid() {
		s := p.tok.String()
		switch {
		case p.tok.IsLiteral():
			p.printTrace(s, p.lit)
		case p.tok.IsOperator(), p.tok.IsKeyword():
			p.printTrace("\"" + s + "\"")
		default:
			p.printTrace(s)
		}
	}
	p.pos, p.tok, p.lit = p.scanner.Scan()
}
func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
	endline = p.file.Line(p.pos)
	if p.lit[1] == '*' {
		for i := 0; i < len(p.lit); i++ {
			if p.lit[i] == '\n' {
				endline++
			}
		}
	}
	comment = &ast.Comment{Slash: p.pos, Text: p.lit}
	p.next0()
	return
}
func (p *parser) consumeCommentGroup(n int) (comments *ast.CommentGroup, endline int) {
	var list []*ast.Comment
	endline = p.file.Line(p.pos)
	for p.tok == token.COMMENT && p.file.Line(p.pos) <= endline+n {
		var comment *ast.Comment
		comment, endline = p.consumeComment()
		list = append(list, comment)
	}
	comments = &ast.CommentGroup{List: list}
	p.comments = append(p.comments, comments)
	return
}
func (p *parser) next() {
	p.leadComment = nil
	p.lineComment = nil
	prev := p.pos
	p.next0()
	if p.tok == token.COMMENT {
		var comment *ast.CommentGroup
		var endline int
		if p.file.Line(p.pos) == p.file.Line(prev) {
			comment, endline = p.consumeCommentGroup(0)
			if p.file.Line(p.pos) != endline || p.tok == token.EOF {
				p.lineComment = comment
			}
		}
		endline = -1
		for p.tok == token.COMMENT {
			comment, endline = p.consumeCommentGroup(1)
		}
		if endline+1 == p.file.Line(p.pos) {
			p.leadComment = comment
		}
	}
}
type bailout struct{}
func (p *parser) error(pos token.Pos, msg string) {
	epos := p.file.Position(pos)
	if p.mode&AllErrors == 0 {
		n := len(p.errors)
		if n > 0 && p.errors[n-1].Pos.Line == epos.Line {
			return  
		}
		if n > 10 {
			panic(bailout{})
		}
	}
	p.errors.Add(epos, msg)
}
func (p *parser) errorExpected(pos token.Pos, msg string, calldepth int) {
	msg = "expected " + msg
	if pos == p.pos {
		switch {
		case p.tok == token.SEMICOLON && p.lit == "\n":
			msg += ", found newline"
		case p.tok.IsLiteral():
			msg += ", found " + p.lit
		default:
			msg += ", found '" + p.tok.String() + "'"
		}
	}
	if debugParseError {
		log.Std.Output("", log.Linfo, calldepth, msg)
	}
	p.error(pos, msg)
}
func (p *parser) expect(tok token.Token) token.Pos {
	pos := p.pos
	if p.tok != tok {
		p.errorExpected(pos, "'"+tok.String()+"'", 3)
	}
	p.next()  
	return pos
}
func (p *parser) expect2(tok token.Token) (pos token.Pos) {
	if p.tok == tok {
		pos = p.pos
	} else {
		p.errorExpected(p.pos, "'"+tok.String()+"'", 3)
	}
	p.next()  
	return
}
func (p *parser) expectClosing(tok token.Token, context string) token.Pos {
	if p.tok != tok && p.tok == token.SEMICOLON && p.lit == "\n" {
		p.error(p.pos, "missing ',' before newline in "+context)
		p.next()
	}
	return p.expect(tok)
}
func (p *parser) expectSemi() {
	if p.tok != token.RPAREN && p.tok != token.RBRACE {
		switch p.tok {
		case token.COMMA:
			p.errorExpected(p.pos, "';'", 3)
			fallthrough
		case token.SEMICOLON:
			p.next()
		default:
			p.errorExpected(p.pos, "';'", 3)
			p.advance(stmtStart)
		}
	}
}
func (p *parser) atComma(context string, follow token.Token) bool {
	if p.tok == token.COMMA {
		return true
	}
	if p.tok != follow {
		msg := "missing ','"
		if p.tok == token.SEMICOLON && p.lit == "\n" {
			msg += " before newline"
		}
		msgctx := msg + " in " + context
		p.error(p.pos, msgctx)
		if debugParseError {
			log.Std.Output("", log.Linfo, 2, msgctx)
			panic(msgctx)
		}
		return true  
	}
	return false
}
func assert(cond bool, msg string) {
	if !cond {
		panic("go/parser internal error: " + msg)
	}
}
func (p *parser) advance(to map[token.Token]bool) {
	for ; p.tok != token.EOF; p.next() {
		if to[p.tok] {
			if p.pos == p.syncPos && p.syncCnt < 10 {
				p.syncCnt++
				return
			}
			if p.pos > p.syncPos {
				p.syncPos = p.pos
				p.syncCnt = 0
				return
			}
		}
	}
}
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 (p *parser) safePos(pos token.Pos) (res token.Pos) {
	defer func() {
		if recover() != nil {
			res = token.Pos(p.file.Base() + p.file.Size())  
		}
	}()
	_ = p.file.Offset(pos)  
	return pos
}
func (p *parser) parseIdentOrOp() (*ast.Ident, bool) {  
	if int(p.tok) < len(overloadOps) {
		flags := overloadOps[p.tok]
		if flags != 0 {
			pos := p.pos
			tok := p.tok
			p.next()
			if debugParseOutput {
				log.Printf("ast.Ident{Tok: %v}\n", tok)
			}
			return &ast.Ident{NamePos: pos, Name: tok.String()}, true
		}
	}
	return p.parseIdent(), false
}
const (
	opUnary = 1 << iota
	opBinary
	opAssign
	opAssignOp
	opIncDec
)
var overloadOps = [...]byte{
	token.ADD: opBinary,            
	token.SUB: opBinary | opUnary,  
	token.MUL: opBinary | opUnary,  
	token.QUO: opBinary,            
	token.REM: opBinary,            
	token.AND:     opBinary,  
	token.OR:      opBinary,  
	token.XOR:     opBinary,  
	token.SHL:     opBinary,  
	token.SHR:     opBinary,  
	token.AND_NOT: opBinary,  
	token.ADD_ASSIGN: opAssignOp,  
	token.SUB_ASSIGN: opAssignOp,  
	token.MUL_ASSIGN: opAssignOp,  
	token.QUO_ASSIGN: opAssignOp,  
	token.REM_ASSIGN: opAssignOp,  
	token.AND_ASSIGN:     opAssignOp,  
	token.OR_ASSIGN:      opAssignOp,  
	token.XOR_ASSIGN:     opAssignOp,  
	token.SHL_ASSIGN:     opAssignOp,  
	token.SHR_ASSIGN:     opAssignOp,  
	token.AND_NOT_ASSIGN: opAssignOp,  
	token.ASSIGN: opAssign,  
	token.INC: opIncDec,  
	token.DEC: opIncDec,  
	token.EQL:  opBinary,  
	token.LSS:  opBinary,  
	token.GTR:  opBinary,  
	token.NEQ:  opBinary,  
	token.LEQ:  opBinary,  
	token.GEQ:  opBinary,  
	token.LAND: opBinary,  
	token.LOR:  opBinary,  
	token.NOT:  opUnary,   
	token.ARROW: opBinary | opUnary,  
}
func (p *parser) parseIdent() *ast.Ident {
	pos := p.pos
	name := "_"
	if p.tok == token.IDENT {
		name = p.lit
		p.next()
	} else {
		p.expect(token.IDENT)  
	}
	if debugParseOutput {
		log.Printf("ast.Ident{Name: %v}\n", name)
	}
	return &ast.Ident{NamePos: pos, Name: name}
}
func (p *parser) parseIdentList() (list []*ast.Ident) {
	if p.trace {
		defer un(trace(p, "IdentList"))
	}
	list = append(list, p.parseIdent())
	for p.tok == token.COMMA {
		p.next()
		list = append(list, p.parseIdent())
	}
	return
}
func (p *parser) parseExprList(lhs, allowCmd bool) (list []ast.Expr) {
	if p.trace {
		defer un(trace(p, "ExpressionList"))
	}
	list = append(list, p.checkExpr(p.parseExpr(lhs, allowCmd)))
	for p.tok == token.COMMA {
		p.next()
		list = append(list, p.checkExpr(p.parseExpr(lhs, false)))
	}
	return
}
func (p *parser) parseLHSList(allowCmd bool) []ast.Expr {
	old := p.inRHS
	p.inRHS = false
	list := p.parseExprList(true, allowCmd)
	switch p.tok {
	case token.DEFINE:
	case token.COLON:
	default:
		for _, x := range list {
			p.resolve(x)
		}
	}
	p.inRHS = old
	return list
}
func (p *parser) parseRHSList() []ast.Expr {
	old := p.inRHS
	p.inRHS = true
	list := p.parseExprList(false, false)
	p.inRHS = old
	return list
}
func (p *parser) parseType() ast.Expr {
	if p.trace {
		defer un(trace(p, "Type"))
	}
	typ := p.tryType()
	if typ == nil {
		pos := p.pos
		p.errorExpected(pos, "type", 2)
		p.advance(exprEnd)
		return &ast.BadExpr{From: pos, To: p.pos}
	}
	return typ
}
func (p *parser) parseTypeName() ast.Expr {
	if p.trace {
		defer un(trace(p, "TypeName"))
	}
	ident := p.parseIdent()
	if p.tok == token.PERIOD {
		p.next()
		p.resolve(ident)
		sel := p.parseIdent()
		return &ast.SelectorExpr{X: ident, Sel: sel}
	}
	return ident
}
const (
	stateArrayTypeOrSliceLit = iota
	stateTypeOrSliceOp
	stateType
)
const (
	resultNone      = 0
	resultArrayType = 1 << iota
	resultSliceLit
	resultSliceOp
	resultComprehensionExpr
	resultParenType
	resultType
	resultIdent      
	resultExprFlags = resultSliceLit | resultSliceOp | resultComprehensionExpr
	resultTypeFlags = resultArrayType | resultParenType | resultType
)
func (p *parser) parseArrayTypeOrSliceLit(state int, slice ast.Expr) (expr ast.Expr, result int) {
	if p.trace {
		defer un(trace(p, "ArrayType"))
	}
	lbrack := p.expect(token.LBRACK)
	p.exprLev++
	var len ast.Expr
	if p.tok == token.ELLIPSIS {
		len = &ast.Ellipsis{Ellipsis: p.pos}
		p.next()
	} else if p.tok != token.RBRACK {
		len = p.parseRHS()
		switch state {
		case stateArrayTypeOrSliceLit:
			switch p.tok {
			case token.COMMA:  
				sliceLit := p.parseSliceLit(lbrack, len)
				p.exprLev--
				return sliceLit, resultSliceLit
			case token.FOR:  
				phrases := p.parseForPhrases()
				p.exprLev--
				rbrack := p.expect(token.RBRACK)
				if debugParseOutput {
					log.Printf("ast.ComprehensionExpr{Tok: [, Elt: %v, Fors: %v}\n", len, phrases)
				}
				return &ast.ComprehensionExpr{
					Lpos: lbrack, Tok: token.LBRACK, Elt: len,
					Fors: phrases, Rpos: rbrack,
				}, resultComprehensionExpr
			}
		case stateTypeOrSliceOp:
			switch p.tok {
			case token.COLON:  
				return p.parseIndexOrSliceContinue(slice, lbrack, len), resultSliceOp
			}
		}
	}
	p.exprLev--
	rbrack := p.expect(token.RBRACK)
	var elt ast.Expr
	switch state {
	case stateType:
		elt = p.parseType()
	case stateArrayTypeOrSliceLit:
		sliceLit := newSliceLit(lbrack, rbrack, len)
		elt, result = p.tryIdentOrType(stateTypeOrSliceOp, sliceLit)
		switch result {
		case resultNone:
			if debugParseOutput {
				log.Printf("ast.SliceLit{Elts: %v}\n", sliceLit.Elts)
			}
			return sliceLit, resultSliceLit
		case resultSliceOp:
			return elt, resultSliceOp
		}
		p.resolve(elt)
	case stateTypeOrSliceOp:
		elt = p.tryType()
		if elt == nil {
			if len == nil {
				log.Panicln("TODO: expect slice index")
			}
			if debugParseOutput {
				log.Printf("ast.IndexExpr{X: %v, Index: %v}\n", slice, len)
			}
			return &ast.IndexExpr{X: slice, Index: len}, resultSliceOp
		}
	default:
		panic("parseArrayTypeOrSliceLit: unexpected state")
	}
	if debugParseOutput {
		log.Printf("ast.ArrayType{Len: %v, Elt: %v}\n", len, elt)
	}
	return &ast.ArrayType{Lbrack: lbrack, Len: len, Elt: elt}, resultArrayType
}
func (p *parser) parseSliceLit(lbrack token.Pos, len ast.Expr) ast.Expr {
	elts := make([]ast.Expr, 1, 8)
	elts[0] = len
	for p.tok == token.COMMA {
		p.next()
		if p.tok != token.RBRACK {
			elt := p.parseRHS()
			elts = append(elts, elt)
		}
	}
	rbrack := p.expect(token.RBRACK)
	if debugParseOutput {
		log.Printf("ast.SliceLit{Elts: %v}\n", elts)
	}
	return &ast.SliceLit{Lbrack: lbrack, Elts: elts, Rbrack: rbrack}
}
func newSliceLit(lbrack, rbrack token.Pos, len ast.Expr) *ast.SliceLit {
	var elts []ast.Expr
	if len != nil {
		elts = []ast.Expr{len}
	}
	return &ast.SliceLit{Lbrack: lbrack, Elts: elts, Rbrack: rbrack}
}
func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
	idents := make([]*ast.Ident, len(list))
	for i, x := range list {
		ident, isIdent := x.(*ast.Ident)
		if !isIdent {
			if _, isBad := x.(*ast.BadExpr); !isBad {
				p.errorExpected(x.Pos(), "identifier", 2)
			}
			ident = &ast.Ident{NamePos: x.Pos(), Name: "_"}
		}
		idents[i] = ident
	}
	return idents
}
func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field {
	if p.trace {
		defer un(trace(p, "FieldDecl"))
	}
	doc := p.leadComment
	var list []ast.Expr
	for {
		list = append(list, p.parseVarType(false))
		if p.tok != token.COMMA {
			break
		}
		p.next()
	}
	typ := p.tryVarType(false)
	var idents []*ast.Ident
	if typ != nil {
		idents = p.makeIdentList(list)
	} else {
		typ = list[0]  
		if n := len(list); n > 1 {
			p.errorExpected(p.pos, "type", 2)
			typ = &ast.BadExpr{From: p.pos, To: p.pos}
		} else if !isTypeName(deref(typ)) {
			p.errorExpected(typ.Pos(), "anonymous field", 2)
			typ = &ast.BadExpr{From: typ.Pos(), To: p.safePos(typ.End())}
		}
	}
	var tag *ast.BasicLit
	if p.tok == token.STRING {
		tag = &ast.BasicLit{ValuePos: p.pos, Kind: p.tok, Value: p.lit}
		p.next()
	}
	p.expectSemi()  
	field := &ast.Field{Doc: doc, Names: idents, Type: typ, Tag: tag, Comment: p.lineComment}
	p.declare(field, nil, scope, ast.Var, idents...)
	p.resolve(typ)
	return field
}
func (p *parser) parseStructType() *ast.StructType {
	if p.trace {
		defer un(trace(p, "StructType"))
	}
	pos := p.expect(token.STRUCT)
	lbrace := p.expect(token.LBRACE)
	scope := ast.NewScope(nil)  
	var list []*ast.Field
	for p.tok == token.IDENT || p.tok == token.MUL || p.tok == token.LPAREN {
		list = append(list, p.parseFieldDecl(scope))
	}
	rbrace := p.expect(token.RBRACE)
	return &ast.StructType{
		Struct: pos,
		Fields: &ast.FieldList{
			Opening: lbrace,
			List:    list,
			Closing: rbrace,
		},
	}
}
func (p *parser) parsePointerType() *ast.StarExpr {
	if p.trace {
		defer un(trace(p, "PointerType"))
	}
	star := p.expect(token.MUL)
	base := p.parseType()
	return &ast.StarExpr{Star: star, X: base}
}