]> Cypherpunks repositories - gostls13.git/commitdiff
- adjustments to match slightly changed scanner interface
authorRobert Griesemer <gri@golang.org>
Fri, 27 Mar 2009 05:16:06 +0000 (22:16 -0700)
committerRobert Griesemer <gri@golang.org>
Fri, 27 Mar 2009 05:16:06 +0000 (22:16 -0700)
- more comments on parser, various cleanups

TBR=r
OCL=26813
CL=26813

usr/gri/pretty/compilation.go
usr/gri/pretty/parser.go

index 8d74ea5b72204cdbfb03785baf537df36bb383b9..17906c50e1557e5f2ff6e2241e4f984c4bae68ca 100644 (file)
@@ -101,7 +101,7 @@ func Compile(src_file string, flags *Flags) (*ast.Package, ErrorList) {
        if flags.Verbose {
                pflags |= parser.Trace;
        }
-       prog := parser.Parse(&scanner, &err, parser.ParseEntirePackage, pflags);
+       prog, nerrs := parser.Parse(&scanner, &err, parser.ParseEntirePackage, pflags);
 
        if err.errors.Len() == 0 {
                TypeChecker.CheckProgram(&err, prog);
index 073fd2a01496a81619b1067c31c735eb5a7f4bd4..92ff4622a6b447cfd3a4cdfe031c8f6a8f28b26a 100644 (file)
@@ -4,7 +4,8 @@
 
 // A parser for Go source text. The input is a stream of lexical tokens
 // provided via the Scanner interface. The output is an abstract syntax
-// tree (AST) representing the Go source.
+// tree (AST) representing the Go source. The parser is invoked by calling
+// Parse.
 //
 package parser
 
@@ -16,26 +17,22 @@ import (
 )
 
 
-type interval struct {
-       beg, end int;
-}
-
-
 // An implementation of a Scanner must be provided to the Parser.
 // The parser calls Scan() repeatedly until token.EOF is returned.
 // Scan must return the current token position pos, the token value
-// tok, and the corresponding token literal string lit if the token
-// is a literal (i.e., if tok.IsLiteral() is true).
+// tok, and the corresponding token literal string lit; lit can be
+// undefined/nil unless the token is a literal (i.e., tok.IsLiteral()
+// is true).
 //
 type Scanner interface {
        Scan() (pos token.Position, tok token.Token, lit []byte);
 }
 
 
-// An implementation of an ErrorHandler must be provided to the parser.
-// If a syntax error is encountered, Error is called with a position and
-// an error message. The position points to the beginning of the offending
-// token.
+// An implementation of an ErrorHandler may be provided to the parser.
+// If a syntax error is encountered and a handler was installed, Error
+// is called with a position and an error message. The position points
+// to the beginning of the offending token.
 //
 type ErrorHandler interface {
        Error(pos token.Position, msg string);
@@ -46,24 +43,31 @@ type ErrorHandler interface {
 // flags (or 0) must be provided as a parameter to the Parse function.
 //
 const (
-       Trace = 1 << iota;
+       Trace = 1 << iota;  // print a trace of parsed productions
 )
 
 
+type interval struct {
+       beg, end int;
+}
+
+
 // The parser structure holds the parser's internal state.
 type parser struct {
        scanner Scanner;
-       err ErrorHandler;
+       err ErrorHandler;  // nil if no handler installed
+       errorCount int;
 
        // Tracing/debugging
        trace bool;
        indent uint;
 
+       // Comments
        comments vector.Vector;  // list of collected, unassociated comments
        last_doc interval;  // last comments interval of consecutive comments
 
        // The next token
-       pos token.Position;  // token location
+       pos token.Position;  // token position
        tok token.Token;  // one token look-ahead
        lit []byte;  // token literal
 
@@ -73,8 +77,8 @@ type parser struct {
 };
 
 
-// When we don't have a location use nopos.
-// TODO make sure we always have a location.
+// When we don't have a position use nopos.
+// TODO make sure we always have a position.
 var nopos token.Position;
 
 
@@ -89,8 +93,8 @@ func unreachable() {
 // ----------------------------------------------------------------------------
 // Parsing support
 
-func (P *parser) printIndent() {
-       i := P.indent;
+func (p *parser) printIndent() {
+       i := p.indent;
        // reduce printing time by a factor of 2 or more
        for ; i > 10; i -= 10 {
                fmt.Printf(". . . . . . . . . . ");
@@ -101,38 +105,38 @@ func (P *parser) printIndent() {
 }
 
 
-func trace(P *parser, msg string) *parser {
-       P.printIndent();
+func trace(p *parser, msg string) *parser {
+       p.printIndent();
        fmt.Printf("%s (\n", msg);
-       P.indent++;
-       return P;
+       p.indent++;
+       return p;
 }
 
 
-func un/*trace*/(P *parser) {
-       P.indent--;
-       P.printIndent();
+func un/*trace*/(p *parser) {
+       p.indent--;
+       p.printIndent();
        fmt.Printf(")\n");
 }
 
 
-func (P *parser) next0() {
-       P.pos, P.tok, P.lit = P.scanner.Scan();
-       P.opt_semi = false;
+func (p *parser) next0() {
+       p.pos, p.tok, p.lit = p.scanner.Scan();
+       p.opt_semi = false;
 
-       if P.trace {
-               P.printIndent();
-               switch P.tok {
+       if p.trace {
+               p.printIndent();
+               switch p.tok {
                case token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING:
-                       fmt.Printf("%d:%d: %s = %s\n", P.pos.Line, P.pos.Column, P.tok.String(), P.lit);
+                       fmt.Printf("%d:%d: %s = %s\n", p.pos.Line, p.pos.Column, p.tok.String(), p.lit);
                case token.LPAREN:
                        // don't print '(' - screws up selection in terminal window
-                       fmt.Printf("%d:%d: LPAREN\n", P.pos.Line, P.pos.Column);
+                       fmt.Printf("%d:%d: LPAREN\n", p.pos.Line, p.pos.Column);
                case token.RPAREN:
                        // don't print ')' - screws up selection in terminal window
-                       fmt.Printf("%d:%d: RPAREN\n", P.pos.Line, P.pos.Column);
+                       fmt.Printf("%d:%d: RPAREN\n", p.pos.Line, p.pos.Column);
                default:
-                       fmt.Printf("%d:%d: %s\n", P.pos.Line, P.pos.Column, P.tok.String());
+                       fmt.Printf("%d:%d: %s\n", p.pos.Line, p.pos.Column, p.tok.String());
                }
        }
 }
@@ -140,71 +144,74 @@ func (P *parser) next0() {
 
 // Collect a comment in the parser's comment list and return the line
 // on which the comment ends.
-func (P *parser) collectComment() int {
+func (p *parser) collectComment() int {
        // For /*-style comments, the comment may end on a different line.
        // Scan the comment for '\n' chars and adjust the end line accordingly.
        // (Note that the position of the next token may be even further down
        // as there may be more whitespace lines after the comment.)
-       endline := P.pos.Line;
-       if P.lit[1] == '*' {
-               for i, b := range P.lit {
+       endline := p.pos.Line;
+       if p.lit[1] == '*' {
+               for i, b := range p.lit {
                        if b == '\n' {
                                endline++;
                        }
                }
        }
-       P.comments.Push(&ast.Comment{P.pos, P.lit, endline});
-       P.next0();
+       p.comments.Push(&ast.Comment{p.pos, p.lit, endline});
+       p.next0();
        
        return endline;
 }
 
 
-func (P *parser) getComments() interval {
+func (p *parser) getComments() interval {
        // group adjacent comments, an empty line terminates a group
-       beg := P.comments.Len();
-       endline := P.pos.Line;
-       for P.tok == token.COMMENT && endline+1 >= P.pos.Line {
-               endline = P.collectComment();
+       beg := p.comments.Len();
+       endline := p.pos.Line;
+       for p.tok == token.COMMENT && endline+1 >= p.pos.Line {
+               endline = p.collectComment();
        }
-       end := P.comments.Len();
+       end := p.comments.Len();
        return interval {beg, end};
 }
 
 
-func (P *parser) next() {
-       P.next0();
-       P.last_doc = interval{0, 0};
-       for P.tok == token.COMMENT {
-               P.last_doc = P.getComments();
+func (p *parser) next() {
+       p.next0();
+       p.last_doc = interval{0, 0};
+       for p.tok == token.COMMENT {
+               p.last_doc = p.getComments();
        }
 }
 
 
-func (P *parser) error(pos token.Position, msg string) {
-       P.err.Error(pos, msg);
+func (p *parser) error(pos token.Position, msg string) {
+       if p.err != nil {
+               p.err.Error(pos, msg);
+       }
+       p.errorCount++;
 }
 
 
-func (P *parser) expect(tok token.Token) token.Position {
-       if P.tok != tok {
-               msg := "expected '" + tok.String() + "', found '" + P.tok.String() + "'";
-               if P.tok.IsLiteral() {
-                       msg += " " + string(P.lit);
+func (p *parser) expect(tok token.Token) token.Position {
+       if p.tok != tok {
+               msg := "expected '" + tok.String() + "', found '" + p.tok.String() + "'";
+               if p.tok.IsLiteral() {
+                       msg += " " + string(p.lit);
                }
-               P.error(P.pos, msg);
+               p.error(p.pos, msg);
        }
-       loc := P.pos;
-       P.next();  // make progress in any case
-       return loc;
+       pos := p.pos;
+       p.next();  // make progress in any case
+       return pos;
 }
 
 
-func (P *parser) getDoc() ast.Comments {
-       doc := P.last_doc;
+func (p *parser) getDoc() ast.Comments {
+       doc := p.last_doc;
        n := doc.end - doc.beg;
        
-       if n <= 0 || P.comments.At(doc.end - 1).(*ast.Comment).EndLine + 1 < P.pos.Line {
+       if n <= 0 || p.comments.At(doc.end - 1).(*ast.Comment).EndLine + 1 < p.pos.Line {
                // no comments or empty line between last comment and current token;
                // do not use as documentation
                return nil;
@@ -214,10 +221,12 @@ func (P *parser) getDoc() ast.Comments {
        // use as documentation
        c := make(ast.Comments, n);
        for i := 0; i < n; i++ {
-               c[i] = P.comments.At(doc.beg + i).(*ast.Comment);
-               // TODO find a better way to do this
-               P.comments.Set(doc.beg + i, nil);  // remove the comment from the general list
+               c[i] = p.comments.At(doc.beg + i).(*ast.Comment);
        }
+
+       // remove comments from the general list
+       p.comments.Cut(doc.beg, doc.end);
+
        return c;
 }
 
@@ -225,41 +234,41 @@ func (P *parser) getDoc() ast.Comments {
 // ----------------------------------------------------------------------------
 // Common productions
 
-func (P *parser) tryType() ast.Expr;
-func (P *parser) parseExpression(prec int) ast.Expr;
-func (P *parser) parseStatement() ast.Stmt;
-func (P *parser) parseDeclaration() ast.Decl;
+func (p *parser) tryType() ast.Expr;
+func (p *parser) parseExpression(prec int) ast.Expr;
+func (p *parser) parseStatement() ast.Stmt;
+func (p *parser) parseDeclaration() ast.Decl;
 
 
-func (P *parser) parseIdent() *ast.Ident {
-       if P.trace {
-               defer un(trace(P, "Ident"));
+func (p *parser) parseIdent() *ast.Ident {
+       if p.trace {
+               defer un(trace(p, "Ident"));
        }
 
-       if P.tok == token.IDENT {
-               x := &ast.Ident{P.pos, P.lit};
-               P.next();
+       if p.tok == token.IDENT {
+               x := &ast.Ident{p.pos, p.lit};
+               p.next();
                return x;
        }
-       P.expect(token.IDENT);  // use expect() error handling
+       p.expect(token.IDENT);  // use expect() error handling
 
-       return &ast.Ident{P.pos, [0]byte{}};
+       return &ast.Ident{p.pos, [0]byte{}};
 }
 
 
-func (P *parser) parseIdentList(x ast.Expr) []*ast.Ident {
-       if P.trace {
-               defer un(trace(P, "IdentList"));
+func (p *parser) parseIdentList(x ast.Expr) []*ast.Ident {
+       if p.trace {
+               defer un(trace(p, "IdentList"));
        }
 
        list := vector.New(0);
        if x == nil {
-               x = P.parseIdent();
+               x = p.parseIdent();
        }
        list.Push(x);
-       for P.tok == token.COMMA {
-               P.next();
-               list.Push(P.parseIdent());
+       for p.tok == token.COMMA {
+               p.next();
+               list.Push(p.parseIdent());
        }
 
        // convert vector
@@ -272,16 +281,16 @@ func (P *parser) parseIdentList(x ast.Expr) []*ast.Ident {
 }
 
 
-func (P *parser) parseExpressionList() []ast.Expr {
-       if P.trace {
-               defer un(trace(P, "ExpressionList"));
+func (p *parser) parseExpressionList() []ast.Expr {
+       if p.trace {
+               defer un(trace(p, "ExpressionList"));
        }
 
        list := vector.New(0);
-       list.Push(P.parseExpression(1));
-       for P.tok == token.COMMA {
-               P.next();
-               list.Push(P.parseExpression(1));
+       list.Push(p.parseExpression(1));
+       for p.tok == token.COMMA {
+               p.next();
+               list.Push(p.parseExpression(1));
        }
 
        // convert list
@@ -297,149 +306,140 @@ func (P *parser) parseExpressionList() []ast.Expr {
 // ----------------------------------------------------------------------------
 // Types
 
-func (P *parser) parseType() ast.Expr {
-       if P.trace {
-               defer un(trace(P, "Type"));
+func (p *parser) parseType() ast.Expr {
+       if p.trace {
+               defer un(trace(p, "Type"));
        }
 
-       typ := P.tryType();
+       typ := p.tryType();
        if typ == nil {
-               P.error(P.pos, "type expected");
-               typ = &ast.BadExpr{P.pos};
+               p.error(p.pos, "type expected");
+               typ = &ast.BadExpr{p.pos};
        }
 
        return typ;
 }
 
 
-func (P *parser) parseVarType() ast.Expr {
-       if P.trace {
-               defer un(trace(P, "VarType"));
-       }
-
-       return P.parseType();
-}
-
-
-func (P *parser) parseQualifiedIdent() ast.Expr {
-       if P.trace {
-               defer un(trace(P, "QualifiedIdent"));
+func (p *parser) parseQualifiedIdent() ast.Expr {
+       if p.trace {
+               defer un(trace(p, "QualifiedIdent"));
        }
 
-       var x ast.Expr = P.parseIdent();
-       for P.tok == token.PERIOD {
-               P.next();
-               sel := P.parseIdent();
+       var x ast.Expr = p.parseIdent();
+       for p.tok == token.PERIOD {
+               p.next();
+               sel := p.parseIdent();
                x = &ast.SelectorExpr{x, sel};
        }
        return x;
 }
 
 
-func (P *parser) parseTypeName() ast.Expr {
-       if P.trace {
-               defer un(trace(P, "TypeName"));
+func (p *parser) parseTypeName() ast.Expr {
+       if p.trace {
+               defer un(trace(p, "TypeName"));
        }
 
-       return P.parseQualifiedIdent();
+       return p.parseQualifiedIdent();
 }
 
 
-func (P *parser) parseArrayType() *ast.ArrayType {
-       if P.trace {
-               defer un(trace(P, "ArrayType"));
+func (p *parser) parseArrayType() *ast.ArrayType {
+       if p.trace {
+               defer un(trace(p, "ArrayType"));
        }
 
-       lbrack := P.expect(token.LBRACK);
+       lbrack := p.expect(token.LBRACK);
        var len ast.Expr;
-       if P.tok == token.ELLIPSIS {
-               len = &ast.Ellipsis{P.pos};
-               P.next();
-       } else if P.tok != token.RBRACK {
-               len = P.parseExpression(1);
+       if p.tok == token.ELLIPSIS {
+               len = &ast.Ellipsis{p.pos};
+               p.next();
+       } else if p.tok != token.RBRACK {
+               len = p.parseExpression(1);
        }
-       P.expect(token.RBRACK);
-       elt := P.parseType();
+       p.expect(token.RBRACK);
+       elt := p.parseType();
 
        return &ast.ArrayType{lbrack, len, elt};
 }
 
 
-func (P *parser) parseChannelType() *ast.ChannelType {
-       if P.trace {
-               defer un(trace(P, "ChannelType"));
+func (p *parser) parseChannelType() *ast.ChannelType {
+       if p.trace {
+               defer un(trace(p, "ChannelType"));
        }
 
-       pos := P.pos;
+       pos := p.pos;
        dir := ast.SEND | ast.RECV;
-       if P.tok == token.CHAN {
-               P.next();
-               if P.tok == token.ARROW {
-                       P.next();
+       if p.tok == token.CHAN {
+               p.next();
+               if p.tok == token.ARROW {
+                       p.next();
                        dir = ast.SEND;
                }
        } else {
-               P.expect(token.ARROW);
-               P.expect(token.CHAN);
+               p.expect(token.ARROW);
+               p.expect(token.CHAN);
                dir = ast.RECV;
        }
-       value := P.parseVarType();
+       value := p.parseType();
 
        return &ast.ChannelType{pos, dir, value};
 }
 
 
-func (P *parser) tryParameterType() ast.Expr {
-       if P.tok == token.ELLIPSIS {
-               loc  := P.pos;
-               P.next();
-               return &ast.Ellipsis{loc};
+func (p *parser) tryParameterType() ast.Expr {
+       if p.tok == token.ELLIPSIS {
+               x := &ast.Ellipsis{p.pos};
+               p.next();
+               return x;
        }
-       return P.tryType();
+       return p.tryType();
 }
 
 
-func (P *parser) parseParameterType() ast.Expr {
-       typ := P.tryParameterType();
+func (p *parser) parseParameterType() ast.Expr {
+       typ := p.tryParameterType();
        if typ == nil {
-               P.error(P.pos, "type expected");
-               typ = &ast.BadExpr{P.pos};
+               p.error(p.pos, "type expected");
+               typ = &ast.BadExpr{p.pos};
        }
 
        return typ;
 }
 
 
-func (P *parser) parseParameterDecl(ellipsis_ok bool) (*vector.Vector, ast.Expr) {
-       if P.trace {
-               defer un(trace(P, "ParameterDecl"));
+func (p *parser) parseParameterDecl(ellipsis_ok bool) (*vector.Vector, ast.Expr) {
+       if p.trace {
+               defer un(trace(p, "ParameterDecl"));
        }
 
        // a list of identifiers looks like a list of type names
        list := vector.New(0);
        for {
                // TODO do not allow ()'s here
-               list.Push(P.parseParameterType());
-               if P.tok == token.COMMA {
-                       P.next();
+               list.Push(p.parseParameterType());
+               if p.tok == token.COMMA {
+                       p.next();
                } else {
                        break;
                }
        }
 
        // if we had a list of identifiers, it must be followed by a type
-       typ := P.tryParameterType();
+       typ := p.tryParameterType();
 
        return list, typ;
 }
 
 
-func (P *parser) parseParameterList(ellipsis_ok bool) []*ast.Field {
-       if P.trace {
-               defer un(trace(P, "ParameterList"));
+func (p *parser) parseParameterList(ellipsis_ok bool) []*ast.Field {
+       if p.trace {
+               defer un(trace(p, "ParameterList"));
        }
 
-       list, typ := P.parseParameterDecl(false);
+       list, typ := p.parseParameterDecl(false);
        if typ != nil {
                // IdentifierList Type
                // convert list of identifiers into []*Ident
@@ -450,10 +450,10 @@ func (P *parser) parseParameterList(ellipsis_ok bool) []*ast.Field {
                list.Init(0);
                list.Push(&ast.Field{nil, idents, typ, nil});
 
-               for P.tok == token.COMMA {
-                       P.next();
-                       idents := P.parseIdentList(nil);
-                       typ := P.parseParameterType();
+               for p.tok == token.COMMA {
+                       p.next();
+                       idents := p.parseIdentList(nil);
+                       typ := p.parseParameterType();
                        list.Push(&ast.Field{nil, idents, typ, nil});
                }
 
@@ -476,32 +476,32 @@ func (P *parser) parseParameterList(ellipsis_ok bool) []*ast.Field {
 
 
 // TODO make sure Go spec is updated
-func (P *parser) parseParameters(ellipsis_ok bool) []*ast.Field {
-       if P.trace {
-               defer un(trace(P, "Parameters"));
+func (p *parser) parseParameters(ellipsis_ok bool) []*ast.Field {
+       if p.trace {
+               defer un(trace(p, "Parameters"));
        }
 
        var params []*ast.Field;
-       P.expect(token.LPAREN);
-       if P.tok != token.RPAREN {
-               params = P.parseParameterList(ellipsis_ok);
+       p.expect(token.LPAREN);
+       if p.tok != token.RPAREN {
+               params = p.parseParameterList(ellipsis_ok);
        }
-       P.expect(token.RPAREN);
+       p.expect(token.RPAREN);
 
        return params;
 }
 
 
-func (P *parser) parseResult() []*ast.Field {
-       if P.trace {
-               defer un(trace(P, "Result"));
+func (p *parser) parseResult() []*ast.Field {
+       if p.trace {
+               defer un(trace(p, "Result"));
        }
 
        var results []*ast.Field;
-       if P.tok == token.LPAREN {
-               results = P.parseParameters(false);
-       } else if P.tok != token.FUNC {
-               typ := P.tryType();
+       if p.tok == token.LPAREN {
+               results = p.parseParameters(false);
+       } else if p.tok != token.FUNC {
+               typ := p.tryType();
                if typ != nil {
                        results = make([]*ast.Field, 1);
                        results[0] = &ast.Field{nil, nil, typ, nil};
@@ -518,43 +518,43 @@ func (P *parser) parseResult() []*ast.Field {
 // (params) type
 // (params) (results)
 
-func (P *parser) parseSignature() (params []*ast.Field, results []*ast.Field) {
-       if P.trace {
-               defer un(trace(P, "Signature"));
+func (p *parser) parseSignature() (params []*ast.Field, results []*ast.Field) {
+       if p.trace {
+               defer un(trace(p, "Signature"));
        }
 
-       params = P.parseParameters(true);  // TODO find better solution
-       results = P.parseResult();
+       params = p.parseParameters(true);  // TODO find better solution
+       results = p.parseResult();
 
        return params, results;
 }
 
 
-func (P *parser) parseFunctionType() *ast.FunctionType {
-       if P.trace {
-               defer un(trace(P, "FunctionType"));
+func (p *parser) parseFunctionType() *ast.FunctionType {
+       if p.trace {
+               defer un(trace(p, "FunctionType"));
        }
 
-       pos := P.expect(token.FUNC);
-       params, results := P.parseSignature();
+       pos := p.expect(token.FUNC);
+       params, results := p.parseSignature();
 
        return &ast.FunctionType{pos, params, results};
 }
 
 
-func (P *parser) parseMethodSpec() *ast.Field {
-       if P.trace {
-               defer un(trace(P, "MethodSpec"));
+func (p *parser) parseMethodSpec() *ast.Field {
+       if p.trace {
+               defer un(trace(p, "MethodSpec"));
        }
 
-       doc := P.getDoc();
+       doc := p.getDoc();
        var idents []*ast.Ident;
        var typ ast.Expr;
-       x := P.parseQualifiedIdent();
-       if tmp, is_ident := x.(*ast.Ident); is_ident && (P.tok == token.COMMA || P.tok == token.LPAREN) {
+       x := p.parseQualifiedIdent();
+       if tmp, is_ident := x.(*ast.Ident); is_ident && (p.tok == token.COMMA || p.tok == token.LPAREN) {
                // method(s)
-               idents = P.parseIdentList(x);
-               params, results := P.parseSignature();
+               idents = p.parseIdentList(x);
+               params, results := p.parseSignature();
                typ = &ast.FunctionType{nopos, params, results};
        } else {
                // embedded interface
@@ -565,28 +565,28 @@ func (P *parser) parseMethodSpec() *ast.Field {
 }
 
 
-func (P *parser) parseInterfaceType() *ast.InterfaceType {
-       if P.trace {
-               defer un(trace(P, "InterfaceType"));
+func (p *parser) parseInterfaceType() *ast.InterfaceType {
+       if p.trace {
+               defer un(trace(p, "InterfaceType"));
        }
 
-       pos := P.expect(token.INTERFACE);
+       pos := p.expect(token.INTERFACE);
        var lbrace, rbrace token.Position;
        var methods []*ast.Field;
-       if P.tok == token.LBRACE {
-               lbrace = P.pos;
-               P.next();
+       if p.tok == token.LBRACE {
+               lbrace = p.pos;
+               p.next();
 
                list := vector.New(0);
-               for P.tok == token.IDENT {
-                       list.Push(P.parseMethodSpec());
-                       if P.tok != token.RBRACE {
-                               P.expect(token.SEMICOLON);
+               for p.tok == token.IDENT {
+                       list.Push(p.parseMethodSpec());
+                       if p.tok != token.RBRACE {
+                               p.expect(token.SEMICOLON);
                        }
                }
 
-               rbrace = P.expect(token.RBRACE);
-               P.opt_semi = true;
+               rbrace = p.expect(token.RBRACE);
+               p.opt_semi = true;
 
                // convert vector
                methods = make([]*ast.Field, list.Len());
@@ -599,49 +599,49 @@ func (P *parser) parseInterfaceType() *ast.InterfaceType {
 }
 
 
-func (P *parser) parseMapType() *ast.MapType {
-       if P.trace {
-               defer un(trace(P, "MapType"));
+func (p *parser) parseMapType() *ast.MapType {
+       if p.trace {
+               defer un(trace(p, "MapType"));
        }
 
-       pos := P.expect(token.MAP);
-       P.expect(token.LBRACK);
-       key := P.parseVarType();
-       P.expect(token.RBRACK);
-       value := P.parseVarType();
+       pos := p.expect(token.MAP);
+       p.expect(token.LBRACK);
+       key := p.parseType();
+       p.expect(token.RBRACK);
+       value := p.parseType();
 
        return &ast.MapType{pos, key, value};
 }
 
 
-func (P *parser) parseStringList(x *ast.StringLit) []*ast.StringLit
+func (p *parser) parseStringList(x *ast.StringLit) []*ast.StringLit
 
-func (P *parser) parseFieldDecl() *ast.Field {
-       if P.trace {
-               defer un(trace(P, "FieldDecl"));
+func (p *parser) parseFieldDecl() *ast.Field {
+       if p.trace {
+               defer un(trace(p, "FieldDecl"));
        }
 
-       doc := P.getDoc();
+       doc := p.getDoc();
 
        // a list of identifiers looks like a list of type names
        list := vector.New(0);
        for {
                // TODO do not allow ()'s here
-               list.Push(P.parseType());
-               if P.tok == token.COMMA {
-                       P.next();
+               list.Push(p.parseType());
+               if p.tok == token.COMMA {
+                       p.next();
                } else {
                        break;
                }
        }
 
        // if we had a list of identifiers, it must be followed by a type
-       typ := P.tryType();
+       typ := p.tryType();
 
        // optional tag
        var tag []*ast.StringLit;
-       if P.tok == token.STRING {
-               tag = P.parseStringList(nil);
+       if p.tok == token.STRING {
+               tag = p.parseStringList(nil);
        }
 
        // analyze case
@@ -653,7 +653,7 @@ func (P *parser) parseFieldDecl() *ast.Field {
                        if ident, is_ident := list.At(i).(*ast.Ident); is_ident {
                                idents[i] = ident;
                        } else {
-                               P.error(list.At(i).(ast.Expr).Pos(), "identifier expected");
+                               p.error(list.At(i).(ast.Expr).Pos(), "identifier expected");
                        }
                }
        } else {
@@ -662,7 +662,7 @@ func (P *parser) parseFieldDecl() *ast.Field {
                        // TODO should do more checks here
                        typ = list.At(0).(ast.Expr);
                } else {
-                       P.error(P.pos, "anonymous field expected");
+                       p.error(p.pos, "anonymous field expected");
                }
        }
 
@@ -670,33 +670,33 @@ func (P *parser) parseFieldDecl() *ast.Field {
 }
 
 
-func (P *parser) parseStructType() *ast.StructType {
-       if P.trace {
-               defer un(trace(P, "StructType"));
+func (p *parser) parseStructType() *ast.StructType {
+       if p.trace {
+               defer un(trace(p, "StructType"));
        }
 
-       pos := P.expect(token.STRUCT);
+       pos := p.expect(token.STRUCT);
        var lbrace, rbrace token.Position;
        var fields []*ast.Field;
-       if P.tok == token.LBRACE {
-               lbrace = P.pos;
-               P.next();
+       if p.tok == token.LBRACE {
+               lbrace = p.pos;
+               p.next();
 
                list := vector.New(0);
-               for P.tok != token.RBRACE && P.tok != token.EOF {
-                       list.Push(P.parseFieldDecl());
-                       if P.tok == token.SEMICOLON {
-                               P.next();
+               for p.tok != token.RBRACE && p.tok != token.EOF {
+                       list.Push(p.parseFieldDecl());
+                       if p.tok == token.SEMICOLON {
+                               p.next();
                        } else {
                                break;
                        }
                }
-               if P.tok == token.SEMICOLON {
-                       P.next();
+               if p.tok == token.SEMICOLON {
+                       p.next();
                }
 
-               rbrace = P.expect(token.RBRACE);
-               P.opt_semi = true;
+               rbrace = p.expect(token.RBRACE);
+               p.opt_semi = true;
 
                // convert vector
                fields = make([]*ast.Field, list.Len());
@@ -709,37 +709,37 @@ func (P *parser) parseStructType() *ast.StructType {
 }
 
 
-func (P *parser) parsePointerType() *ast.StarExpr {
-       if P.trace {
-               defer un(trace(P, "PointerType"));
+func (p *parser) parsePointerType() *ast.StarExpr {
+       if p.trace {
+               defer un(trace(p, "PointerType"));
        }
 
-       star := P.expect(token.MUL);
-       base := P.parseType();
+       star := p.expect(token.MUL);
+       base := p.parseType();
 
        return &ast.StarExpr{star, base};
 }
 
 
-func (P *parser) tryType() ast.Expr {
-       if P.trace {
-               defer un(trace(P, "Type (try)"));
+func (p *parser) tryType() ast.Expr {
+       if p.trace {
+               defer un(trace(p, "Type (try)"));
        }
 
-       switch P.tok {
-       case token.IDENT: return P.parseTypeName();
-       case token.LBRACK: return P.parseArrayType();
-       case token.CHAN, token.ARROW: return P.parseChannelType();
-       case token.INTERFACE: return P.parseInterfaceType();
-       case token.FUNC: return P.parseFunctionType();
-       case token.MAP: return P.parseMapType();
-       case token.STRUCT: return P.parseStructType();
-       case token.MUL: return P.parsePointerType();
+       switch p.tok {
+       case token.IDENT: return p.parseTypeName();
+       case token.LBRACK: return p.parseArrayType();
+       case token.CHAN, token.ARROW: return p.parseChannelType();
+       case token.INTERFACE: return p.parseInterfaceType();
+       case token.FUNC: return p.parseFunctionType();
+       case token.MAP: return p.parseMapType();
+       case token.STRUCT: return p.parseStructType();
+       case token.MUL: return p.parsePointerType();
        case token.LPAREN:
-               lparen := P.pos;
-               P.next();
-               x := P.parseType();
-               rparen := P.expect(token.RPAREN);
+               lparen := p.pos;
+               p.next();
+               x := p.parseType();
+               rparen := p.expect(token.RPAREN);
                return &ast.ParenExpr{lparen, x, rparen};
        }
 
@@ -760,23 +760,23 @@ func asStmtList(list *vector.Vector) []ast.Stmt {
 }
 
 
-func (P *parser) parseStatementList() []ast.Stmt {
-       if P.trace {
-               defer un(trace(P, "StatementList"));
+func (p *parser) parseStatementList() []ast.Stmt {
+       if p.trace {
+               defer un(trace(p, "StatementList"));
        }
 
        list := vector.New(0);
        expect_semi := false;
-       for P.tok != token.CASE && P.tok != token.DEFAULT && P.tok != token.RBRACE && P.tok != token.EOF {
+       for p.tok != token.CASE && p.tok != token.DEFAULT && p.tok != token.RBRACE && p.tok != token.EOF {
                if expect_semi {
-                       P.expect(token.SEMICOLON);
+                       p.expect(token.SEMICOLON);
                        expect_semi = false;
                }
-               list.Push(P.parseStatement());
-               if P.tok == token.SEMICOLON {
-                       P.next();
-               } else if P.opt_semi {
-                       P.opt_semi = false;  // "consume" optional semicolon
+               list.Push(p.parseStatement());
+               if p.tok == token.SEMICOLON {
+                       p.next();
+               } else if p.opt_semi {
+                       p.opt_semi = false;  // "consume" optional semicolon
                } else {
                        expect_semi = true;
                }
@@ -786,15 +786,15 @@ func (P *parser) parseStatementList() []ast.Stmt {
 }
 
 
-func (P *parser) parseBlockStmt() *ast.BlockStmt {
-       if P.trace {
-               defer un(trace(P, "compositeStmt"));
+func (p *parser) parseBlockStmt() *ast.BlockStmt {
+       if p.trace {
+               defer un(trace(p, "compositeStmt"));
        }
 
-       lbrace := P.expect(token.LBRACE);
-       list := P.parseStatementList();
-       rbrace := P.expect(token.RBRACE);
-       P.opt_semi = true;
+       lbrace := p.expect(token.LBRACE);
+       list := p.parseStatementList();
+       rbrace := p.expect(token.RBRACE);
+       p.opt_semi = true;
 
        return &ast.BlockStmt{lbrace, list, rbrace};
 }
@@ -803,23 +803,23 @@ func (P *parser) parseBlockStmt() *ast.BlockStmt {
 // ----------------------------------------------------------------------------
 // Expressions
 
-func (P *parser) parseFunctionLit() ast.Expr {
-       if P.trace {
-               defer un(trace(P, "FunctionLit"));
+func (p *parser) parseFunctionLit() ast.Expr {
+       if p.trace {
+               defer un(trace(p, "FunctionLit"));
        }
 
-       typ := P.parseFunctionType();
-       P.expr_lev++;
-       body := P.parseBlockStmt();
-       P.expr_lev--;
+       typ := p.parseFunctionType();
+       p.expr_lev++;
+       body := p.parseBlockStmt();
+       p.expr_lev--;
 
        return &ast.FunctionLit{typ, body};
 }
 
 
-func (P *parser) parseStringList(x *ast.StringLit) []*ast.StringLit {
-       if P.trace {
-               defer un(trace(P, "StringList"));
+func (p *parser) parseStringList(x *ast.StringLit) []*ast.StringLit {
+       if p.trace {
+               defer un(trace(p, "StringList"));
        }
 
        list := vector.New(0);
@@ -827,9 +827,9 @@ func (P *parser) parseStringList(x *ast.StringLit) []*ast.StringLit {
                list.Push(x);
        }
        
-       for P.tok == token.STRING {
-               list.Push(&ast.StringLit{P.pos, P.lit});
-               P.next();
+       for p.tok == token.STRING {
+               list.Push(&ast.StringLit{p.pos, p.lit});
+               p.next();
        }
 
        // convert list
@@ -842,87 +842,87 @@ func (P *parser) parseStringList(x *ast.StringLit) []*ast.StringLit {
 }
 
 
-func (P *parser) parseOperand() ast.Expr {
-       if P.trace {
-               defer un(trace(P, "Operand"));
+func (p *parser) parseOperand() ast.Expr {
+       if p.trace {
+               defer un(trace(p, "Operand"));
        }
 
-       switch P.tok {
+       switch p.tok {
        case token.IDENT:
-               return P.parseIdent();
+               return p.parseIdent();
 
        case token.INT:
-               x := &ast.IntLit{P.pos, P.lit};
-               P.next();
+               x := &ast.IntLit{p.pos, p.lit};
+               p.next();
                return x;
 
        case token.FLOAT:
-               x := &ast.FloatLit{P.pos, P.lit};
-               P.next();
+               x := &ast.FloatLit{p.pos, p.lit};
+               p.next();
                return x;
 
        case token.CHAR:
-               x := &ast.CharLit{P.pos, P.lit};
-               P.next();
+               x := &ast.CharLit{p.pos, p.lit};
+               p.next();
                return x;
 
        case token.STRING:
-               x := &ast.StringLit{P.pos, P.lit};
-               P.next();
-               if P.tok == token.STRING {
-                       return &ast.StringList{P.parseStringList(x)};
+               x := &ast.StringLit{p.pos, p.lit};
+               p.next();
+               if p.tok == token.STRING {
+                       return &ast.StringList{p.parseStringList(x)};
                }
                return x;
 
        case token.LPAREN:
-               lparen := P.pos;
-               P.next();
-               P.expr_lev++;
-               x := P.parseExpression(1);
-               P.expr_lev--;
-               rparen := P.expect(token.RPAREN);
+               lparen := p.pos;
+               p.next();
+               p.expr_lev++;
+               x := p.parseExpression(1);
+               p.expr_lev--;
+               rparen := p.expect(token.RPAREN);
                return &ast.ParenExpr{lparen, x, rparen};
 
        case token.FUNC:
-               return P.parseFunctionLit();
+               return p.parseFunctionLit();
 
        default:
-               t := P.tryType();
+               t := p.tryType();
                if t != nil {
                        return t;
                } else {
-                       P.error(P.pos, "operand expected");
-                       P.next();  // make progress
+                       p.error(p.pos, "operand expected");
+                       p.next();  // make progress
                }
        }
 
-       return &ast.BadExpr{P.pos};
+       return &ast.BadExpr{p.pos};
 }
 
 
-func (P *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr {
-       if P.trace {
-               defer un(trace(P, "SelectorOrTypeAssertion"));
+func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr {
+       if p.trace {
+               defer un(trace(p, "SelectorOrTypeAssertion"));
        }
 
-       P.expect(token.PERIOD);
-       if P.tok == token.IDENT {
+       p.expect(token.PERIOD);
+       if p.tok == token.IDENT {
                // selector
-               sel := P.parseIdent();
+               sel := p.parseIdent();
                return &ast.SelectorExpr{x, sel};
                
        } else {
                // type assertion
-               P.expect(token.LPAREN);
+               p.expect(token.LPAREN);
                var typ ast.Expr;
-               if P.tok == token.TYPE {
+               if p.tok == token.TYPE {
                        // special case for type switch syntax
-                       typ = &ast.Ident{P.pos, P.lit};
-                       P.next();
+                       typ = &ast.Ident{p.pos, p.lit};
+                       p.next();
                } else {
-                       typ = P.parseType();
+                       typ = p.parseType();
                }
-               P.expect(token.RPAREN);
+               p.expect(token.RPAREN);
                return &ast.TypeAssertExpr{x, typ};
        }
 
@@ -931,56 +931,56 @@ func (P *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr {
 }
 
 
-func (P *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
-       if P.trace {
-               defer un(trace(P, "IndexOrSlice"));
+func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
+       if p.trace {
+               defer un(trace(p, "IndexOrSlice"));
        }
 
-       P.expect(token.LBRACK);
-       P.expr_lev++;
-       index := P.parseExpression(1);
-       P.expr_lev--;
+       p.expect(token.LBRACK);
+       p.expr_lev++;
+       index := p.parseExpression(1);
+       p.expr_lev--;
 
-       if P.tok == token.RBRACK {
+       if p.tok == token.RBRACK {
                // index
-               P.next();
+               p.next();
                return &ast.IndexExpr{x, index};
        }
        
        // slice
-       P.expect(token.COLON);
-       P.expr_lev++;
-       end := P.parseExpression(1);
-       P.expr_lev--;
-       P.expect(token.RBRACK);
+       p.expect(token.COLON);
+       p.expr_lev++;
+       end := p.parseExpression(1);
+       p.expr_lev--;
+       p.expect(token.RBRACK);
        return &ast.SliceExpr{x, index, end};
 }
 
 
-func (P *parser) parseCall(fun ast.Expr) *ast.CallExpr {
-       if P.trace {
-               defer un(trace(P, "Call"));
+func (p *parser) parseCall(fun ast.Expr) *ast.CallExpr {
+       if p.trace {
+               defer un(trace(p, "Call"));
        }
 
-       lparen := P.expect(token.LPAREN);
+       lparen := p.expect(token.LPAREN);
        var args []ast.Expr;
-       if P.tok != token.RPAREN {
-               args = P.parseExpressionList();
+       if p.tok != token.RPAREN {
+               args = p.parseExpressionList();
        }
-       rparen := P.expect(token.RPAREN);
+       rparen := p.expect(token.RPAREN);
        return &ast.CallExpr{fun, lparen, args, rparen};
 }
 
 
-func (P *parser) parseElementList() []ast.Expr {
-       if P.trace {
-               defer un(trace(P, "ElementList"));
+func (p *parser) parseElementList() []ast.Expr {
+       if p.trace {
+               defer un(trace(p, "ElementList"));
        }
 
        list := vector.New(0);
        singles := true;
-       for P.tok != token.RBRACE {
-               x := P.parseExpression(0);
+       for p.tok != token.RBRACE {
+               x := p.parseExpression(0);
                if list.Len() == 0 {
                        // first element determines syntax for remaining elements
                        if t, is_binary := x.(*ast.BinaryExpr); is_binary && t.Op == token.COLON {
@@ -990,19 +990,19 @@ func (P *parser) parseElementList() []ast.Expr {
                        // not the first element - check syntax
                        if singles {
                                if t, is_binary := x.(*ast.BinaryExpr); is_binary && t.Op == token.COLON {
-                                       P.error(t.X.Pos(), "single value expected; found pair");
+                                       p.error(t.X.Pos(), "single value expected; found pair");
                                }
                        } else {
                                if t, is_binary := x.(*ast.BinaryExpr); !is_binary || t.Op != token.COLON {
-                                       P.error(x.Pos(), "key:value pair expected; found single value");
+                                       p.error(x.Pos(), "key:value pair expected; found single value");
                                }
                        }
                }
 
                list.Push(x);
 
-               if P.tok == token.COMMA {
-                       P.next();
+               if p.tok == token.COMMA {
+                       p.next();
                } else {
                        break;
                }
@@ -1018,35 +1018,35 @@ func (P *parser) parseElementList() []ast.Expr {
 }
 
 
-func (P *parser) parseCompositeLit(typ ast.Expr) ast.Expr {
-       if P.trace {
-               defer un(trace(P, "CompositeLit"));
+func (p *parser) parseCompositeLit(typ ast.Expr) ast.Expr {
+       if p.trace {
+               defer un(trace(p, "CompositeLit"));
        }
 
-       lbrace := P.expect(token.LBRACE);
+       lbrace := p.expect(token.LBRACE);
        var elts []ast.Expr;
-       if P.tok != token.RBRACE {
-               elts = P.parseElementList();
+       if p.tok != token.RBRACE {
+               elts = p.parseElementList();
        }
-       rbrace := P.expect(token.RBRACE);
+       rbrace := p.expect(token.RBRACE);
        return &ast.CompositeLit{typ, lbrace, elts, rbrace};
 }
 
 
-func (P *parser) parsePrimaryExpr() ast.Expr {
-       if P.trace {
-               defer un(trace(P, "PrimaryExpr"));
+func (p *parser) parsePrimaryExpr() ast.Expr {
+       if p.trace {
+               defer un(trace(p, "PrimaryExpr"));
        }
 
-       x := P.parseOperand();
+       x := p.parseOperand();
        for {
-               switch P.tok {
-               case token.PERIOD: x = P.parseSelectorOrTypeAssertion(x);
-               case token.LBRACK: x = P.parseIndexOrSlice(x);
-               case token.LPAREN: x = P.parseCall(x);
+               switch p.tok {
+               case token.PERIOD: x = p.parseSelectorOrTypeAssertion(x);
+               case token.LBRACK: x = p.parseIndexOrSlice(x);
+               case token.LPAREN: x = p.parseCall(x);
                case token.LBRACE:
-                       if P.expr_lev >= 0 {
-                               x = P.parseCompositeLit(x);
+                       if p.expr_lev >= 0 {
+                               x = p.parseCompositeLit(x);
                        } else {
                                return x;
                        }
@@ -1060,41 +1060,41 @@ func (P *parser) parsePrimaryExpr() ast.Expr {
 }
 
 
-func (P *parser) parseUnaryExpr() ast.Expr {
-       if P.trace {
-               defer un(trace(P, "UnaryExpr"));
+func (p *parser) parseUnaryExpr() ast.Expr {
+       if p.trace {
+               defer un(trace(p, "UnaryExpr"));
        }
 
-       switch P.tok {
+       switch p.tok {
        case token.ADD, token.SUB, token.NOT, token.XOR, token.ARROW, token.AND, token.RANGE:
-               pos, tok := P.pos, P.tok;
-               P.next();
-               x := P.parseUnaryExpr();
+               pos, tok := p.pos, p.tok;
+               p.next();
+               x := p.parseUnaryExpr();
                return &ast.UnaryExpr{pos, tok, x};
 
        case token.MUL:
                // unary "*" expression or pointer type
-               pos := P.pos;
-               P.next();
-               x := P.parseUnaryExpr();
+               pos := p.pos;
+               p.next();
+               x := p.parseUnaryExpr();
                return &ast.StarExpr{pos, x};
        }
 
-       return P.parsePrimaryExpr();
+       return p.parsePrimaryExpr();
 }
 
 
-func (P *parser) parseBinaryExpr(prec1 int) ast.Expr {
-       if P.trace {
-               defer un(trace(P, "BinaryExpr"));
+func (p *parser) parseBinaryExpr(prec1 int) ast.Expr {
+       if p.trace {
+               defer un(trace(p, "BinaryExpr"));
        }
 
-       x := P.parseUnaryExpr();
-       for prec := P.tok.Precedence(); prec >= prec1; prec-- {
-               for P.tok.Precedence() == prec {
-                       pos, tok := P.pos, P.tok;
-                       P.next();
-                       y := P.parseBinaryExpr(prec + 1);
+       x := p.parseUnaryExpr();
+       for prec := p.tok.Precedence(); prec >= prec1; prec-- {
+               for p.tok.Precedence() == prec {
+                       pos, tok := p.pos, p.tok;
+                       p.next();
+                       y := p.parseBinaryExpr(prec + 1);
                        x = &ast.BinaryExpr{x, pos, tok, y};
                }
        }
@@ -1103,16 +1103,16 @@ func (P *parser) parseBinaryExpr(prec1 int) ast.Expr {
 }
 
 
-func (P *parser) parseExpression(prec int) ast.Expr {
-       if P.trace {
-               defer un(trace(P, "Expression"));
+func (p *parser) parseExpression(prec int) ast.Expr {
+       if p.trace {
+               defer un(trace(p, "Expression"));
        }
 
        if prec < 0 {
                panic("precedence must be >= 0");
        }
 
-       return P.parseBinaryExpr(prec);
+       return p.parseBinaryExpr(prec);
 }
 
 
@@ -1120,23 +1120,23 @@ func (P *parser) parseExpression(prec int) ast.Expr {
 // Statements
 
 
-func (P *parser) parseSimpleStmt() ast.Stmt {
-       if P.trace {
-               defer un(trace(P, "SimpleStmt"));
+func (p *parser) parseSimpleStmt() ast.Stmt {
+       if p.trace {
+               defer un(trace(p, "SimpleStmt"));
        }
 
-       x := P.parseExpressionList();
+       x := p.parseExpressionList();
 
-       switch P.tok {
+       switch p.tok {
        case token.COLON:
                // labeled statement
-               P.expect(token.COLON);
+               p.expect(token.COLON);
                if len(x) == 1 {
                        if label, is_ident := x[0].(*ast.Ident); is_ident {
-                               return &ast.LabeledStmt{label, P.parseStatement()};
+                               return &ast.LabeledStmt{label, p.parseStatement()};
                        }
                }
-               P.error(x[0].Pos(), "illegal label declaration");
+               p.error(x[0].Pos(), "illegal label declaration");
                return &ast.BadStmt{x[0].Pos()};
 
        case
@@ -1145,24 +1145,24 @@ func (P *parser) parseSimpleStmt() ast.Stmt {
                token.REM_ASSIGN, token.AND_ASSIGN, token.OR_ASSIGN,
                token.XOR_ASSIGN, token.SHL_ASSIGN, token.SHR_ASSIGN:
                // assignment statement
-               pos, tok := P.pos, P.tok;
-               P.next();
-               y := P.parseExpressionList();
+               pos, tok := p.pos, p.tok;
+               p.next();
+               y := p.parseExpressionList();
                if len(x) > 1 && len(y) > 1 && len(x) != len(y) {
-                       P.error(x[0].Pos(), "arity of lhs doesn't match rhs");
+                       p.error(x[0].Pos(), "arity of lhs doesn't match rhs");
                }
                return &ast.AssignStmt{x, pos, tok, y};
        }
 
        if len(x) > 1 {
-               P.error(x[0].Pos(), "only one expression allowed");
+               p.error(x[0].Pos(), "only one expression allowed");
                // continue with first expression
        }
 
-       if P.tok == token.INC || P.tok == token.DEC {
+       if p.tok == token.INC || p.tok == token.DEC {
                // increment or decrement
-               s := &ast.IncDecStmt{x[0], P.tok};
-               P.next();  // consume "++" or "--"
+               s := &ast.IncDecStmt{x[0], p.tok};
+               p.next();  // consume "++" or "--"
                return s;
        }
 
@@ -1171,23 +1171,23 @@ func (P *parser) parseSimpleStmt() ast.Stmt {
 }
 
 
-func (P *parser) parseCallExpr() *ast.CallExpr {
-       x := P.parseExpression(1);
+func (p *parser) parseCallExpr() *ast.CallExpr {
+       x := p.parseExpression(1);
        if call, is_call := x.(*ast.CallExpr); is_call {
                return call;
        }
-       P.error(x.Pos(), "expected function/method call");
+       p.error(x.Pos(), "expected function/method call");
        return nil;
 }
 
 
-func (P *parser) parseGoStmt() ast.Stmt {
-       if P.trace {
-               defer un(trace(P, "GoStmt"));
+func (p *parser) parseGoStmt() ast.Stmt {
+       if p.trace {
+               defer un(trace(p, "GoStmt"));
        }
 
-       pos := P.expect(token.GO);
-       call := P.parseCallExpr();
+       pos := p.expect(token.GO);
+       call := p.parseCallExpr();
        if call != nil {
                return &ast.GoStmt{pos, call};
        }
@@ -1195,13 +1195,13 @@ func (P *parser) parseGoStmt() ast.Stmt {
 }
 
 
-func (P *parser) parseDeferStmt() ast.Stmt {
-       if P.trace {
-               defer un(trace(P, "DeferStmt"));
+func (p *parser) parseDeferStmt() ast.Stmt {
+       if p.trace {
+               defer un(trace(p, "DeferStmt"));
        }
 
-       pos := P.expect(token.DEFER);
-       call := P.parseCallExpr();
+       pos := p.expect(token.DEFER);
+       call := p.parseCallExpr();
        if call != nil {
                return &ast.DeferStmt{pos, call};
        }
@@ -1209,38 +1209,38 @@ func (P *parser) parseDeferStmt() ast.Stmt {
 }
 
 
-func (P *parser) parseReturnStmt() *ast.ReturnStmt {
-       if P.trace {
-               defer un(trace(P, "ReturnStmt"));
+func (p *parser) parseReturnStmt() *ast.ReturnStmt {
+       if p.trace {
+               defer un(trace(p, "ReturnStmt"));
        }
 
-       loc := P.pos;
-       P.expect(token.RETURN);
+       pos := p.pos;
+       p.expect(token.RETURN);
        var x []ast.Expr;
-       if P.tok != token.SEMICOLON && P.tok != token.RBRACE {
-               x = P.parseExpressionList();
+       if p.tok != token.SEMICOLON && p.tok != token.RBRACE {
+               x = p.parseExpressionList();
        }
 
-       return &ast.ReturnStmt{loc, x};
+       return &ast.ReturnStmt{pos, x};
 }
 
 
-func (P *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
-       if P.trace {
-               defer un(trace(P, "BranchStmt"));
+func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
+       if p.trace {
+               defer un(trace(p, "BranchStmt"));
        }
 
-       s := &ast.BranchStmt{P.pos, tok, nil};
-       P.expect(tok);
-       if tok != token.FALLTHROUGH && P.tok == token.IDENT {
-               s.Label = P.parseIdent();
+       s := &ast.BranchStmt{p.pos, tok, nil};
+       p.expect(tok);
+       if tok != token.FALLTHROUGH && p.tok == token.IDENT {
+               s.Label = p.parseIdent();
        }
 
        return s;
 }
 
 
-func (P *parser) isExpr(s ast.Stmt) bool {
+func (p *parser) isExpr(s ast.Stmt) bool {
        if s == nil {
                return true;
        }
@@ -1249,145 +1249,145 @@ func (P *parser) isExpr(s ast.Stmt) bool {
 }
 
 
-func (P *parser) asExpr(s ast.Stmt) ast.Expr {
+func (p *parser) asExpr(s ast.Stmt) ast.Expr {
        if s == nil {
                return nil;
        }
        if es, is_expr := s.(*ast.ExprStmt); is_expr {
                return es.X;
        }
-       P.error(s.Pos(), "condition expected; found simple statement");
+       p.error(s.Pos(), "condition expected; found simple statement");
        return &ast.BadExpr{s.Pos()};
 }
 
 
-func (P *parser) parseControlClause(isForStmt bool) (s1, s2, s3 ast.Stmt) {
-       if P.trace {
-               defer un(trace(P, "ControlClause"));
+func (p *parser) parseControlClause(isForStmt bool) (s1, s2, s3 ast.Stmt) {
+       if p.trace {
+               defer un(trace(p, "ControlClause"));
        }
 
-       if P.tok != token.LBRACE {
-               prev_lev := P.expr_lev;
-               P.expr_lev = -1;
+       if p.tok != token.LBRACE {
+               prev_lev := p.expr_lev;
+               p.expr_lev = -1;
 
-               if P.tok != token.SEMICOLON {
-                       s1 = P.parseSimpleStmt();
+               if p.tok != token.SEMICOLON {
+                       s1 = p.parseSimpleStmt();
                }
-               if P.tok == token.SEMICOLON {
-                       P.next();
-                       if P.tok != token.LBRACE && P.tok != token.SEMICOLON {
-                               s2 = P.parseSimpleStmt();
+               if p.tok == token.SEMICOLON {
+                       p.next();
+                       if p.tok != token.LBRACE && p.tok != token.SEMICOLON {
+                               s2 = p.parseSimpleStmt();
                        }
                        if isForStmt {
                                // for statements have a 3rd section
-                               P.expect(token.SEMICOLON);
-                               if P.tok != token.LBRACE {
-                                       s3 = P.parseSimpleStmt();
+                               p.expect(token.SEMICOLON);
+                               if p.tok != token.LBRACE {
+                                       s3 = p.parseSimpleStmt();
                                }
                        }
                } else {
                        s1, s2 = nil, s1;
                }
                
-               P.expr_lev = prev_lev;
+               p.expr_lev = prev_lev;
        }
 
        return s1, s2, s3;
 }
 
 
-func (P *parser) parseIfStmt() *ast.IfStmt {
-       if P.trace {
-               defer un(trace(P, "IfStmt"));
+func (p *parser) parseIfStmt() *ast.IfStmt {
+       if p.trace {
+               defer un(trace(p, "IfStmt"));
        }
 
-       pos := P.expect(token.IF);
-       s1, s2, dummy := P.parseControlClause(false);
-       body := P.parseBlockStmt();
+       pos := p.expect(token.IF);
+       s1, s2, dummy := p.parseControlClause(false);
+       body := p.parseBlockStmt();
        var else_ ast.Stmt;
-       if P.tok == token.ELSE {
-               P.next();
-               else_ = P.parseStatement();
+       if p.tok == token.ELSE {
+               p.next();
+               else_ = p.parseStatement();
        }
 
-       return &ast.IfStmt{pos, s1, P.asExpr(s2), body, else_};
+       return &ast.IfStmt{pos, s1, p.asExpr(s2), body, else_};
 }
 
 
-func (P *parser) parseCaseClause() *ast.CaseClause {
-       if P.trace {
-               defer un(trace(P, "CaseClause"));
+func (p *parser) parseCaseClause() *ast.CaseClause {
+       if p.trace {
+               defer un(trace(p, "CaseClause"));
        }
 
        // SwitchCase
-       loc := P.pos;
+       pos := p.pos;
        var x []ast.Expr;
-       if P.tok == token.CASE {
-               P.next();
-               x = P.parseExpressionList();
+       if p.tok == token.CASE {
+               p.next();
+               x = p.parseExpressionList();
        } else {
-               P.expect(token.DEFAULT);
+               p.expect(token.DEFAULT);
        }
        
-       colon := P.expect(token.COLON);
-       body := P.parseStatementList();
+       colon := p.expect(token.COLON);
+       body := p.parseStatementList();
 
-       return &ast.CaseClause{loc, x, colon, body};
+       return &ast.CaseClause{pos, x, colon, body};
 }
 
 
-func (P *parser) parseTypeCaseClause() *ast.TypeCaseClause {
-       if P.trace {
-               defer un(trace(P, "CaseClause"));
+func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
+       if p.trace {
+               defer un(trace(p, "CaseClause"));
        }
 
        // TypeSwitchCase
-       pos := P.pos;
+       pos := p.pos;
        var typ ast.Expr;
-       if P.tok == token.CASE {
-               P.next();
-               typ = P.parseType();
+       if p.tok == token.CASE {
+               p.next();
+               typ = p.parseType();
        } else {
-               P.expect(token.DEFAULT);
+               p.expect(token.DEFAULT);
        }
 
-       colon := P.expect(token.COLON);
-       body := P.parseStatementList();
+       colon := p.expect(token.COLON);
+       body := p.parseStatementList();
 
        return &ast.TypeCaseClause{pos, typ, colon, body};
 }
 
 
-func (P *parser) parseSwitchStmt() ast.Stmt {
-       if P.trace {
-               defer un(trace(P, "SwitchStmt"));
+func (p *parser) parseSwitchStmt() ast.Stmt {
+       if p.trace {
+               defer un(trace(p, "SwitchStmt"));
        }
 
-       pos := P.expect(token.SWITCH);
-       s1, s2, dummy := P.parseControlClause(false);
+       pos := p.expect(token.SWITCH);
+       s1, s2, dummy := p.parseControlClause(false);
 
-       if P.isExpr(s2) {
+       if p.isExpr(s2) {
                // expression switch
-               lbrace := P.expect(token.LBRACE);
+               lbrace := p.expect(token.LBRACE);
                cases := vector.New(0);
-               for P.tok == token.CASE || P.tok == token.DEFAULT {
-                       cases.Push(P.parseCaseClause());
+               for p.tok == token.CASE || p.tok == token.DEFAULT {
+                       cases.Push(p.parseCaseClause());
                }
-               rbrace := P.expect(token.RBRACE);
-               P.opt_semi = true;
+               rbrace := p.expect(token.RBRACE);
+               p.opt_semi = true;
                body := &ast.BlockStmt{lbrace, asStmtList(cases), rbrace};
-               return &ast.SwitchStmt{pos, s1, P.asExpr(s2), body};
+               return &ast.SwitchStmt{pos, s1, p.asExpr(s2), body};
 
        } else {
                // type switch
                // TODO do all the checks!
-               lbrace := P.expect(token.LBRACE);
+               lbrace := p.expect(token.LBRACE);
                cases := vector.New(0);
-               for P.tok == token.CASE || P.tok == token.DEFAULT {
-                       cases.Push(P.parseTypeCaseClause());
+               for p.tok == token.CASE || p.tok == token.DEFAULT {
+                       cases.Push(p.parseTypeCaseClause());
                }
-               rbrace := P.expect(token.RBRACE);
-               P.opt_semi = true;
+               rbrace := p.expect(token.RBRACE);
+               p.opt_semi = true;
                body := &ast.BlockStmt{lbrace, asStmtList(cases), rbrace};
                return &ast.TypeSwitchStmt{pos, s1, s2, body};
        }
@@ -1397,79 +1397,79 @@ func (P *parser) parseSwitchStmt() ast.Stmt {
 }
 
 
-func (P *parser) parseCommClause() *ast.CommClause {
-       if P.trace {
-               defer un(trace(P, "CommClause"));
+func (p *parser) parseCommClause() *ast.CommClause {
+       if p.trace {
+               defer un(trace(p, "CommClause"));
        }
 
        // CommCase
-       loc := P.pos;
+       pos := p.pos;
        var tok token.Token;
        var lhs, rhs ast.Expr;
-       if P.tok == token.CASE {
-               P.next();
-               if P.tok == token.ARROW {
+       if p.tok == token.CASE {
+               p.next();
+               if p.tok == token.ARROW {
                        // RecvExpr without assignment
-                       rhs = P.parseExpression(1);
+                       rhs = p.parseExpression(1);
                } else {
                        // SendExpr or RecvExpr
-                       rhs = P.parseExpression(1);
-                       if P.tok == token.ASSIGN || P.tok == token.DEFINE {
+                       rhs = p.parseExpression(1);
+                       if p.tok == token.ASSIGN || p.tok == token.DEFINE {
                                // RecvExpr with assignment
-                               tok = P.tok;
-                               P.next();
+                               tok = p.tok;
+                               p.next();
                                lhs = rhs;
-                               if P.tok == token.ARROW {
-                                       rhs = P.parseExpression(1);
+                               if p.tok == token.ARROW {
+                                       rhs = p.parseExpression(1);
                                } else {
-                                       P.expect(token.ARROW);  // use expect() error handling
+                                       p.expect(token.ARROW);  // use expect() error handling
                                }
                        }
                        // else SendExpr
                }
        } else {
-               P.expect(token.DEFAULT);
+               p.expect(token.DEFAULT);
        }
 
-       colon := P.expect(token.COLON);
-       body := P.parseStatementList();
+       colon := p.expect(token.COLON);
+       body := p.parseStatementList();
 
-       return &ast.CommClause{loc, tok, lhs, rhs, colon, body};
+       return &ast.CommClause{pos, tok, lhs, rhs, colon, body};
 }
 
 
-func (P *parser) parseSelectStmt() *ast.SelectStmt {
-       if P.trace {
-               defer un(trace(P, "SelectStmt"));
+func (p *parser) parseSelectStmt() *ast.SelectStmt {
+       if p.trace {
+               defer un(trace(p, "SelectStmt"));
        }
 
-       pos := P.expect(token.SELECT);
-       lbrace := P.expect(token.LBRACE);
+       pos := p.expect(token.SELECT);
+       lbrace := p.expect(token.LBRACE);
        cases := vector.New(0);
-       for P.tok == token.CASE || P.tok == token.DEFAULT {
-               cases.Push(P.parseCommClause());
+       for p.tok == token.CASE || p.tok == token.DEFAULT {
+               cases.Push(p.parseCommClause());
        }
-       rbrace := P.expect(token.RBRACE);
-       P.opt_semi = true;
+       rbrace := p.expect(token.RBRACE);
+       p.opt_semi = true;
        body := &ast.BlockStmt{lbrace, asStmtList(cases), rbrace};
 
        return &ast.SelectStmt{pos, body};
 }
 
 
-func (P *parser) parseForStmt() ast.Stmt {
-       if P.trace {
-               defer un(trace(P, "ForStmt"));
+func (p *parser) parseForStmt() ast.Stmt {
+       if p.trace {
+               defer un(trace(p, "ForStmt"));
        }
 
-       pos := P.expect(token.FOR);
-       s1, s2, s3 := P.parseControlClause(true);
-       body := P.parseBlockStmt();
+       pos := p.expect(token.FOR);
+       s1, s2, s3 := p.parseControlClause(true);
+       body := p.parseBlockStmt();
 
        if as, is_as := s2.(*ast.AssignStmt); is_as {
                // possibly a for statement with a range clause; check assignment operator
                if as.Tok != token.ASSIGN && as.Tok != token.DEFINE {
-                       P.error(as.TokPos, "'=' or ':=' expected");
+                       p.error(as.TokPos, "'=' or ':=' expected");
                        return &ast.BadStmt{pos};
                }
                // check lhs
@@ -1481,24 +1481,24 @@ func (P *parser) parseForStmt() ast.Stmt {
                case 1:
                        key = as.Lhs[0];
                default:
-                       P.error(as.Lhs[0].Pos(), "expected 1 or 2 expressions");
+                       p.error(as.Lhs[0].Pos(), "expected 1 or 2 expressions");
                        return &ast.BadStmt{pos};
                }
                // check rhs
                if len(as.Rhs) != 1 {
-                       P.error(as.Rhs[0].Pos(), "expected 1 expressions");
+                       p.error(as.Rhs[0].Pos(), "expected 1 expressions");
                        return &ast.BadStmt{pos};
                }
                if rhs, is_unary := as.Rhs[0].(*ast.UnaryExpr); is_unary && rhs.Op == token.RANGE {
                        // rhs is range expression; check lhs
                        return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body}
                } else {
-                       P.error(s2.Pos(), "range clause expected");
+                       p.error(s2.Pos(), "range clause expected");
                        return &ast.BadStmt{pos};
                }
        } else {
                // regular for statement
-               return &ast.ForStmt{pos, s1, P.asExpr(s2), s3, body};
+               return &ast.ForStmt{pos, s1, p.asExpr(s2), s3, body};
        }
        
        unreachable();
@@ -1506,128 +1506,128 @@ func (P *parser) parseForStmt() ast.Stmt {
 }
 
 
-func (P *parser) parseStatement() ast.Stmt {
-       if P.trace {
-               defer un(trace(P, "Statement"));
+func (p *parser) parseStatement() ast.Stmt {
+       if p.trace {
+               defer un(trace(p, "Statement"));
        }
 
-       switch P.tok {
+       switch p.tok {
        case token.CONST, token.TYPE, token.VAR:
-               return &ast.DeclStmt{P.parseDeclaration()};
+               return &ast.DeclStmt{p.parseDeclaration()};
        case
                // tokens that may start a top-level expression
                token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING, token.FUNC, token.LPAREN,  // operand
                token.LBRACK, token.STRUCT,  // composite type
                token.MUL, token.AND, token.ARROW:  // unary operators
-               return P.parseSimpleStmt();
+               return p.parseSimpleStmt();
        case token.GO:
-               return P.parseGoStmt();
+               return p.parseGoStmt();
        case token.DEFER:
-               return P.parseDeferStmt();
+               return p.parseDeferStmt();
        case token.RETURN:
-               return P.parseReturnStmt();
+               return p.parseReturnStmt();
        case token.BREAK, token.CONTINUE, token.GOTO, token.FALLTHROUGH:
-               return P.parseBranchStmt(P.tok);
+               return p.parseBranchStmt(p.tok);
        case token.LBRACE:
-               return P.parseBlockStmt();
+               return p.parseBlockStmt();
        case token.IF:
-               return P.parseIfStmt();
+               return p.parseIfStmt();
        case token.FOR:
-               return P.parseForStmt();
+               return p.parseForStmt();
        case token.SWITCH:
-               return P.parseSwitchStmt();
+               return p.parseSwitchStmt();
        case token.SELECT:
-               return P.parseSelectStmt();
+               return p.parseSelectStmt();
        case token.SEMICOLON, token.RBRACE:
                // don't consume the ";", it is the separator following the empty statement
-               return &ast.EmptyStmt{P.pos};
+               return &ast.EmptyStmt{p.pos};
        }
 
        // no statement found
-       P.error(P.pos, "statement expected");
-       return &ast.BadStmt{P.pos};
+       p.error(p.pos, "statement expected");
+       return &ast.BadStmt{p.pos};
 }
 
 
 // ----------------------------------------------------------------------------
 // Declarations
 
-func (P *parser) parseImportSpec(pos token.Position, doc ast.Comments) *ast.ImportDecl {
-       if P.trace {
-               defer un(trace(P, "ImportSpec"));
+func (p *parser) parseImportSpec(pos token.Position, doc ast.Comments) *ast.ImportDecl {
+       if p.trace {
+               defer un(trace(p, "ImportSpec"));
        }
 
        var ident *ast.Ident;
-       if P.tok == token.PERIOD {
-               P.error(P.pos, `"import ." not yet handled properly`);
-               P.next();
-       } else if P.tok == token.IDENT {
-               ident = P.parseIdent();
+       if p.tok == token.PERIOD {
+               p.error(p.pos, `"import ." not yet handled properly`);
+               p.next();
+       } else if p.tok == token.IDENT {
+               ident = p.parseIdent();
        }
 
        var path []*ast.StringLit;
-       if P.tok == token.STRING {
-               path = P.parseStringList(nil);
+       if p.tok == token.STRING {
+               path = p.parseStringList(nil);
        } else {
-               P.expect(token.STRING);  // use expect() error handling
+               p.expect(token.STRING);  // use expect() error handling
        }
 
        return &ast.ImportDecl{doc, pos, ident, path};
 }
 
 
-func (P *parser) parseConstSpec(pos token.Position, doc ast.Comments) *ast.ConstDecl {
-       if P.trace {
-               defer un(trace(P, "ConstSpec"));
+func (p *parser) parseConstSpec(pos token.Position, doc ast.Comments) *ast.ConstDecl {
+       if p.trace {
+               defer un(trace(p, "ConstSpec"));
        }
 
-       names := P.parseIdentList(nil);
-       typ := P.tryType();
+       names := p.parseIdentList(nil);
+       typ := p.tryType();
        var values []ast.Expr;
-       if typ != nil || P.tok == token.ASSIGN {
-               P.expect(token.ASSIGN);
-               values = P.parseExpressionList();
+       if typ != nil || p.tok == token.ASSIGN {
+               p.expect(token.ASSIGN);
+               values = p.parseExpressionList();
        }
 
        return &ast.ConstDecl{doc, pos, names, typ, values};
 }
 
 
-func (P *parser) parseTypeSpec(pos token.Position, doc ast.Comments) *ast.TypeDecl {
-       if P.trace {
-               defer un(trace(P, "TypeSpec"));
+func (p *parser) parseTypeSpec(pos token.Position, doc ast.Comments) *ast.TypeDecl {
+       if p.trace {
+               defer un(trace(p, "TypeSpec"));
        }
 
-       ident := P.parseIdent();
-       typ := P.parseType();
+       ident := p.parseIdent();
+       typ := p.parseType();
 
        return &ast.TypeDecl{doc, pos, ident, typ};
 }
 
 
-func (P *parser) parseVarSpec(pos token.Position, doc ast.Comments) *ast.VarDecl {
-       if P.trace {
-               defer un(trace(P, "VarSpec"));
+func (p *parser) parseVarSpec(pos token.Position, doc ast.Comments) *ast.VarDecl {
+       if p.trace {
+               defer un(trace(p, "VarSpec"));
        }
 
-       names := P.parseIdentList(nil);
-       typ := P.tryType();
+       names := p.parseIdentList(nil);
+       typ := p.tryType();
        var values []ast.Expr;
-       if typ == nil || P.tok == token.ASSIGN {
-               P.expect(token.ASSIGN);
-               values = P.parseExpressionList();
+       if typ == nil || p.tok == token.ASSIGN {
+               p.expect(token.ASSIGN);
+               values = p.parseExpressionList();
        }
 
        return &ast.VarDecl{doc, pos, names, typ, values};
 }
 
 
-func (P *parser) parseSpec(pos token.Position, doc ast.Comments, keyword int) ast.Decl {
+func (p *parser) parseSpec(pos token.Position, doc ast.Comments, keyword int) ast.Decl {
        switch keyword {
-       case token.IMPORT: return P.parseImportSpec(pos, doc);
-       case token.CONST: return P.parseConstSpec(pos, doc);
-       case token.TYPE: return P.parseTypeSpec(pos, doc);
-       case token.VAR: return P.parseVarSpec(pos, doc);
+       case token.IMPORT: return p.parseImportSpec(pos, doc);
+       case token.CONST: return p.parseConstSpec(pos, doc);
+       case token.TYPE: return p.parseTypeSpec(pos, doc);
+       case token.VAR: return p.parseVarSpec(pos, doc);
        }
 
        unreachable();
@@ -1635,27 +1635,27 @@ func (P *parser) parseSpec(pos token.Position, doc ast.Comments, keyword int) as
 }
 
 
-func (P *parser) parseDecl(keyword int) ast.Decl {
-       if P.trace {
-               defer un(trace(P, "Decl"));
+func (p *parser) parseDecl(keyword int) ast.Decl {
+       if p.trace {
+               defer un(trace(p, "Decl"));
        }
 
-       doc := P.getDoc();
-       pos := P.expect(keyword);
-       if P.tok == token.LPAREN {
-               lparen := P.pos;
-               P.next();
+       doc := p.getDoc();
+       pos := p.expect(keyword);
+       if p.tok == token.LPAREN {
+               lparen := p.pos;
+               p.next();
                list := vector.New(0);
-               for P.tok != token.RPAREN && P.tok != token.EOF {
-                       list.Push(P.parseSpec(nopos, nil, keyword));
-                       if P.tok == token.SEMICOLON {
-                               P.next();
+               for p.tok != token.RPAREN && p.tok != token.EOF {
+                       list.Push(p.parseSpec(nopos, nil, keyword));
+                       if p.tok == token.SEMICOLON {
+                               p.next();
                        } else {
                                break;
                        }
                }
-               rparen := P.expect(token.RPAREN);
-               P.opt_semi = true;
+               rparen := p.expect(token.RPAREN);
+               p.opt_semi = true;
 
                // convert vector
                decls := make([]ast.Decl, list.Len());
@@ -1666,7 +1666,7 @@ func (P *parser) parseDecl(keyword int) ast.Decl {
                return &ast.DeclList{doc, pos, keyword, lparen, decls, rparen};
        }
 
-       return P.parseSpec(pos, doc, keyword);
+       return p.parseSpec(pos, doc, keyword);
 }
 
 
@@ -1679,53 +1679,53 @@ func (P *parser) parseDecl(keyword int) ast.Decl {
 // func (recv) ident (params) type
 // func (recv) ident (params) (results)
 
-func (P *parser) parseFunctionDecl() *ast.FuncDecl {
-       if P.trace {
-               defer un(trace(P, "FunctionDecl"));
+func (p *parser) parseFunctionDecl() *ast.FuncDecl {
+       if p.trace {
+               defer un(trace(p, "FunctionDecl"));
        }
 
-       doc := P.getDoc();
-       pos := P.expect(token.FUNC);
+       doc := p.getDoc();
+       pos := p.expect(token.FUNC);
 
        var recv *ast.Field;
-       if P.tok == token.LPAREN {
-               loc := P.pos;
-               tmp := P.parseParameters(true);
+       if p.tok == token.LPAREN {
+               pos := p.pos;
+               tmp := p.parseParameters(true);
                if len(tmp) == 1 {
                        recv = tmp[0];
                } else {
-                       P.error(loc, "must have exactly one receiver");
+                       p.error(pos, "must have exactly one receiver");
                }
        }
 
-       ident := P.parseIdent();
-       params, results := P.parseSignature();
+       ident := p.parseIdent();
+       params, results := p.parseSignature();
 
        var body *ast.BlockStmt;
-       if P.tok == token.LBRACE {
-               body = P.parseBlockStmt();
+       if p.tok == token.LBRACE {
+               body = p.parseBlockStmt();
        }
 
        return &ast.FuncDecl{doc, recv, ident, &ast.FunctionType{pos, params, results}, body};
 }
 
 
-func (P *parser) parseDeclaration() ast.Decl {
-       if P.trace {
-               defer un(trace(P, "Declaration"));
+func (p *parser) parseDeclaration() ast.Decl {
+       if p.trace {
+               defer un(trace(p, "Declaration"));
        }
 
-       switch P.tok {
+       switch p.tok {
        case token.CONST, token.TYPE, token.VAR:
-               return P.parseDecl(P.tok);
+               return p.parseDecl(p.tok);
        case token.FUNC:
-               return P.parseFunctionDecl();
+               return p.parseFunctionDecl();
        }
 
-       loc := P.pos;
-       P.error(loc, "declaration expected");
-       P.next();  // make progress
-       return &ast.BadDecl{loc};
+       pos := p.pos;
+       p.error(pos, "declaration expected");
+       p.next();  // make progress
+       return &ast.BadDecl{pos};
 }
 
 
@@ -1741,19 +1741,19 @@ const (
 )
 
 
-func (P *parser) parsePackage(mode Mode) *ast.Package {
-       if P.trace {
-               defer un(trace(P, "Program"));
+func (p *parser) parsePackage(mode Mode) *ast.Package {
+       if p.trace {
+               defer un(trace(p, "Program"));
        }
 
        // package clause
-       comment := P.getDoc();
-       pos := P.expect(token.PACKAGE);
-       name := P.parseIdent();
-       if P.tok == token.SEMICOLON {
+       comment := p.getDoc();
+       pos := p.expect(token.PACKAGE);
+       name := p.parseIdent();
+       if p.tok == token.SEMICOLON {
                // common error
-               P.error(P.pos, "extra semicolon");
-               P.next();
+               p.error(p.pos, "extra semicolon");
+               p.next();
        }
        
        
@@ -1761,19 +1761,19 @@ func (P *parser) parsePackage(mode Mode) *ast.Package {
        if mode <= ParseImportDeclsOnly {
                // import decls
                list := vector.New(0);
-               for P.tok == token.IMPORT {
-                       list.Push(P.parseDecl(token.IMPORT));
-                       if P.tok == token.SEMICOLON {
-                               P.next();
+               for p.tok == token.IMPORT {
+                       list.Push(p.parseDecl(token.IMPORT));
+                       if p.tok == token.SEMICOLON {
+                               p.next();
                        }
                }
 
                if mode <= ParseEntirePackage {
                        // rest of package body
-                       for P.tok != token.EOF {
-                               list.Push(P.parseDeclaration());
-                               if P.tok == token.SEMICOLON {
-                                       P.next();
+                       for p.tok != token.EOF {
+                               list.Push(p.parseDeclaration());
+                               if p.tok == token.SEMICOLON {
+                                       p.next();
                                }
                        }
                }
@@ -1786,12 +1786,9 @@ func (P *parser) parsePackage(mode Mode) *ast.Package {
        }
 
        // convert comments list
-       comments := make([]*ast.Comment, P.comments.Len());
-       for i := 0; i < P.comments.Len(); i++ {
-               c := P.comments.At(i);
-               if c != nil {
-                       comments[i] = c.(*ast.Comment);
-               }
+       comments := make([]*ast.Comment, p.comments.Len());
+       for i := 0; i < p.comments.Len(); i++ {
+               comments[i] = p.comments.At(i).(*ast.Comment);
        }
 
        return &ast.Package{comment, pos, name, decls, comments};
@@ -1802,19 +1799,25 @@ func (P *parser) parsePackage(mode Mode) *ast.Package {
 // Parsing of entire programs.
 
 // Parse invokes the Go parser. It calls the scanner's Scan method repeatedly
-// to obtain the token sequence corresponding to the source code. The sequence
-// is parsed according to Go syntax and the corresponding abstract syntax tree
-// is constructed. The error handler err will be used to report syntax errors.
+// to obtain a token sequence which is parsed according to Go syntax. If an
+// error handler is provided (err != nil), it is invoked for each syntax error
+// encountered.
 //
-// If no syntax errors were encountered (i.e., if the error handler was never
-// called), the result is a correct AST. If errors were encountered, the AST
-// may only be constructed partially, with ast.BadX nodes representing the
-// fragments of source code that contained syntax errors.
+// Parse returns an AST and the number of syntax errors encountered. If the
+// error count is 0, the result is the correct AST for the token sequence
+// returned by the scanner (*). If the error count is > 0, the AST may only
+// be constructed partially, with ast.BadX nodes representing the fragments
+// of source code that contained syntax errors.
 //
 // The amount of source text parsed can be controlled with the mode parameter.
 // The flags parameter controls optional parser functionality such as tracing.
 //
-func Parse(scanner Scanner, err ErrorHandler, mode Mode, flags uint) *ast.Package {
+// (*) Note that a scanner may find lexical syntax errors but still return
+//     a legal token sequence. To be sure there are no syntax errors in the
+//     source (and not just the token sequence corresponding to the source)
+//     both the parser and scanner error count must be 0.
+//
+func Parse(scanner Scanner, err ErrorHandler, mode Mode, flags uint) (*ast.Package, int) {
        // initialize parser state
        var p parser;
        p.scanner = scanner;
@@ -1824,5 +1827,5 @@ func Parse(scanner Scanner, err ErrorHandler, mode Mode, flags uint) *ast.Packag
        p.next();
 
        // parse program
-       return p.parsePackage(mode);
+       return p.parsePackage(mode), p.errorCount;
 }