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 {
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
}
......
......@@ -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 {
......
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