]> Cypherpunks repositories - gostls13.git/commitdiff
go/ast, parser: remember short variable decls. w/ correspoding ident objects
authorRobert Griesemer <gri@golang.org>
Tue, 20 Dec 2011 17:59:09 +0000 (09:59 -0800)
committerRobert Griesemer <gri@golang.org>
Tue, 20 Dec 2011 17:59:09 +0000 (09:59 -0800)
The ast.Object's Decl field pointed back to the corresponding declaration for
all but short variable declarations. Now remember corresponding assignment
statement in the Decl field.

Also: simplified some code for parsing select statements.

R=golang-dev, r, bradfitz
CC=golang-dev
https://golang.org/cl/5492072

src/pkg/go/ast/scope.go
src/pkg/go/parser/parser.go

index 92e3669808121ab704e58afcbccb2de0266aec12..fbe4779671ec8fc67b857d89eae1c6e6cb01422a 100644 (file)
@@ -80,7 +80,7 @@ func (s *Scope) String() string {
 type Object struct {
        Kind ObjKind
        Name string      // declared name
-       Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil
+       Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, or AssignStmt; or nil
        Data interface{} // object-specific data; or nil
        Type interface{} // place holder for type information; may be nil
 }
@@ -125,6 +125,12 @@ func (obj *Object) Pos() token.Pos {
                if d.Label.Name == name {
                        return d.Label.Pos()
                }
+       case *AssignStmt:
+               for _, x := range d.Lhs {
+                       if ident, isIdent := x.(*Ident); isIdent && ident.Name == name {
+                               return ident.Pos()
+                       }
+               }
        }
        return token.NoPos
 }
index f0a8055f4c1227cf211969395e5a890b35ba92b1..9fbed2d2ca35de31d605caf2336722ce22225d80 100644 (file)
@@ -144,28 +144,31 @@ func (p *parser) declare(decl, data interface{}, scope *ast.Scope, kind ast.ObjK
        }
 }
 
-func (p *parser) shortVarDecl(idents []*ast.Ident) {
+func (p *parser) shortVarDecl(decl *ast.AssignStmt, list []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.
        n := 0 // number of new variables
-       for _, ident := range idents {
-               assert(ident.Obj == nil, "identifier already declared or resolved")
-               obj := ast.NewObj(ast.Var, ident.Name)
-               // short var declarations cannot have redeclaration errors
-               // and are not global => no need to remember the respective
-               // declaration
-               ident.Obj = obj
-               if ident.Name != "_" {
-                       if alt := p.topScope.Insert(obj); alt != nil {
-                               ident.Obj = alt // redeclaration
-                       } else {
-                               n++ // new declaration
+       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)
+                       // remember corresponding assignment for other tools
+                       obj.Decl = decl
+                       ident.Obj = obj
+                       if ident.Name != "_" {
+                               if alt := p.topScope.Insert(obj); alt != nil {
+                                       ident.Obj = alt // redeclaration
+                               } else {
+                                       n++ // new declaration
+                               }
                        }
+               } else {
+                       p.errorExpected(x.Pos(), "identifier")
                }
        }
        if n == 0 && p.mode&DeclarationErrors != 0 {
-               p.error(idents[0].Pos(), "no new variables on left side of :=")
+               p.error(list[0].Pos(), "no new variables on left side of :=")
        }
 }
 
@@ -522,7 +525,7 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
        for i, x := range list {
                ident, isIdent := x.(*ast.Ident)
                if !isIdent {
-                       pos := x.(ast.Expr).Pos()
+                       pos := x.Pos()
                        p.errorExpected(pos, "identifier")
                        ident = &ast.Ident{pos, "_", nil}
                }
@@ -1400,10 +1403,11 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
                } else {
                        y = p.parseRhsList()
                }
+               as := &ast.AssignStmt{x, pos, tok, y}
                if tok == token.DEFINE {
-                       p.shortVarDecl(p.makeIdentList(x))
+                       p.shortVarDecl(as, x)
                }
-               return &ast.AssignStmt{x, pos, tok, y}, isRange
+               return as, isRange
        }
 
        if len(x) > 1 {
@@ -1715,34 +1719,28 @@ func (p *parser) parseCommClause() *ast.CommClause {
                        comm = &ast.SendStmt{lhs[0], arrow, rhs}
                } else {
                        // RecvStmt
-                       pos := p.pos
-                       tok := p.tok
-                       var rhs ast.Expr
-                       if tok == token.ASSIGN || tok == token.DEFINE {
+                       if tok := p.tok; tok == token.ASSIGN || tok == token.DEFINE {
                                // RecvStmt with assignment
                                if len(lhs) > 2 {
                                        p.errorExpected(lhs[0].Pos(), "1 or 2 expressions")
                                        // continue with first two expressions
                                        lhs = lhs[0:2]
                                }
+                               pos := p.pos
                                p.next()
-                               rhs = p.parseRhs()
-                               if tok == token.DEFINE && lhs != nil {
-                                       p.shortVarDecl(p.makeIdentList(lhs))
+                               rhs := p.parseRhs()
+                               as := &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}}
+                               if tok == token.DEFINE {
+                                       p.shortVarDecl(as, lhs)
                                }
+                               comm = as
                        } else {
-                               // rhs must be single receive operation
+                               // lhs must be single receive operation
                                if len(lhs) > 1 {
                                        p.errorExpected(lhs[0].Pos(), "1 expression")
                                        // continue with first expression
                                }
-                               rhs = lhs[0]
-                               lhs = nil // there is no lhs
-                       }
-                       if lhs != nil {
-                               comm = &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}}
-                       } else {
-                               comm = &ast.ExprStmt{rhs}
+                               comm = &ast.ExprStmt{lhs[0]}
                        }
                }
        } else {