diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-04-26 09:55:32 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-04-26 09:55:32 +0200 |
commit | 7b15ed9ef455b6b66c6b376898a88aef5d6a9970 (patch) | |
tree | 3ef530baa80cdf29436ba981f5783be6b4d2202b /src/pkg/go/parser/parser.go | |
parent | 50104cc32a498f7517a51c8dc93106c51c7a54b4 (diff) | |
download | golang-7b15ed9ef455b6b66c6b376898a88aef5d6a9970.tar.gz |
Imported Upstream version 2011.04.13upstream/2011.04.13
Diffstat (limited to 'src/pkg/go/parser/parser.go')
-rw-r--r-- | src/pkg/go/parser/parser.go | 696 |
1 files changed, 502 insertions, 194 deletions
diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go index 7c5843f36..84a0da6ae 100644 --- a/src/pkg/go/parser/parser.go +++ b/src/pkg/go/parser/parser.go @@ -17,10 +17,6 @@ import ( ) -// noPos is used when there is no corresponding source position for a token. -var noPos token.Position - - // The mode parameter to the Parse* functions is a set of flags (or 0). // They control the amount of source code parsed and other optional // parser functionality. @@ -30,6 +26,7 @@ const ( ImportsOnly // parsing stops after import declarations ParseComments // parse comments and add them to AST Trace // print a trace of parsed productions + DeclarationErrors // report declaration errors ) @@ -46,16 +43,27 @@ type parser struct { // Comments comments []*ast.CommentGroup - leadComment *ast.CommentGroup // the last lead comment - lineComment *ast.CommentGroup // the last line comment + leadComment *ast.CommentGroup // last lead comment + lineComment *ast.CommentGroup // last line comment // Next token pos token.Pos // token position tok token.Token // one token look-ahead - lit []byte // token literal + lit string // token literal // Non-syntactic parser control exprLev int // < 0: in control clause, >= 0: in expression + + // Ordinary identifer scopes + pkgScope *ast.Scope // pkgScope.Outer == nil + topScope *ast.Scope // top-most scope; may be pkgScope + unresolved []*ast.Ident // unresolved identifiers + imports []*ast.ImportSpec // list of imports + + // Label scope + // (maintained by open/close LabelScope) + labelScope *ast.Scope // label scope for current function + targetStack [][]*ast.Ident // stack of unresolved labels } @@ -72,9 +80,133 @@ func scannerMode(mode uint) uint { func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uint) { p.file = fset.AddFile(filename, fset.Base(), len(src)) p.scanner.Init(p.file, src, p, scannerMode(mode)) + p.mode = mode p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently) + p.next() + + // set up the pkgScope here (as opposed to in parseFile) because + // there are other parser entry points (ParseExpr, etc.) + p.openScope() + p.pkgScope = p.topScope + + // for the same reason, set up a label scope + p.openLabelScope() +} + + +// ---------------------------------------------------------------------------- +// Scoping support + +func (p *parser) openScope() { + p.topScope = ast.NewScope(p.topScope) +} + + +func (p *parser) closeScope() { + p.topScope = p.topScope.Outer +} + + +func (p *parser) openLabelScope() { + p.labelScope = ast.NewScope(p.labelScope) + p.targetStack = append(p.targetStack, nil) +} + + +func (p *parser) closeLabelScope() { + // resolve labels + n := len(p.targetStack) - 1 + scope := p.labelScope + for _, ident := range p.targetStack[n] { + ident.Obj = scope.Lookup(ident.Name) + if ident.Obj == nil && p.mode&DeclarationErrors != 0 { + p.error(ident.Pos(), fmt.Sprintf("label %s undefined", ident.Name)) + } + } + // pop label scope + p.targetStack = p.targetStack[0:n] + p.labelScope = p.labelScope.Outer +} + + +func (p *parser) declare(decl interface{}, scope *ast.Scope, kind ast.ObjKind, idents ...*ast.Ident) { + for _, ident := range idents { + assert(ident.Obj == nil, "identifier already declared or resolved") + if ident.Name != "_" { + obj := ast.NewObj(kind, ident.Name) + // remember the corresponding declaration for redeclaration + // errors and global variable resolution/typechecking phase + obj.Decl = decl + if alt := scope.Insert(obj); alt != nil && p.mode&DeclarationErrors != 0 { + prevDecl := "" + if pos := alt.Pos(); pos.IsValid() { + prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", p.file.Position(pos)) + } + p.error(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl)) + } + ident.Obj = obj + } + } +} + + +func (p *parser) shortVarDecl(idents []*ast.Ident) { + // 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") + if ident.Name != "_" { + 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 + alt := p.topScope.Insert(obj) + if alt == nil { + n++ // new declaration + alt = obj + } + ident.Obj = alt + } + } + if n == 0 && p.mode&DeclarationErrors != 0 { + p.error(idents[0].Pos(), "no new variables on left side of :=") + } +} + + +// The unresolved object is a sentinel to mark identifiers that have been added +// to the list of unresolved identifiers. The sentinel is only used for verifying +// internal consistency. +var unresolved = new(ast.Object) + + +func (p *parser) resolve(x ast.Expr) { + // nothing to do if x is not an identifier or the blank identifier + ident, _ := x.(*ast.Ident) + if ident == nil { + return + } + assert(ident.Obj == nil, "identifier already declared or resolved") + if ident.Name == "_" { + return + } + // try to resolve the identifier + for s := p.topScope; s != nil; s = s.Outer { + if obj := s.Lookup(ident.Name); obj != nil { + ident.Obj = obj + return + } + } + // all local scopes are known, so any unresolved identifier + // must be found either in the file scope, package scope + // (perhaps in another file), or universe scope --- collect + // them so that they can be resolved later + ident.Obj = unresolved + p.unresolved = append(p.unresolved, ident) } @@ -120,7 +252,7 @@ func (p *parser) next0() { s := p.tok.String() switch { case p.tok.IsLiteral(): - p.printTrace(s, string(p.lit)) + p.printTrace(s, p.lit) case p.tok.IsOperator(), p.tok.IsKeyword(): p.printTrace("\"" + s + "\"") default: @@ -137,8 +269,9 @@ func (p *parser) consumeComment() (comment *ast.Comment, endline int) { // Scan the comment for '\n' chars and adjust endline accordingly. endline = p.file.Line(p.pos) if p.lit[1] == '*' { - for _, b := range p.lit { - if b == '\n' { + // don't use range here - no need to decode Unicode code points + for i := 0; i < len(p.lit); i++ { + if p.lit[i] == '\n' { endline++ } } @@ -199,7 +332,7 @@ func (p *parser) next() { var endline int if p.file.Line(p.pos) == line { - // The comment is on same line as previous token; it + // The comment is on same line as the previous token; it // cannot be a lead comment but may be a line comment. comment, endline = p.consumeCommentGroup() if p.file.Line(p.pos) != endline { @@ -239,7 +372,7 @@ func (p *parser) errorExpected(pos token.Pos, msg string) { } else { msg += ", found '" + p.tok.String() + "'" if p.tok.IsLiteral() { - msg += " " + string(p.lit) + msg += " " + p.lit } } } @@ -264,6 +397,13 @@ func (p *parser) expectSemi() { } +func assert(cond bool, msg string) { + if !cond { + panic("go/parser internal error: " + msg) + } +} + + // ---------------------------------------------------------------------------- // Identifiers @@ -271,7 +411,7 @@ func (p *parser) parseIdent() *ast.Ident { pos := p.pos name := "_" if p.tok == token.IDENT { - name = string(p.lit) + name = p.lit p.next() } else { p.expect(token.IDENT) // use expect() error handling @@ -298,21 +438,51 @@ func (p *parser) parseIdentList() (list []*ast.Ident) { // ---------------------------------------------------------------------------- // Common productions -func (p *parser) parseExprList() (list []ast.Expr) { +// If lhs is set, result list elements which are identifiers are not resolved. +func (p *parser) parseExprList(lhs bool) (list []ast.Expr) { if p.trace { defer un(trace(p, "ExpressionList")) } - list = append(list, p.parseExpr()) + list = append(list, p.parseExpr(lhs)) for p.tok == token.COMMA { p.next() - list = append(list, p.parseExpr()) + list = append(list, p.parseExpr(lhs)) } return } +func (p *parser) parseLhsList() []ast.Expr { + list := p.parseExprList(true) + switch p.tok { + case token.DEFINE: + // lhs of a short variable declaration + p.shortVarDecl(p.makeIdentList(list)) + case token.COLON: + // lhs of a label declaration or a communication clause of a select + // statement (parseLhsList is not called when parsing the case clause + // of a switch statement): + // - labels are declared by the caller of parseLhsList + // - for communication clauses, if there is a stand-alone identifier + // followed by a colon, we have a syntax error; there is no need + // to resolve the identifier in that case + default: + // identifiers must be declared elsewhere + for _, x := range list { + p.resolve(x) + } + } + return list +} + + +func (p *parser) parseRhsList() []ast.Expr { + return p.parseExprList(false) +} + + // ---------------------------------------------------------------------------- // Types @@ -334,28 +504,24 @@ func (p *parser) parseType() ast.Expr { } -func (p *parser) parseQualifiedIdent() ast.Expr { +// If the result is an identifier, it is not resolved. +func (p *parser) parseTypeName() ast.Expr { if p.trace { - defer un(trace(p, "QualifiedIdent")) + defer un(trace(p, "TypeName")) } - var x ast.Expr = p.parseIdent() + ident := p.parseIdent() + // don't resolve ident yet - it may be a parameter or field name + if p.tok == token.PERIOD { - // first identifier is a package identifier + // ident is a package name p.next() + p.resolve(ident) sel := p.parseIdent() - x = &ast.SelectorExpr{x, sel} - } - return x -} - - -func (p *parser) parseTypeName() ast.Expr { - if p.trace { - defer un(trace(p, "TypeName")) + return &ast.SelectorExpr{ident, sel} } - return p.parseQualifiedIdent() + return ident } @@ -370,7 +536,7 @@ func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr { len = &ast.Ellipsis{p.pos, nil} p.next() } else if p.tok != token.RBRACK { - len = p.parseExpr() + len = p.parseRhs() } p.expect(token.RBRACK) elt := p.parseType() @@ -394,7 +560,7 @@ func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident { } -func (p *parser) parseFieldDecl() *ast.Field { +func (p *parser) parseFieldDecl(scope *ast.Scope) *ast.Field { if p.trace { defer un(trace(p, "FieldDecl")) } @@ -419,6 +585,7 @@ func (p *parser) parseFieldDecl() *ast.Field { } else { // ["*"] TypeName (AnonymousField) typ = list[0] // we always have at least one element + p.resolve(typ) if n := len(list); n > 1 || !isTypeName(deref(typ)) { pos := typ.Pos() p.errorExpected(pos, "anonymous field") @@ -426,9 +593,12 @@ func (p *parser) parseFieldDecl() *ast.Field { } } - p.expectSemi() + p.expectSemi() // call before accessing p.linecomment + + field := &ast.Field{doc, idents, typ, tag, p.lineComment} + p.declare(field, scope, ast.Var, idents...) - return &ast.Field{doc, idents, typ, tag, p.lineComment} + return field } @@ -439,15 +609,17 @@ func (p *parser) parseStructType() *ast.StructType { pos := p.expect(token.STRUCT) lbrace := p.expect(token.LBRACE) + scope := ast.NewScope(nil) // struct scope var list []*ast.Field for p.tok == token.IDENT || p.tok == token.MUL || p.tok == token.LPAREN { // a field declaration cannot start with a '(' but we accept // it here for more robust parsing and better error messages // (parseFieldDecl will check and complain if necessary) - list = append(list, p.parseFieldDecl()) + list = append(list, p.parseFieldDecl(scope)) } rbrace := p.expect(token.RBRACE) + // TODO(gri): store struct scope in AST return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false} } @@ -468,7 +640,7 @@ func (p *parser) tryVarType(isParam bool) ast.Expr { if isParam && p.tok == token.ELLIPSIS { pos := p.pos p.next() - typ := p.tryType() // don't use parseType so we can provide better error message + typ := p.tryIdentOrType(isParam) // don't use parseType so we can provide better error message if typ == nil { p.error(pos, "'...' parameter is missing type") typ = &ast.BadExpr{pos, p.pos} @@ -478,7 +650,7 @@ func (p *parser) tryVarType(isParam bool) ast.Expr { } return &ast.Ellipsis{pos, typ} } - return p.tryType() + return p.tryIdentOrType(false) } @@ -514,12 +686,15 @@ func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) { // if we had a list of identifiers, it must be followed by a type typ = p.tryVarType(isParam) + if typ != nil { + p.resolve(typ) + } return } -func (p *parser) parseParameterList(ellipsisOk bool) (params []*ast.Field) { +func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params []*ast.Field) { if p.trace { defer un(trace(p, "ParameterList")) } @@ -528,7 +703,11 @@ func (p *parser) parseParameterList(ellipsisOk bool) (params []*ast.Field) { if typ != nil { // IdentifierList Type idents := p.makeIdentList(list) - params = append(params, &ast.Field{nil, idents, typ, nil, nil}) + field := &ast.Field{nil, idents, typ, nil, nil} + params = append(params, field) + // Go spec: The scope of an identifier denoting a function + // parameter or result variable is the function body. + p.declare(field, scope, ast.Var, idents...) if p.tok == token.COMMA { p.next() } @@ -536,7 +715,11 @@ func (p *parser) parseParameterList(ellipsisOk bool) (params []*ast.Field) { for p.tok != token.RPAREN && p.tok != token.EOF { idents := p.parseIdentList() typ := p.parseVarType(ellipsisOk) - params = append(params, &ast.Field{nil, idents, typ, nil, nil}) + field := &ast.Field{nil, idents, typ, nil, nil} + params = append(params, field) + // Go spec: The scope of an identifier denoting a function + // parameter or result variable is the function body. + p.declare(field, scope, ast.Var, idents...) if p.tok != token.COMMA { break } @@ -547,6 +730,7 @@ func (p *parser) parseParameterList(ellipsisOk bool) (params []*ast.Field) { // Type { "," Type } (anonymous parameters) params = make([]*ast.Field, len(list)) for i, x := range list { + p.resolve(x) params[i] = &ast.Field{Type: x} } } @@ -555,7 +739,7 @@ func (p *parser) parseParameterList(ellipsisOk bool) (params []*ast.Field) { } -func (p *parser) parseParameters(ellipsisOk bool) *ast.FieldList { +func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldList { if p.trace { defer un(trace(p, "Parameters")) } @@ -563,7 +747,7 @@ func (p *parser) parseParameters(ellipsisOk bool) *ast.FieldList { var params []*ast.Field lparen := p.expect(token.LPAREN) if p.tok != token.RPAREN { - params = p.parseParameterList(ellipsisOk) + params = p.parseParameterList(scope, ellipsisOk) } rparen := p.expect(token.RPAREN) @@ -571,13 +755,13 @@ func (p *parser) parseParameters(ellipsisOk bool) *ast.FieldList { } -func (p *parser) parseResult() *ast.FieldList { +func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList { if p.trace { defer un(trace(p, "Result")) } if p.tok == token.LPAREN { - return p.parseParameters(false) + return p.parseParameters(scope, false) } typ := p.tryType() @@ -591,31 +775,32 @@ func (p *parser) parseResult() *ast.FieldList { } -func (p *parser) parseSignature() (params, results *ast.FieldList) { +func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldList) { 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.FuncType, *ast.Scope) { if p.trace { defer un(trace(p, "FuncType")) } pos := p.expect(token.FUNC) - params, results := p.parseSignature() + scope := ast.NewScope(p.topScope) // function scope + params, results := p.parseSignature(scope) - return &ast.FuncType{pos, params, results} + return &ast.FuncType{pos, params, results}, scope } -func (p *parser) parseMethodSpec() *ast.Field { +func (p *parser) parseMethodSpec(scope *ast.Scope) *ast.Field { if p.trace { defer un(trace(p, "MethodSpec")) } @@ -623,19 +808,23 @@ func (p *parser) parseMethodSpec() *ast.Field { doc := p.leadComment var idents []*ast.Ident var typ ast.Expr - x := p.parseQualifiedIdent() + x := p.parseTypeName() if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN { // method idents = []*ast.Ident{ident} - params, results := p.parseSignature() + scope := ast.NewScope(nil) // method scope + params, results := p.parseSignature(scope) typ = &ast.FuncType{token.NoPos, params, results} } else { // embedded interface typ = x } - p.expectSemi() + p.expectSemi() // call before accessing p.linecomment - return &ast.Field{doc, idents, typ, nil, p.lineComment} + spec := &ast.Field{doc, idents, typ, nil, p.lineComment} + p.declare(spec, scope, ast.Fun, idents...) + + return spec } @@ -646,12 +835,14 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType { pos := p.expect(token.INTERFACE) lbrace := p.expect(token.LBRACE) + scope := ast.NewScope(nil) // interface scope var list []*ast.Field for p.tok == token.IDENT { - list = append(list, p.parseMethodSpec()) + list = append(list, p.parseMethodSpec(scope)) } rbrace := p.expect(token.RBRACE) + // TODO(gri): store interface scope in AST return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false} } @@ -695,7 +886,8 @@ func (p *parser) parseChanType() *ast.ChanType { } -func (p *parser) tryRawType(ellipsisOk bool) ast.Expr { +// If the result is an identifier, it is not resolved. +func (p *parser) tryIdentOrType(ellipsisOk bool) ast.Expr { switch p.tok { case token.IDENT: return p.parseTypeName() @@ -706,7 +898,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: @@ -726,7 +919,13 @@ func (p *parser) tryRawType(ellipsisOk bool) ast.Expr { } -func (p *parser) tryType() ast.Expr { return p.tryRawType(false) } +func (p *parser) tryType() ast.Expr { + typ := p.tryIdentOrType(false) + if typ != nil { + p.resolve(typ) + } + return typ +} // ---------------------------------------------------------------------------- @@ -745,13 +944,17 @@ func (p *parser) parseStmtList() (list []ast.Stmt) { } -func (p *parser) parseBody() *ast.BlockStmt { +func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt { if p.trace { defer un(trace(p, "Body")) } lbrace := p.expect(token.LBRACE) + p.topScope = scope // open function scope + p.openLabelScope() list := p.parseStmtList() + p.closeLabelScope() + p.closeScope() rbrace := p.expect(token.RBRACE) return &ast.BlockStmt{lbrace, list, rbrace} @@ -764,7 +967,9 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt { } lbrace := p.expect(token.LBRACE) + p.openScope() list := p.parseStmtList() + p.closeScope() rbrace := p.expect(token.RBRACE) return &ast.BlockStmt{lbrace, list, rbrace} @@ -779,14 +984,14 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr { defer un(trace(p, "FuncTypeOrLit")) } - typ := p.parseFuncType() + typ, scope := p.parseFuncType() if p.tok != token.LBRACE { // function type only return typ } p.exprLev++ - body := p.parseBody() + body := p.parseBody(scope) p.exprLev-- return &ast.FuncLit{typ, body} @@ -795,15 +1000,20 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr { // parseOperand may return an expression or a raw type (incl. array // types of the form [...]T. Callers must verify the result. +// If lhs is set and the result is an identifier, it is not resolved. // -func (p *parser) parseOperand() ast.Expr { +func (p *parser) parseOperand(lhs bool) ast.Expr { if p.trace { defer un(trace(p, "Operand")) } switch p.tok { case token.IDENT: - return p.parseIdent() + x := p.parseIdent() + if !lhs { + p.resolve(x) + } + return x case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING: x := &ast.BasicLit{p.pos, p.tok, p.lit} @@ -814,7 +1024,7 @@ func (p *parser) parseOperand() ast.Expr { lparen := p.pos p.next() p.exprLev++ - x := p.parseExpr() + x := p.parseRhs() p.exprLev-- rparen := p.expect(token.RPAREN) return &ast.ParenExpr{lparen, x, rparen} @@ -823,9 +1033,11 @@ func (p *parser) parseOperand() ast.Expr { return p.parseFuncTypeOrLit() default: - t := p.tryRawType(true) // could be type for composite literal or conversion - if t != nil { - return t + if typ := p.tryIdentOrType(true); typ != nil { + // could be type for composite literal or conversion + _, isIdent := typ.(*ast.Ident) + assert(!isIdent, "type cannot be identifier") + return typ } } @@ -836,19 +1048,22 @@ func (p *parser) parseOperand() ast.Expr { } -func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr { +func (p *parser) parseSelector(x ast.Expr) ast.Expr { if p.trace { - defer un(trace(p, "SelectorOrTypeAssertion")) + defer un(trace(p, "Selector")) } - p.expect(token.PERIOD) - if p.tok == token.IDENT { - // selector - sel := p.parseIdent() - return &ast.SelectorExpr{x, sel} + sel := p.parseIdent() + + return &ast.SelectorExpr{x, sel} +} + + +func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr { + if p.trace { + defer un(trace(p, "TypeAssertion")) } - // type assertion p.expect(token.LPAREN) var typ ast.Expr if p.tok == token.TYPE { @@ -873,13 +1088,13 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr { var low, high ast.Expr isSlice := false if p.tok != token.COLON { - low = p.parseExpr() + low = p.parseRhs() } if p.tok == token.COLON { isSlice = true p.next() if p.tok != token.RBRACK { - high = p.parseExpr() + high = p.parseRhs() } } p.exprLev-- @@ -902,7 +1117,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr { var list []ast.Expr var ellipsis token.Pos for p.tok != token.RPAREN && p.tok != token.EOF && !ellipsis.IsValid() { - list = append(list, p.parseExpr()) + list = append(list, p.parseRhs()) if p.tok == token.ELLIPSIS { ellipsis = p.pos p.next() @@ -928,12 +1143,16 @@ func (p *parser) parseElement(keyOk bool) ast.Expr { return p.parseLiteralValue(nil) } - x := p.parseExpr() - if keyOk && p.tok == token.COLON { - colon := p.pos - p.next() - x = &ast.KeyValueExpr{x, colon, p.parseElement(false)} + x := p.parseExpr(keyOk) // don't resolve if map key + if keyOk { + if p.tok == token.COLON { + colon := p.pos + p.next() + return &ast.KeyValueExpr{x, colon, p.parseElement(false)} + } + p.resolve(x) // not a map key } + return x } @@ -1085,23 +1304,47 @@ func (p *parser) checkExprOrType(x ast.Expr) ast.Expr { } -func (p *parser) parsePrimaryExpr() ast.Expr { +// If lhs is set and the result is an identifier, it is not resolved. +func (p *parser) parsePrimaryExpr(lhs bool) ast.Expr { if p.trace { defer un(trace(p, "PrimaryExpr")) } - x := p.parseOperand() + x := p.parseOperand(lhs) L: for { switch p.tok { case token.PERIOD: - x = p.parseSelectorOrTypeAssertion(p.checkExpr(x)) + p.next() + if lhs { + p.resolve(x) + } + switch p.tok { + case token.IDENT: + x = p.parseSelector(p.checkExpr(x)) + case token.LPAREN: + x = p.parseTypeAssertion(p.checkExpr(x)) + default: + pos := p.pos + p.next() // make progress + p.errorExpected(pos, "selector or type assertion") + x = &ast.BadExpr{pos, p.pos} + } case token.LBRACK: + if lhs { + p.resolve(x) + } x = p.parseIndexOrSlice(p.checkExpr(x)) case token.LPAREN: + if lhs { + p.resolve(x) + } x = p.parseCallOrConversion(p.checkExprOrType(x)) case token.LBRACE: if isLiteralType(x) && (p.exprLev >= 0 || !isTypeName(x)) { + if lhs { + p.resolve(x) + } x = p.parseLiteralValue(x) } else { break L @@ -1109,13 +1352,15 @@ L: default: break L } + lhs = false // no need to try to resolve again } return x } -func (p *parser) parseUnaryExpr() ast.Expr { +// If lhs is set and the result is an identifier, it is not resolved. +func (p *parser) parseUnaryExpr(lhs bool) ast.Expr { if p.trace { defer un(trace(p, "UnaryExpr")) } @@ -1124,7 +1369,7 @@ func (p *parser) parseUnaryExpr() ast.Expr { case token.ADD, token.SUB, token.NOT, token.XOR, token.AND, token.RANGE: pos, op := p.pos, p.tok p.next() - x := p.parseUnaryExpr() + x := p.parseUnaryExpr(false) return &ast.UnaryExpr{pos, op, p.checkExpr(x)} case token.ARROW: @@ -1137,32 +1382,37 @@ func (p *parser) parseUnaryExpr() ast.Expr { return &ast.ChanType{pos, ast.RECV, value} } - x := p.parseUnaryExpr() + x := p.parseUnaryExpr(false) return &ast.UnaryExpr{pos, token.ARROW, p.checkExpr(x)} case token.MUL: // pointer type or unary "*" expression pos := p.pos p.next() - x := p.parseUnaryExpr() + x := p.parseUnaryExpr(false) return &ast.StarExpr{pos, p.checkExprOrType(x)} } - return p.parsePrimaryExpr() + return p.parsePrimaryExpr(lhs) } -func (p *parser) parseBinaryExpr(prec1 int) ast.Expr { +// If lhs is set and the result is an identifier, it is not resolved. +func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr { if p.trace { defer un(trace(p, "BinaryExpr")) } - x := p.parseUnaryExpr() + x := p.parseUnaryExpr(lhs) for prec := p.tok.Precedence(); prec >= prec1; prec-- { for p.tok.Precedence() == prec { pos, op := p.pos, p.tok p.next() - y := p.parseBinaryExpr(prec + 1) + if lhs { + p.resolve(x) + lhs = false + } + y := p.parseBinaryExpr(false, prec+1) x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)} } } @@ -1171,14 +1421,20 @@ func (p *parser) parseBinaryExpr(prec1 int) ast.Expr { } +// If lhs is set and the result is an identifier, it is not resolved. // TODO(gri): parseExpr may return a type or even a raw type ([..]int) - // should reject when a type/raw type is obviously not allowed -func (p *parser) parseExpr() ast.Expr { +func (p *parser) parseExpr(lhs bool) ast.Expr { if p.trace { defer un(trace(p, "Expression")) } - return p.parseBinaryExpr(token.LowestPrec + 1) + return p.parseBinaryExpr(lhs, token.LowestPrec+1) +} + + +func (p *parser) parseRhs() ast.Expr { + return p.parseExpr(false) } @@ -1190,7 +1446,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt { defer un(trace(p, "SimpleStmt")) } - x := p.parseExprList() + x := p.parseLhsList() switch p.tok { case @@ -1201,7 +1457,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt { // assignment statement pos, tok := p.pos, p.tok p.next() - y := p.parseExprList() + y := p.parseRhsList() return &ast.AssignStmt{x, pos, tok, y} } @@ -1216,7 +1472,12 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt { colon := p.pos p.next() if label, isIdent := x[0].(*ast.Ident); labelOk && isIdent { - return &ast.LabeledStmt{label, colon, p.parseStmt()} + // Go spec: The scope of a label is the body of the function + // in which it is declared and excludes the body of any nested + // function. + stmt := &ast.LabeledStmt{label, colon, p.parseStmt()} + p.declare(stmt, p.labelScope, ast.Lbl, label) + return stmt } p.error(x[0].Pos(), "illegal label declaration") return &ast.BadStmt{x[0].Pos(), colon + 1} @@ -1225,7 +1486,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt { // send statement arrow := p.pos p.next() // consume "<-" - y := p.parseExpr() + y := p.parseRhs() return &ast.SendStmt{x[0], arrow, y} case token.INC, token.DEC: @@ -1241,7 +1502,7 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt { func (p *parser) parseCallExpr() *ast.CallExpr { - x := p.parseExpr() + x := p.parseRhs() if call, isCall := x.(*ast.CallExpr); isCall { return call } @@ -1291,7 +1552,7 @@ func (p *parser) parseReturnStmt() *ast.ReturnStmt { p.expect(token.RETURN) var x []ast.Expr if p.tok != token.SEMICOLON && p.tok != token.RBRACE { - x = p.parseExprList() + x = p.parseRhsList() } p.expectSemi() @@ -1304,14 +1565,17 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt { defer un(trace(p, "BranchStmt")) } - s := &ast.BranchStmt{p.pos, tok, nil} - p.expect(tok) + pos := p.expect(tok) + var label *ast.Ident if tok != token.FALLTHROUGH && p.tok == token.IDENT { - s.Label = p.parseIdent() + label = p.parseIdent() + // add to list of unresolved targets + n := len(p.targetStack) - 1 + p.targetStack[n] = append(p.targetStack[n], label) } p.expectSemi() - return s + return &ast.BranchStmt{pos, tok, label} } @@ -1333,6 +1597,8 @@ func (p *parser) parseIfStmt() *ast.IfStmt { } pos := p.expect(token.IF) + p.openScope() + defer p.closeScope() var s ast.Stmt var x ast.Expr @@ -1341,12 +1607,12 @@ func (p *parser) parseIfStmt() *ast.IfStmt { p.exprLev = -1 if p.tok == token.SEMICOLON { p.next() - x = p.parseExpr() + x = p.parseRhs() } else { s = p.parseSimpleStmt(false) if p.tok == token.SEMICOLON { p.next() - x = p.parseExpr() + x = p.parseRhs() } else { x = p.makeExpr(s) s = nil @@ -1368,28 +1634,6 @@ func (p *parser) parseIfStmt() *ast.IfStmt { } -func (p *parser) parseCaseClause() *ast.CaseClause { - if p.trace { - defer un(trace(p, "CaseClause")) - } - - // SwitchCase - pos := p.pos - var x []ast.Expr - if p.tok == token.CASE { - p.next() - x = p.parseExprList() - } else { - p.expect(token.DEFAULT) - } - - colon := p.expect(token.COLON) - body := p.parseStmtList() - - return &ast.CaseClause{pos, x, colon, body} -} - - func (p *parser) parseTypeList() (list []ast.Expr) { if p.trace { defer un(trace(p, "TypeList")) @@ -1405,25 +1649,30 @@ func (p *parser) parseTypeList() (list []ast.Expr) { } -func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause { +func (p *parser) parseCaseClause(exprSwitch bool) *ast.CaseClause { if p.trace { - defer un(trace(p, "TypeCaseClause")) + defer un(trace(p, "CaseClause")) } - // TypeSwitchCase pos := p.pos - var types []ast.Expr + var list []ast.Expr if p.tok == token.CASE { p.next() - types = p.parseTypeList() + if exprSwitch { + list = p.parseRhsList() + } else { + list = p.parseTypeList() + } } else { p.expect(token.DEFAULT) } colon := p.expect(token.COLON) + p.openScope() body := p.parseStmtList() + p.closeScope() - return &ast.TypeCaseClause{pos, types, colon, body} + return &ast.CaseClause{pos, list, colon, body} } @@ -1447,6 +1696,8 @@ func (p *parser) parseSwitchStmt() ast.Stmt { } pos := p.expect(token.SWITCH) + p.openScope() + defer p.closeScope() var s1, s2 ast.Stmt if p.tok != token.LBRACE { @@ -1466,28 +1717,21 @@ func (p *parser) parseSwitchStmt() ast.Stmt { p.exprLev = prevLev } - if isExprSwitch(s2) { - lbrace := p.expect(token.LBRACE) - var list []ast.Stmt - for p.tok == token.CASE || p.tok == token.DEFAULT { - list = append(list, p.parseCaseClause()) - } - rbrace := p.expect(token.RBRACE) - body := &ast.BlockStmt{lbrace, list, rbrace} - p.expectSemi() - return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body} - } - - // type switch - // TODO(gri): do all the checks! + exprSwitch := isExprSwitch(s2) lbrace := p.expect(token.LBRACE) var list []ast.Stmt for p.tok == token.CASE || p.tok == token.DEFAULT { - list = append(list, p.parseTypeCaseClause()) + list = append(list, p.parseCaseClause(exprSwitch)) } rbrace := p.expect(token.RBRACE) p.expectSemi() body := &ast.BlockStmt{lbrace, list, rbrace} + + if exprSwitch { + return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body} + } + // type switch + // TODO(gri): do all the checks! return &ast.TypeSwitchStmt{pos, s1, s2, body} } @@ -1497,12 +1741,12 @@ func (p *parser) parseCommClause() *ast.CommClause { defer un(trace(p, "CommClause")) } - // CommCase + p.openScope() pos := p.pos var comm ast.Stmt if p.tok == token.CASE { p.next() - lhs := p.parseExprList() + lhs := p.parseLhsList() if p.tok == token.ARROW { // SendStmt if len(lhs) > 1 { @@ -1511,14 +1755,14 @@ func (p *parser) parseCommClause() *ast.CommClause { } arrow := p.pos p.next() - rhs := p.parseExpr() + rhs := p.parseRhs() comm = &ast.SendStmt{lhs[0], arrow, rhs} } else { // RecvStmt pos := p.pos tok := p.tok var rhs ast.Expr - if p.tok == token.ASSIGN || p.tok == token.DEFINE { + if tok == token.ASSIGN || tok == token.DEFINE { // RecvStmt with assignment if len(lhs) > 2 { p.errorExpected(lhs[0].Pos(), "1 or 2 expressions") @@ -1526,7 +1770,7 @@ func (p *parser) parseCommClause() *ast.CommClause { lhs = lhs[0:2] } p.next() - rhs = p.parseExpr() + rhs = p.parseRhs() } else { // rhs must be single receive operation if len(lhs) > 1 { @@ -1552,6 +1796,7 @@ func (p *parser) parseCommClause() *ast.CommClause { colon := p.expect(token.COLON) body := p.parseStmtList() + p.closeScope() return &ast.CommClause{pos, comm, colon, body} } @@ -1582,6 +1827,8 @@ func (p *parser) parseForStmt() ast.Stmt { } pos := p.expect(token.FOR) + p.openScope() + defer p.closeScope() var s1, s2, s3 ast.Stmt if p.tok != token.LBRACE { @@ -1631,18 +1878,16 @@ func (p *parser) parseForStmt() ast.Stmt { return &ast.BadStmt{pos, body.End()} } if rhs, isUnary := as.Rhs[0].(*ast.UnaryExpr); isUnary && rhs.Op == token.RANGE { - // rhs is range expression; check lhs + // rhs is range expression + // (any short variable declaration was handled by parseSimpleStat above) return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body} - } else { - p.errorExpected(s2.Pos(), "range clause") - return &ast.BadStmt{pos, body.End()} } - } else { - // regular for statement - return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body} + p.errorExpected(s2.Pos(), "range clause") + return &ast.BadStmt{pos, body.End()} } - panic("unreachable") + // regular for statement + return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body} } @@ -1706,19 +1951,20 @@ func (p *parser) parseStmt() (s ast.Stmt) { // ---------------------------------------------------------------------------- // Declarations -type parseSpecFunction func(p *parser, doc *ast.CommentGroup) ast.Spec +type parseSpecFunction func(p *parser, doc *ast.CommentGroup, iota int) ast.Spec -func parseImportSpec(p *parser, doc *ast.CommentGroup) ast.Spec { +func parseImportSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec { if p.trace { defer un(trace(p, "ImportSpec")) } var ident *ast.Ident - if p.tok == token.PERIOD { + switch p.tok { + case token.PERIOD: ident = &ast.Ident{p.pos, ".", nil} p.next() - } else if p.tok == token.IDENT { + case token.IDENT: ident = p.parseIdent() } @@ -1729,13 +1975,17 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup) ast.Spec { } else { p.expect(token.STRING) // use expect() error handling } - p.expectSemi() + p.expectSemi() // call before accessing p.linecomment - return &ast.ImportSpec{doc, ident, path, p.lineComment} + // collect imports + spec := &ast.ImportSpec{doc, ident, path, p.lineComment} + p.imports = append(p.imports, spec) + + return spec } -func parseConstSpec(p *parser, doc *ast.CommentGroup) ast.Spec { +func parseConstSpec(p *parser, doc *ast.CommentGroup, iota int) ast.Spec { if p.trace { defer un(trace(p, "ConstSpec")) } @@ -1743,30 +1993,46 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup) ast.Spec { idents := p.parseIdentList() typ := p.tryType() var values []ast.Expr - if typ != nil || p.tok == token.ASSIGN { + if typ != nil || p.tok == token.ASSIGN || iota == 0 { p.expect(token.ASSIGN) - values = p.parseExprList() + values = p.parseRhsList() } - p.expectSemi() + p.expectSemi() // call before accessing p.linecomment + + // Go spec: The scope of a constant or variable identifier declared inside + // a function begins at the end of the ConstSpec or VarSpec and ends at + // the end of the innermost containing block. + // (Global identifiers are resolved in a separate phase after parsing.) + spec := &ast.ValueSpec{doc, idents, typ, values, p.lineComment} + p.declare(spec, p.topScope, ast.Con, idents...) - return &ast.ValueSpec{doc, idents, typ, values, p.lineComment} + return spec } -func parseTypeSpec(p *parser, doc *ast.CommentGroup) ast.Spec { +func parseTypeSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec { if p.trace { defer un(trace(p, "TypeSpec")) } ident := p.parseIdent() - typ := p.parseType() - p.expectSemi() - return &ast.TypeSpec{doc, ident, typ, p.lineComment} + // Go spec: The scope of a type identifier declared inside a function begins + // at the identifier in the TypeSpec and ends at the end of the innermost + // containing block. + // (Global identifiers are resolved in a separate phase after parsing.) + spec := &ast.TypeSpec{doc, ident, nil, nil} + p.declare(spec, p.topScope, ast.Typ, ident) + + spec.Type = p.parseType() + p.expectSemi() // call before accessing p.linecomment + spec.Comment = p.lineComment + + return spec } -func parseVarSpec(p *parser, doc *ast.CommentGroup) ast.Spec { +func parseVarSpec(p *parser, doc *ast.CommentGroup, _ int) ast.Spec { if p.trace { defer un(trace(p, "VarSpec")) } @@ -1776,11 +2042,18 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup) ast.Spec { var values []ast.Expr if typ == nil || p.tok == token.ASSIGN { p.expect(token.ASSIGN) - values = p.parseExprList() + values = p.parseRhsList() } - p.expectSemi() + p.expectSemi() // call before accessing p.linecomment + + // Go spec: The scope of a constant or variable identifier declared inside + // a function begins at the end of the ConstSpec or VarSpec and ends at + // the end of the innermost containing block. + // (Global identifiers are resolved in a separate phase after parsing.) + spec := &ast.ValueSpec{doc, idents, typ, values, p.lineComment} + p.declare(spec, p.topScope, ast.Var, idents...) - return &ast.ValueSpec{doc, idents, typ, values, p.lineComment} + return spec } @@ -1796,26 +2069,26 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen if p.tok == token.LPAREN { lparen = p.pos p.next() - for p.tok != token.RPAREN && p.tok != token.EOF { - list = append(list, f(p, p.leadComment)) + for iota := 0; p.tok != token.RPAREN && p.tok != token.EOF; iota++ { + list = append(list, f(p, p.leadComment, iota)) } rparen = p.expect(token.RPAREN) p.expectSemi() } else { - list = append(list, f(p, nil)) + list = append(list, f(p, nil, 0)) } return &ast.GenDecl{doc, pos, keyword, lparen, list, rparen} } -func (p *parser) parseReceiver() *ast.FieldList { +func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList { 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 par.NumFields() != 1 { @@ -1844,22 +2117,37 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl { doc := p.leadComment pos := p.expect(token.FUNC) + scope := ast.NewScope(p.topScope) // function scope var recv *ast.FieldList if p.tok == token.LPAREN { - recv = p.parseReceiver() + recv = p.parseReceiver(scope) } ident := p.parseIdent() - params, results := p.parseSignature() + + params, results := p.parseSignature(scope) var body *ast.BlockStmt if p.tok == token.LBRACE { - body = p.parseBody() + body = p.parseBody(scope) } p.expectSemi() - return &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body} + decl := &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body} + if recv == nil { + // Go spec: The scope of an identifier denoting a constant, type, + // variable, or function (but not method) declared at top level + // (outside any function) is the package block. + // + // init() functions cannot be referred to and there may + // be more than one - don't put them in the pkgScope + if ident.Name != "init" { + p.declare(decl, p.pkgScope, ast.Fun, ident) + } + } + + return decl } @@ -1918,7 +2206,12 @@ func (p *parser) parseFile() *ast.File { // package clause doc := p.leadComment pos := p.expect(token.PACKAGE) + // Go spec: The package clause is not a declaration; + // the package name does not appear in any scope. ident := p.parseIdent() + if ident.Name == "_" { + p.error(p.pos, "invalid package name _") + } p.expectSemi() var decls []ast.Decl @@ -1940,5 +2233,20 @@ func (p *parser) parseFile() *ast.File { } } - return &ast.File{doc, pos, ident, decls, p.comments} + assert(p.topScope == p.pkgScope, "imbalanced scopes") + + // resolve global identifiers within the same file + i := 0 + for _, ident := range p.unresolved { + // i <= index for current ident + assert(ident.Obj == unresolved, "object already resolved") + ident.Obj = p.pkgScope.Lookup(ident.Name) // also removes unresolved sentinel + if ident.Obj == nil { + p.unresolved[i] = ident + i++ + } + } + + // TODO(gri): store p.imports in AST + return &ast.File{doc, pos, ident, decls, p.pkgScope, p.imports, p.unresolved[0:i], p.comments} } |