diff --git a/src/pkg/go/ast/Makefile b/src/pkg/go/ast/Makefile index 752e4535077..9b5c904c19f 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 8f46723200f..f5e8f839eb1 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,18 +275,17 @@ 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, "") + obj := ast.NewObj(kind, p.pos, "_") if p.tok == token.IDENT { obj.Name = string(p.lit) p.next() @@ -295,42 +296,16 @@ func (p *parser) parseIdent(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) declIdent(kind ast.ObjKind) *ast.Ident { - 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 - } - 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) 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.