Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / libgo / go / go / parser / parser.go
index 20e505d..959af38 100644 (file)
@@ -28,7 +28,7 @@ type parser struct {
        // Tracing/debugging
        mode   Mode // parsing mode
        trace  bool // == (mode & Trace != 0)
-       indent uint // indentation used for tracing output
+       indent int  // indentation used for tracing output
 
        // Comments
        comments    []*ast.CommentGroup
@@ -56,7 +56,7 @@ type parser struct {
        unresolved []*ast.Ident      // unresolved identifiers
        imports    []*ast.ImportSpec // list of imports
 
-       // Label scope
+       // Label scopes
        // (maintained by open/close LabelScope)
        labelScope  *ast.Scope     // label scope for current function
        targetStack [][]*ast.Ident // stack of unresolved labels
@@ -75,14 +75,6 @@ func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode Mod
        p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently)
 
        p.next()
-
-       // set up the pkgScope here (as opposed to in parseFile) because
-       // there are other parser entry points (ParseExpr, etc.)
-       p.openScope()
-       p.pkgScope = p.topScope
-
-       // for the same reason, set up a label scope
-       p.openLabelScope()
 }
 
 // ----------------------------------------------------------------------------
@@ -157,7 +149,7 @@ func (p *parser) shortVarDecl(decl *ast.AssignStmt, list []ast.Expr) {
                                }
                        }
                } else {
-                       p.errorExpected(x.Pos(), "identifier")
+                       p.errorExpected(x.Pos(), "identifier on left side of :=")
                }
        }
        if n == 0 && p.mode&DeclarationErrors != 0 {
@@ -170,7 +162,12 @@ func (p *parser) shortVarDecl(decl *ast.AssignStmt, list []ast.Expr) {
 // internal consistency.
 var unresolved = new(ast.Object)
 
-func (p *parser) resolve(x ast.Expr) {
+// 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 (p *parser) tryResolve(x ast.Expr, collectUnresolved bool) {
        // nothing to do if x is not an identifier or the blank identifier
        ident, _ := x.(*ast.Ident)
        if ident == nil {
@@ -191,23 +188,30 @@ func (p *parser) resolve(x ast.Expr) {
        // 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
-       ident.Obj = unresolved
-       p.unresolved = append(p.unresolved, ident)
+       if collectUnresolved {
+               ident.Obj = unresolved
+               p.unresolved = append(p.unresolved, ident)
+       }
+}
+
+func (p *parser) resolve(x ast.Expr) {
+       p.tryResolve(x, true)
 }
 
 // ----------------------------------------------------------------------------
 // Parsing support
 
 func (p *parser) printTrace(a ...interface{}) {
-       const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " +
-               ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
-       const n = uint(len(dots))
+       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; i -= n {
+       for i > n {
                fmt.Print(dots)
+               i -= n
        }
+       // i <= n
        fmt.Print(dots[0:i])
        fmt.Println(a...)
 }
@@ -218,7 +222,7 @@ func trace(p *parser, msg string) *parser {
        return p
 }
 
-// Usage pattern: defer un(trace(p, "..."));
+// Usage pattern: defer un(trace(p, "..."))
 func un(p *parser) {
        p.indent--
        p.printTrace(")")
@@ -304,14 +308,14 @@ func (p *parser) consumeCommentGroup(n int) (comments *ast.CommentGroup, endline
 func (p *parser) next() {
        p.leadComment = nil
        p.lineComment = nil
-       line := p.file.Line(p.pos) // current line
+       prev := p.pos
        p.next0()
 
        if p.tok == token.COMMENT {
                var comment *ast.CommentGroup
                var endline int
 
-               if p.file.Line(p.pos) == line {
+               if p.file.Line(p.pos) == p.file.Line(prev) {
                        // The comment is on same line as the previous token; it
                        // cannot be a lead comment but may be a line comment.
                        comment, endline = p.consumeCommentGroup(0)
@@ -585,14 +589,15 @@ func (p *parser) parseTypeName() ast.Expr {
        return ident
 }
 
-func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
+func (p *parser) parseArrayType() ast.Expr {
        if p.trace {
                defer un(trace(p, "ArrayType"))
        }
 
        lbrack := p.expect(token.LBRACK)
        var len ast.Expr
-       if ellipsisOk && p.tok == token.ELLIPSIS {
+       // always permit ellipsis for more fault-tolerant parsing
+       if p.tok == token.ELLIPSIS {
                len = &ast.Ellipsis{Ellipsis: p.pos}
                p.next()
        } else if p.tok != token.RBRACK {
@@ -704,7 +709,7 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
        if isParam && p.tok == token.ELLIPSIS {
                pos := p.pos
                p.next()
-               typ := p.tryIdentOrType(isParam) // don't use parseType so we can provide better error message
+               typ := p.tryIdentOrType() // don't use parseType so we can provide better error message
                if typ != nil {
                        p.resolve(typ)
                } else {
@@ -713,7 +718,7 @@ func (p *parser) tryVarType(isParam bool) ast.Expr {
                }
                return &ast.Ellipsis{Ellipsis: pos, Elt: typ}
        }
-       return p.tryIdentOrType(false)
+       return p.tryIdentOrType()
 }
 
 // If the result is an identifier, it is not resolved.
@@ -931,29 +936,31 @@ func (p *parser) parseChanType() *ast.ChanType {
 
        pos := p.pos
        dir := ast.SEND | ast.RECV
+       var arrow token.Pos
        if p.tok == token.CHAN {
                p.next()
                if p.tok == token.ARROW {
+                       arrow = p.pos
                        p.next()
                        dir = ast.SEND
                }
        } else {
-               p.expect(token.ARROW)
+               arrow = p.expect(token.ARROW)
                p.expect(token.CHAN)
                dir = ast.RECV
        }
        value := p.parseType()
 
-       return &ast.ChanType{Begin: pos, Dir: dir, Value: value}
+       return &ast.ChanType{Begin: pos, Arrow: arrow, Dir: dir, Value: value}
 }
 
 // If the result is an identifier, it is not resolved.
-func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
+func (p *parser) tryIdentOrType() ast.Expr {
        switch p.tok {
        case token.IDENT:
                return p.parseTypeName()
        case token.LBRACK:
-               return p.parseArrayType(ellipsisOk)
+               return p.parseArrayType()
        case token.STRUCT:
                return p.parseStructType()
        case token.MUL:
@@ -980,7 +987,7 @@ func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr {
 }
 
 func (p *parser) tryType() ast.Expr {
-       typ := p.tryIdentOrType(false)
+       typ := p.tryIdentOrType()
        if typ != nil {
                p.resolve(typ)
        }
@@ -1088,7 +1095,7 @@ func (p *parser) parseOperand(lhs bool) ast.Expr {
                return p.parseFuncTypeOrLit()
        }
 
-       if typ := p.tryIdentOrType(true); typ != nil {
+       if typ := p.tryIdentOrType(); typ != nil {
                // could be type for composite literal or conversion
                _, isIdent := typ.(*ast.Ident)
                assert(!isIdent, "type cannot be identifier")
@@ -1193,14 +1200,35 @@ func (p *parser) parseElement(keyOk bool) ast.Expr {
                return p.parseLiteralValue(nil)
        }
 
-       x := p.checkExpr(p.parseExpr(keyOk)) // don't resolve if map key
+       // 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 must a) be defined at the top-
+       // level in another file of the same package 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.
+       x := p.checkExpr(p.parseExpr(keyOk))
        if keyOk {
                if p.tok == token.COLON {
                        colon := p.pos
                        p.next()
+                       // 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.
+                       p.tryResolve(x, false)
                        return &ast.KeyValueExpr{Key: x, Colon: colon, Value: p.parseElement(false)}
                }
-               p.resolve(x) // not a map key
+               p.resolve(x) // not a key
        }
 
        return x
@@ -1404,16 +1432,49 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
 
        case token.ARROW:
                // channel type or receive expression
-               pos := p.pos
+               arrow := p.pos
                p.next()
-               if p.tok == token.CHAN {
-                       p.next()
-                       value := p.parseType()
-                       return &ast.ChanType{Begin: pos, Dir: ast.RECV, Value: value}
-               }
+
+               // 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))
 
                x := p.parseUnaryExpr(false)
-               return &ast.UnaryExpr{OpPos: pos, Op: token.ARROW, X: p.checkExpr(x)}
+
+               // determine which case we have
+               if typ, ok := x.(*ast.ChanType); ok {
+                       // (<-type)
+
+                       // re-associate position info and <-
+                       dir := ast.SEND
+                       for ok && dir == ast.SEND {
+                               if typ.Dir == ast.RECV {
+                                       // error: (<-type) is (<-(<-chan T))
+                                       p.errorExpected(typ.Arrow, "'chan'")
+                               }
+                               arrow, typ.Begin, typ.Arrow = typ.Arrow, arrow, arrow
+                               dir, typ.Dir = typ.Dir, ast.RECV
+                               typ, ok = typ.Value.(*ast.ChanType)
+                       }
+                       if dir == ast.SEND {
+                               p.errorExpected(arrow, "channel type")
+                       }
+
+                       return x
+               }
+
+               // <-(expr)
+               return &ast.UnaryExpr{OpPos: arrow, Op: token.ARROW, X: p.checkExpr(x)}
 
        case token.MUL:
                // pointer type or unary "*" expression
@@ -1774,7 +1835,7 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
                                //
                                //      switch t := 0; t := x.(T) { ... }
                                //
-                               // (this code is not valid Go because the first t will
+                               // (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).
                                //
@@ -2012,7 +2073,7 @@ func (p *parser) parseStmt() (s ast.Stmt) {
 // ----------------------------------------------------------------------------
 // Declarations
 
-type parseSpecFunction func(p *parser, doc *ast.CommentGroup, iota int) ast.Spec
+type parseSpecFunction func(p *parser, doc *ast.CommentGroup, keyword token.Token, iota int) ast.Spec
 
 func isValidImport(lit string) bool {
        const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
@@ -2025,7 +2086,7 @@ func isValidImport(lit string) bool {
        return s != ""
 }
 
-func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
+func (p *parser) parseImportSpec(doc *ast.CommentGroup, _ token.Token, _ int) ast.Spec {
        if p.trace {
                defer un(trace(p, "ImportSpec"))
        }
@@ -2063,15 +2124,15 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
        return spec
 }
 
-func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
+func (p *parser) parseValueSpec(doc *ast.CommentGroup, keyword token.Token, iota int) ast.Spec {
        if p.trace {
-               defer un(trace(p, "ConstSpec"))
+               defer un(trace(p, keyword.String()+"Spec"))
        }
 
        idents := p.parseIdentList()
        typ := p.tryType()
        var values []ast.Expr
-       if typ != nil || p.tok == token.ASSIGN || iota == 0 {
+       if p.tok == token.ASSIGN || keyword == token.CONST && (typ != nil || iota == 0) || keyword == token.VAR && typ == nil {
                p.expect(token.ASSIGN)
                values = p.parseRhsList()
        }
@@ -2088,12 +2149,16 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec {
                Values:  values,
                Comment: p.lineComment,
        }
-       p.declare(spec, iota, p.topScope, ast.Con, idents...)
+       kind := ast.Con
+       if keyword == token.VAR {
+               kind = ast.Var
+       }
+       p.declare(spec, iota, p.topScope, kind, idents...)
 
        return spec
 }
 
-func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
+func (p *parser) parseTypeSpec(doc *ast.CommentGroup, _ token.Token, _ int) ast.Spec {
        if p.trace {
                defer un(trace(p, "TypeSpec"))
        }
@@ -2114,36 +2179,6 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
        return spec
 }
 
-func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec {
-       if p.trace {
-               defer un(trace(p, "VarSpec"))
-       }
-
-       idents := p.parseIdentList()
-       typ := p.tryType()
-       var values []ast.Expr
-       if typ == nil || p.tok == token.ASSIGN {
-               p.expect(token.ASSIGN)
-               values = p.parseRhsList()
-       }
-       p.expectSemi() // call before accessing p.linecomment
-
-       // 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.)
-       spec := &ast.ValueSpec{
-               Doc:     doc,
-               Names:   idents,
-               Type:    typ,
-               Values:  values,
-               Comment: p.lineComment,
-       }
-       p.declare(spec, nil, p.topScope, ast.Var, idents...)
-
-       return spec
-}
-
 func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
        if p.trace {
                defer un(trace(p, "GenDecl("+keyword.String()+")"))
@@ -2157,12 +2192,12 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
                lparen = p.pos
                p.next()
                for iota := 0; p.tok != token.RPAREN && p.tok != token.EOF; iota++ {
-                       list = append(list, f(p, p.leadComment, iota))
+                       list = append(list, f(p, p.leadComment, keyword, iota))
                }
                rparen = p.expect(token.RPAREN)
                p.expectSemi()
        } else {
-               list = append(list, f(p, nil, 0))
+               list = append(list, f(p, nil, keyword, 0))
        }
 
        return &ast.GenDecl{
@@ -2262,14 +2297,11 @@ func (p *parser) parseDecl(sync func(*parser)) ast.Decl {
 
        var f parseSpecFunction
        switch p.tok {
-       case token.CONST:
-               f = parseConstSpec
+       case token.CONST, token.VAR:
+               f = (*parser).parseValueSpec
 
        case token.TYPE:
-               f = parseTypeSpec
-
-       case token.VAR:
-               f = parseVarSpec
+               f = (*parser).parseTypeSpec
 
        case token.FUNC:
                return p.parseFuncDecl()
@@ -2292,6 +2324,12 @@ func (p *parser) parseFile() *ast.File {
                defer un(trace(p, "File"))
        }
 
+       // Don't bother parsing the rest if we had errors scanning the first token.
+       // Likely not a Go source file at all.
+       if p.errors.Len() != 0 {
+               return nil
+       }
+
        // package clause
        doc := p.leadComment
        pos := p.expect(token.PACKAGE)
@@ -2303,15 +2341,19 @@ func (p *parser) parseFile() *ast.File {
        }
        p.expectSemi()
 
-       var decls []ast.Decl
-
-       // Don't bother parsing the rest if we had errors already.
+       // Don't bother parsing the rest if we had errors parsing the package clause.
        // Likely not a Go source file at all.
+       if p.errors.Len() != 0 {
+               return nil
+       }
 
-       if p.errors.Len() == 0 && p.mode&PackageClauseOnly == 0 {
+       p.openScope()
+       p.pkgScope = p.topScope
+       var decls []ast.Decl
+       if p.mode&PackageClauseOnly == 0 {
                // import decls
                for p.tok == token.IMPORT {
-                       decls = append(decls, p.parseGenDecl(token.IMPORT, parseImportSpec))
+                       decls = append(decls, p.parseGenDecl(token.IMPORT, (*parser).parseImportSpec))
                }
 
                if p.mode&ImportsOnly == 0 {
@@ -2321,8 +2363,9 @@ func (p *parser) parseFile() *ast.File {
                        }
                }
        }
-
-       assert(p.topScope == p.pkgScope, "imbalanced scopes")
+       p.closeScope()
+       assert(p.topScope == nil, "unbalanced scopes")
+       assert(p.labelScope == nil, "unbalanced label scopes")
 
        // resolve global identifiers within the same file
        i := 0