aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2010-01-25 10:06:18 -0800
committerRobert Griesemer <gri@golang.org>2010-01-25 10:06:18 -0800
commitfcf45174232be8a151cacc49efc87f82a0a8145b (patch)
tree8bdb0f2faec1b47f7158c53590bf5f56f3989ca7
parent69e244a104c4ae488c6fa6de9e836b133e4917d8 (diff)
downloadgo-fcf45174232be8a151cacc49efc87f82a0a8145b.tar.gz
go-fcf45174232be8a151cacc49efc87f82a0a8145b.zip
Scoping snapshot.
- separate parsing from declaration - setup of correct scopes R=rsc CC=golang-dev https://golang.org/cl/189098
-rw-r--r--src/pkg/go/ast/Makefile2
-rw-r--r--src/pkg/go/parser/parser.go206
2 files changed, 134 insertions, 74 deletions
diff --git a/src/pkg/go/ast/Makefile b/src/pkg/go/ast/Makefile
index 752e453507..9b5c904c19 100644
--- a/src/pkg/go/ast/Makefile
+++ b/src/pkg/go/ast/Makefile
@@ -7,8 +7,8 @@ include ../../../Make.$(GOARCH)
TARG=go/ast
GOFILES=\
ast.go\
- scope.go\
filter.go\
+ scope.go\
walk.go\
include ../../../Make.pkg
diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go
index 8f46723200..f5e8f839eb 100644
--- a/src/pkg/go/parser/parser.go
+++ b/src/pkg/go/parser/parser.go
@@ -63,7 +63,7 @@ type parser struct {
// Scopes
pkgScope *ast.Scope
fileScope *ast.Scope
- topScope *ast.Scope
+ funcScope *ast.Scope
}
@@ -82,6 +82,8 @@ func (p *parser) init(filename string, src []byte, mode uint) {
p.mode = mode
p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently)
p.check = mode&CheckSemantics != 0 // for convenience (p.check is used frequently)
+ p.pkgScope = ast.NewScope(nil) // TODO(gri) should probably provide the pkgScope from outside
+ p.fileScope = ast.NewScope(p.pkgScope)
p.next()
}
@@ -273,44 +275,19 @@ func (p *parser) expectSemi() {
// ----------------------------------------------------------------------------
// Scope support
-// Usage pattern: defer closeScope(openScope(p));
-func openScope(p *parser) *parser {
- p.topScope = ast.NewScope(p.topScope)
- return p
+func (p *parser) openScope() *ast.Scope {
+ p.funcScope = ast.NewScope(p.funcScope)
+ return p.funcScope
}
-func closeScope(p *parser) { p.topScope = p.topScope.Outer }
+func (p *parser) closeScope() { p.funcScope = p.funcScope.Outer }
func (p *parser) parseIdent(kind ast.ObjKind) *ast.Ident {
- obj := ast.NewObj(ast.Err, p.pos, "")
- if p.tok == token.IDENT {
- obj.Name = string(p.lit)
- p.next()
- } else {
- p.expect(token.IDENT) // use expect() error handling
- }
- return &ast.Ident{obj.Pos, obj}
-}
-
-
-// TODO(gri) Separate parsing from declaration since an identifier's
-// scope often starts only after the type has been seen.
-func (p *parser) declIdent(kind ast.ObjKind) *ast.Ident {
- obj := ast.NewObj(kind, p.pos, "")
+ obj := ast.NewObj(kind, p.pos, "_")
if p.tok == token.IDENT {
obj.Name = string(p.lit)
- // TODO(gri) Consider reversing the conditionals below:
- // always do the declaration but only report
- // error if enabled (may be necessary to get
- // search functionality in the presence of
- // incorrect files).
- if p.check && !p.topScope.Declare(obj) {
- // TODO(gri) Declare could return already-declared
- // object for a very good error message.
- p.Error(obj.Pos, "'"+obj.Name+"' declared already")
- }
p.next()
} else {
p.expect(token.IDENT) // use expect() error handling
@@ -319,18 +296,16 @@ func (p *parser) declIdent(kind ast.ObjKind) *ast.Ident {
}
-// TODO(gri) Separate parsing from declaration since an identifier's
-// scope often starts only after the type has been seen.
-func (p *parser) declIdentList(kind ast.ObjKind) []*ast.Ident {
+func (p *parser) parseIdentList(kind ast.ObjKind) []*ast.Ident {
if p.trace {
defer un(trace(p, "IdentList"))
}
var list vector.Vector
- list.Push(p.declIdent(kind))
+ list.Push(p.parseIdent(kind))
for p.tok == token.COMMA {
p.next()
- list.Push(p.declIdent(kind))
+ list.Push(p.parseIdent(kind))
}
// convert vector
@@ -343,18 +318,43 @@ func (p *parser) declIdentList(kind ast.ObjKind) []*ast.Ident {
}
+func (p *parser) declIdent(scope *ast.Scope, id *ast.Ident) {
+ ok := scope.Declare(id.Obj)
+ if p.check && !ok {
+ p.Error(id.Pos(), "'"+id.Name()+"' declared already")
+ }
+}
+
+
+func (p *parser) declIdentList(scope *ast.Scope, list []*ast.Ident) {
+ for _, id := range list {
+ p.declIdent(scope, id)
+ }
+}
+
+
+func (p *parser) declFieldList(scope *ast.Scope, list []*ast.Field) {
+ for _, f := range list {
+ p.declIdentList(scope, f.Names)
+ }
+}
+
+
func (p *parser) findIdent() *ast.Ident {
pos := p.pos
name := ""
var obj *ast.Object
if p.tok == token.IDENT {
name = string(p.lit)
- obj = p.topScope.Lookup(name)
+ obj = p.funcScope.Lookup(name)
p.next()
} else {
p.expect(token.IDENT) // use expect() error handling
}
if obj == nil {
+ // TODO(gri) These identifiers need to be tracked as
+ // unresolved identifiers in the package
+ // scope so that they can be resolved later.
obj = ast.NewObj(ast.Err, pos, name)
}
return &ast.Ident{pos, obj}
@@ -539,6 +539,9 @@ func (p *parser) parseStructType() *ast.StructType {
fields[i] = x.(*ast.Field)
}
+ // TODO(gri) The struct scope shouldn't get lost.
+ p.declFieldList(ast.NewScope(nil), fields)
+
return &ast.StructType{pos, lbrace, fields, rbrace, false}
}
@@ -619,7 +622,7 @@ func (p *parser) parseParameterList(ellipsisOk bool) []*ast.Field {
}
for p.tok != token.RPAREN && p.tok != token.EOF {
- idents := p.declIdentList(ast.Var)
+ idents := p.parseIdentList(ast.Var)
typ := p.parseParameterType(ellipsisOk)
list.Push(&ast.Field{nil, idents, typ, nil, nil})
if p.tok != token.COMMA {
@@ -646,32 +649,31 @@ func (p *parser) parseParameterList(ellipsisOk bool) []*ast.Field {
}
-func (p *parser) parseParameters(ellipsisOk bool) []*ast.Field {
+func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) []*ast.Field {
if p.trace {
defer un(trace(p, "Parameters"))
}
var params []*ast.Field
p.expect(token.LPAREN)
- openScope(p)
if p.tok != token.RPAREN {
params = p.parseParameterList(ellipsisOk)
+ p.declFieldList(scope, params)
}
- closeScope(p)
p.expect(token.RPAREN)
return params
}
-func (p *parser) parseResult() []*ast.Field {
+func (p *parser) parseResult(scope *ast.Scope) []*ast.Field {
if p.trace {
defer un(trace(p, "Result"))
}
var results []*ast.Field
if p.tok == token.LPAREN {
- results = p.parseParameters(false)
+ results = p.parseParameters(scope, false)
} else if p.tok != token.FUNC {
typ := p.tryType()
if typ != nil {
@@ -684,27 +686,28 @@ func (p *parser) parseResult() []*ast.Field {
}
-func (p *parser) parseSignature() (params []*ast.Field, results []*ast.Field) {
+func (p *parser) parseSignature(scope *ast.Scope) (params []*ast.Field, results []*ast.Field) {
if p.trace {
defer un(trace(p, "Signature"))
}
- params = p.parseParameters(true)
- results = p.parseResult()
+ params = p.parseParameters(scope, true)
+ results = p.parseResult(scope)
return
}
-func (p *parser) parseFuncType() *ast.FuncType {
+func (p *parser) parseFuncType() (*ast.Scope, *ast.FuncType) {
if p.trace {
defer un(trace(p, "FuncType"))
}
pos := p.expect(token.FUNC)
- params, results := p.parseSignature()
+ scope := ast.NewScope(p.funcScope)
+ params, results := p.parseSignature(scope)
- return &ast.FuncType{pos, params, results}
+ return scope, &ast.FuncType{pos, params, results}
}
@@ -720,7 +723,7 @@ func (p *parser) parseMethodSpec() *ast.Field {
if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN {
// method
idents = []*ast.Ident{ident}
- params, results := p.parseSignature()
+ params, results := p.parseSignature(ast.NewScope(p.funcScope))
typ = &ast.FuncType{noPos, params, results}
} else {
// embedded interface
@@ -751,6 +754,9 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
methods[i] = x.(*ast.Field)
}
+ // TODO(gri) The interface scope shouldn't get lost.
+ p.declFieldList(ast.NewScope(nil), methods)
+
return &ast.InterfaceType{pos, lbrace, methods, rbrace, false}
}
@@ -805,7 +811,8 @@ func (p *parser) tryRawType(ellipsisOk bool) ast.Expr {
case token.MUL:
return p.parsePointerType()
case token.FUNC:
- return p.parseFuncType()
+ _, typ := p.parseFuncType()
+ return typ
case token.INTERFACE:
return p.parseInterfaceType()
case token.MAP:
@@ -854,12 +861,31 @@ func (p *parser) parseStmtList() []ast.Stmt {
}
+func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
+ if p.trace {
+ defer un(trace(p, "Body"))
+ }
+
+ savedScope := p.funcScope
+ p.funcScope = scope
+
+ lbrace := p.expect(token.LBRACE)
+ list := p.parseStmtList()
+ rbrace := p.expect(token.RBRACE)
+
+ p.funcScope = savedScope
+
+ return &ast.BlockStmt{lbrace, list, rbrace}
+}
+
+
func (p *parser) parseBlockStmt() *ast.BlockStmt {
if p.trace {
defer un(trace(p, "BlockStmt"))
}
- defer closeScope(openScope(p))
+ p.openScope()
+ defer p.closeScope()
lbrace := p.expect(token.LBRACE)
list := p.parseStmtList()
@@ -877,14 +903,14 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
defer un(trace(p, "FuncTypeOrLit"))
}
- typ := p.parseFuncType()
+ scope, typ := p.parseFuncType()
if p.tok != token.LBRACE {
// function type only
return typ
}
p.exprLev++
- body := p.parseBlockStmt()
+ body := p.parseBody(scope)
p.exprLev--
return &ast.FuncLit{typ, body}
@@ -1418,7 +1444,8 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
}
// IfStmt block
- defer closeScope(openScope(p))
+ p.openScope()
+ defer p.closeScope()
pos := p.expect(token.IF)
s1, s2, _ := p.parseControlClause(false)
@@ -1441,7 +1468,8 @@ func (p *parser) parseCaseClause() *ast.CaseClause {
}
// CaseClause block
- defer closeScope(openScope(p))
+ p.openScope()
+ defer p.closeScope()
// SwitchCase
pos := p.pos
@@ -1482,7 +1510,8 @@ func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
}
// TypeCaseClause block
- defer closeScope(openScope(p))
+ p.openScope()
+ defer p.closeScope()
// TypeSwitchCase
pos := p.pos
@@ -1521,7 +1550,8 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
}
// SwitchStmt block
- defer closeScope(openScope(p))
+ p.openScope()
+ defer p.closeScope()
pos := p.expect(token.SWITCH)
s1, s2, _ := p.parseControlClause(false)
@@ -1558,7 +1588,8 @@ func (p *parser) parseCommClause() *ast.CommClause {
}
// CommClause block
- defer closeScope(openScope(p))
+ p.openScope()
+ defer p.closeScope()
// CommCase
pos := p.pos
@@ -1621,7 +1652,8 @@ func (p *parser) parseForStmt() ast.Stmt {
}
// ForStmt block
- defer closeScope(openScope(p))
+ p.openScope()
+ defer p.closeScope()
pos := p.expect(token.FOR)
s1, s2, s3 := p.parseControlClause(true)
@@ -1740,7 +1772,8 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
ident = &ast.Ident{p.pos, ast.NewObj(ast.Pkg, p.pos, ".")}
p.next()
} else if p.tok == token.IDENT {
- ident = p.declIdent(ast.Pkg)
+ ident = p.parseIdent(ast.Pkg)
+ p.declIdent(p.fileScope, ident)
}
var path []*ast.BasicLit
@@ -1762,13 +1795,23 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
defer un(trace(p, "ConstSpec"))
}
- idents := p.declIdentList(ast.Con)
+ idents := p.parseIdentList(ast.Con)
+ if p.funcScope == nil {
+ // the scope of a constant outside any function
+ // is the package scope
+ p.declIdentList(p.pkgScope, idents)
+ }
typ := p.tryType()
var values []ast.Expr
if typ != nil || p.tok == token.ASSIGN {
p.expect(token.ASSIGN)
values = p.parseExprList()
}
+ if p.funcScope != nil {
+ // the scope of a constant inside a function
+ // begins after the the ConstSpec
+ p.declIdentList(p.funcScope, idents)
+ }
p.expectSemi()
return &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
@@ -1780,7 +1823,15 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
defer un(trace(p, "TypeSpec"))
}
- ident := p.declIdent(ast.Typ)
+ ident := p.parseIdent(ast.Typ)
+ // the scope of a type outside any function is
+ // the package scope; the scope of a type inside
+ // a function starts at the type identifier
+ scope := p.funcScope
+ if scope == nil {
+ scope = p.pkgScope
+ }
+ p.declIdent(scope, ident)
typ := p.parseType()
p.expectSemi()
@@ -1793,13 +1844,23 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
defer un(trace(p, "VarSpec"))
}
- idents := p.declIdentList(ast.Var)
+ idents := p.parseIdentList(ast.Var)
+ if p.funcScope == nil {
+ // the scope of a variable outside any function
+ // is the pkgScope
+ p.declIdentList(p.pkgScope, idents)
+ }
typ := p.tryType()
var values []ast.Expr
if typ == nil || p.tok == token.ASSIGN {
p.expect(token.ASSIGN)
values = p.parseExprList()
}
+ if p.funcScope != nil {
+ // the scope of a variable inside a function
+ // begins after the the VarSpec
+ p.declIdentList(p.funcScope, idents)
+ }
p.expectSemi()
return &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
@@ -1837,13 +1898,13 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
}
-func (p *parser) parseReceiver() *ast.Field {
+func (p *parser) parseReceiver(scope *ast.Scope) *ast.Field {
if p.trace {
defer un(trace(p, "Receiver"))
}
pos := p.pos
- par := p.parseParameters(false)
+ par := p.parseParameters(scope, false)
// must have exactly one receiver
if len(par) != 1 || len(par) == 1 && len(par[0].Names) > 1 {
@@ -1873,18 +1934,20 @@ func (p *parser) parseFunctionDecl() *ast.FuncDecl {
doc := p.leadComment
pos := p.expect(token.FUNC)
+ scope := ast.NewScope(p.funcScope)
var recv *ast.Field
if p.tok == token.LPAREN {
- recv = p.parseReceiver()
+ recv = p.parseReceiver(scope)
}
- ident := p.declIdent(ast.Fun)
- params, results := p.parseSignature()
+ ident := p.parseIdent(ast.Fun)
+ p.declIdent(p.pkgScope, ident) // there are no local function declarations
+ params, results := p.parseSignature(scope)
var body *ast.BlockStmt
if p.tok == token.LBRACE {
- body = p.parseBlockStmt()
+ body = p.parseBody(scope)
}
p.expectSemi()
@@ -1957,9 +2020,6 @@ func (p *parser) parseFile() *ast.File {
ident := p.parseIdent(ast.Pkg) // package name is in no scope
p.expectSemi()
- // file block
- defer closeScope(openScope(p))
-
var decls []ast.Decl
// Don't bother parsing the rest if we had errors already.