diff options
| author | Robert Griesemer <gri@golang.org> | 2010-01-25 10:06:18 -0800 | 
|---|---|---|
| committer | Robert Griesemer <gri@golang.org> | 2010-01-25 10:06:18 -0800 | 
| commit | f35f8245e8341df39e137290d698dadab041d965 (patch) | |
| tree | 847f7bc905fbc291f16f427b0555ce0f760f970f /src | |
| parent | 21f966ea37841047df960b5ad5b65ae2d038bde3 (diff) | |
| download | golang-f35f8245e8341df39e137290d698dadab041d965.tar.gz | |
Scoping snapshot.
- separate parsing from declaration
- setup of correct scopes
R=rsc
CC=golang-dev
http://codereview.appspot.com/189098
Diffstat (limited to 'src')
| -rw-r--r-- | src/pkg/go/ast/Makefile | 2 | ||||
| -rw-r--r-- | src/pkg/go/parser/parser.go | 206 | 
2 files changed, 134 insertions, 74 deletions
| diff --git a/src/pkg/go/ast/Makefile b/src/pkg/go/ast/Makefile index 752e45350..9b5c904c1 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 8f4672320..f5e8f839e 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. | 
