Commit b9697d4a authored by Robert Griesemer's avatar Robert Griesemer

go/ast, parser: remember short variable decls. w/ correspoding ident objects

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
parent c50e4f5e
...@@ -80,7 +80,7 @@ func (s *Scope) String() string { ...@@ -80,7 +80,7 @@ func (s *Scope) String() string {
type Object struct { type Object struct {
Kind ObjKind Kind ObjKind
Name string // declared name 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 Data interface{} // object-specific data; or nil
Type interface{} // place holder for type information; may be nil Type interface{} // place holder for type information; may be nil
} }
...@@ -125,6 +125,12 @@ func (obj *Object) Pos() token.Pos { ...@@ -125,6 +125,12 @@ func (obj *Object) Pos() token.Pos {
if d.Label.Name == name { if d.Label.Name == name {
return d.Label.Pos() 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 return token.NoPos
} }
......
...@@ -144,28 +144,31 @@ func (p *parser) declare(decl, data interface{}, scope *ast.Scope, kind ast.ObjK ...@@ -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 // Go spec: A short variable declaration may redeclare variables
// provided they were originally declared in the same block with // provided they were originally declared in the same block with
// the same type, and at least one of the non-blank variables is new. // the same type, and at least one of the non-blank variables is new.
n := 0 // number of new variables n := 0 // number of new variables
for _, ident := range idents { for _, x := range list {
assert(ident.Obj == nil, "identifier already declared or resolved") if ident, isIdent := x.(*ast.Ident); isIdent {
obj := ast.NewObj(ast.Var, ident.Name) assert(ident.Obj == nil, "identifier already declared or resolved")
// short var declarations cannot have redeclaration errors obj := ast.NewObj(ast.Var, ident.Name)
// and are not global => no need to remember the respective // remember corresponding assignment for other tools
// declaration obj.Decl = decl
ident.Obj = obj ident.Obj = obj
if ident.Name != "_" { if ident.Name != "_" {
if alt := p.topScope.Insert(obj); alt != nil { if alt := p.topScope.Insert(obj); alt != nil {
ident.Obj = alt // redeclaration ident.Obj = alt // redeclaration
} else { } else {
n++ // new declaration n++ // new declaration
}
} }
} else {
p.errorExpected(x.Pos(), "identifier")
} }
} }
if n == 0 && p.mode&DeclarationErrors != 0 { 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 { ...@@ -522,7 +525,7 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
for i, x := range list { for i, x := range list {
ident, isIdent := x.(*ast.Ident) ident, isIdent := x.(*ast.Ident)
if !isIdent { if !isIdent {
pos := x.(ast.Expr).Pos() pos := x.Pos()
p.errorExpected(pos, "identifier") p.errorExpected(pos, "identifier")
ident = &ast.Ident{pos, "_", nil} ident = &ast.Ident{pos, "_", nil}
} }
...@@ -1400,10 +1403,11 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) { ...@@ -1400,10 +1403,11 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
} else { } else {
y = p.parseRhsList() y = p.parseRhsList()
} }
as := &ast.AssignStmt{x, pos, tok, y}
if tok == token.DEFINE { 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 { if len(x) > 1 {
...@@ -1715,34 +1719,28 @@ func (p *parser) parseCommClause() *ast.CommClause { ...@@ -1715,34 +1719,28 @@ func (p *parser) parseCommClause() *ast.CommClause {
comm = &ast.SendStmt{lhs[0], arrow, rhs} comm = &ast.SendStmt{lhs[0], arrow, rhs}
} else { } else {
// RecvStmt // RecvStmt
pos := p.pos if tok := p.tok; tok == token.ASSIGN || tok == token.DEFINE {
tok := p.tok
var rhs ast.Expr
if tok == token.ASSIGN || tok == token.DEFINE {
// RecvStmt with assignment // RecvStmt with assignment
if len(lhs) > 2 { if len(lhs) > 2 {
p.errorExpected(lhs[0].Pos(), "1 or 2 expressions") p.errorExpected(lhs[0].Pos(), "1 or 2 expressions")
// continue with first two expressions // continue with first two expressions
lhs = lhs[0:2] lhs = lhs[0:2]
} }
pos := p.pos
p.next() p.next()
rhs = p.parseRhs() rhs := p.parseRhs()
if tok == token.DEFINE && lhs != nil { as := &ast.AssignStmt{lhs, pos, tok, []ast.Expr{rhs}}
p.shortVarDecl(p.makeIdentList(lhs)) if tok == token.DEFINE {
p.shortVarDecl(as, lhs)
} }
comm = as
} else { } else {
// rhs must be single receive operation // lhs must be single receive operation
if len(lhs) > 1 { if len(lhs) > 1 {
p.errorExpected(lhs[0].Pos(), "1 expression") p.errorExpected(lhs[0].Pos(), "1 expression")
// continue with first expression // continue with first expression
} }
rhs = lhs[0] comm = &ast.ExprStmt{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}
} }
} }
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment