mirror of
https://github.com/golang/go
synced 2024-11-22 04:44:39 -07:00
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
This commit is contained in:
parent
c50e4f5e2f
commit
b9697d4a58
@ -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 {
|
|||||||
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
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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) {
|
|||||||
} 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 {
|
|||||||
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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user