]> Cypherpunks repositories - gostls13.git/commitdiff
parser changed to reflect new semicolon rules
authorRobert Griesemer <gri@golang.org>
Fri, 11 Dec 2009 23:31:24 +0000 (15:31 -0800)
committerRobert Griesemer <gri@golang.org>
Fri, 11 Dec 2009 23:31:24 +0000 (15:31 -0800)
R=rsc
https://golang.org/cl/175046

src/pkg/go/parser/parser.go
src/pkg/go/parser/parser_test.go

index 98f57d370243e3e65df50fd139c464491fd912fc..fa6fb545ed85cc57429b6b3d599828c78f0a84bd 100644 (file)
@@ -56,7 +56,6 @@ type parser struct {
        lit     []byte;         // token literal
 
        // Non-syntactic parser control
-       optSemi bool;   // true if semicolon separator is optional in statement list
        exprLev int;    // < 0: in control clause, >= 0: in expression
 
        // Scopes
@@ -68,10 +67,11 @@ type parser struct {
 
 // scannerMode returns the scanner mode bits given the parser's mode bits.
 func scannerMode(mode uint) uint {
+       var m uint = scanner.InsertSemis;
        if mode&ParseComments != 0 {
-               return scanner.ScanComments
+               m |= scanner.ScanComments
        }
-       return 0;
+       return m;
 }
 
 
@@ -133,10 +133,8 @@ func (p *parser) next0() {
        }
 
        p.pos, p.tok, p.lit = p.scanner.Scan();
-       p.optSemi = false;
 }
 
-
 // Consume a comment and return it and the line on which it ends.
 func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
        // /*-style comments may end on a different line than where they start.
@@ -163,7 +161,7 @@ func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
 // a comment group.
 //
 func (p *parser) consumeCommentGroup() int {
-       list := new(vector.Vector);
+       var list vector.Vector;
        endline := p.pos.Line;
        for p.tok == token.COMMENT && endline+1 >= p.pos.Line {
                var comment *ast.Comment;
@@ -262,6 +260,13 @@ func (p *parser) expect(tok token.Token) token.Position {
 }
 
 
+func (p *parser) expectSemi() {
+       if p.tok != token.RPAREN && p.tok != token.RBRACE {
+               p.expect(token.SEMICOLON)
+       }
+}
+
+
 // ----------------------------------------------------------------------------
 // Scope support
 
@@ -308,7 +313,7 @@ func (p *parser) parseIdentList() []*ast.Ident {
                defer un(trace(p, "IdentList"))
        }
 
-       list := new(vector.Vector);
+       var list vector.Vector;
        list.Push(p.parseIdent());
        for p.tok == token.COMMA {
                p.next();
@@ -325,25 +330,28 @@ func (p *parser) parseIdentList() []*ast.Ident {
 }
 
 
+func makeExprList(list *vector.Vector) []ast.Expr {
+       exprs := make([]ast.Expr, list.Len());
+       for i := 0; i < list.Len(); i++ {
+               exprs[i] = list.At(i).(ast.Expr)
+       }
+       return exprs;
+}
+
+
 func (p *parser) parseExprList() []ast.Expr {
        if p.trace {
                defer un(trace(p, "ExpressionList"))
        }
 
-       list := new(vector.Vector);
+       var list vector.Vector;
        list.Push(p.parseExpr());
        for p.tok == token.COMMA {
                p.next();
                list.Push(p.parseExpr());
        }
 
-       // convert list
-       exprs := make([]ast.Expr, list.Len());
-       for i := 0; i < list.Len(); i++ {
-               exprs[i] = list.At(i).(ast.Expr)
-       }
-
-       return exprs;
+       return makeExprList(&list);
 }
 
 
@@ -435,15 +443,14 @@ func (p *parser) parseFieldDecl() *ast.Field {
        doc := p.leadComment;
 
        // a list of identifiers looks like a list of type names
-       list := new(vector.Vector);
+       var list vector.Vector;
        for {
                // TODO(gri): do not allow ()'s here
                list.Push(p.parseType());
-               if p.tok == token.COMMA {
-                       p.next()
-               } else {
+               if p.tok != token.COMMA {
                        break
                }
+               p.next();
        }
 
        // if we had a list of identifiers, it must be followed by a type
@@ -452,14 +459,16 @@ func (p *parser) parseFieldDecl() *ast.Field {
        // optional tag
        var tag []*ast.BasicLit;
        if p.tok == token.STRING {
-               tag = p.parseStringList(nil)
+               x := &ast.BasicLit{p.pos, p.tok, p.lit};
+               p.next();
+               tag = []*ast.BasicLit{x};
        }
 
        // analyze case
        var idents []*ast.Ident;
        if typ != nil {
                // IdentifierList Type
-               idents = p.makeIdentList(list)
+               idents = p.makeIdentList(&list)
        } else {
                // Type (anonymous field)
                if list.Len() == 1 {
@@ -471,7 +480,9 @@ func (p *parser) parseFieldDecl() *ast.Field {
                }
        }
 
-       return &ast.Field{doc, idents, typ, tag, nil};
+       p.expectSemi();
+
+       return &ast.Field{doc, idents, typ, tag, p.lineComment};
 }
 
 
@@ -482,17 +493,11 @@ func (p *parser) parseStructType() *ast.StructType {
 
        pos := p.expect(token.STRUCT);
        lbrace := p.expect(token.LBRACE);
-       list := new(vector.Vector);
+       var list vector.Vector;
        for p.tok == token.IDENT || p.tok == token.MUL {
-               f := p.parseFieldDecl();
-               if p.tok != token.RBRACE {
-                       p.expect(token.SEMICOLON)
-               }
-               f.Comment = p.lineComment;
-               list.Push(f);
+               list.Push(p.parseFieldDecl())
        }
        rbrace := p.expect(token.RBRACE);
-       p.optSemi = true;
 
        // convert vector
        fields := make([]*ast.Field, list.Len());
@@ -547,21 +552,20 @@ func (p *parser) parseParameterDecl(ellipsisOk bool) (*vector.Vector, ast.Expr)
        }
 
        // a list of identifiers looks like a list of type names
-       list := new(vector.Vector);
+       var list vector.Vector;
        for {
                // TODO(gri): do not allow ()'s here
                list.Push(p.parseParameterType(ellipsisOk));
-               if p.tok == token.COMMA {
-                       p.next()
-               } else {
+               if p.tok != token.COMMA {
                        break
                }
+               p.next();
        }
 
        // if we had a list of identifiers, it must be followed by a type
        typ := p.tryParameterType(ellipsisOk);
 
-       return list, typ;
+       return &list, typ;
 }
 
 
@@ -576,12 +580,18 @@ func (p *parser) parseParameterList(ellipsisOk bool) []*ast.Field {
                idents := p.makeIdentList(list);
                list.Resize(0, 0);
                list.Push(&ast.Field{nil, idents, typ, nil, nil});
+               if p.tok == token.COMMA {
+                       p.next()
+               }
 
-               for p.tok == token.COMMA {
-                       p.next();
+               for p.tok != token.RPAREN && p.tok != token.EOF {
                        idents := p.parseIdentList();
                        typ := p.parseParameterType(ellipsisOk);
                        list.Push(&ast.Field{nil, idents, typ, nil, nil});
+                       if p.tok != token.COMMA {
+                               break
+                       }
+                       p.next();
                }
 
        } else {
@@ -680,8 +690,9 @@ func (p *parser) parseMethodSpec() *ast.Field {
                // embedded interface
                typ = x
        }
+       p.expectSemi();
 
-       return &ast.Field{doc, idents, typ, nil, nil};
+       return &ast.Field{doc, idents, typ, nil, p.lineComment};
 }
 
 
@@ -692,17 +703,11 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
 
        pos := p.expect(token.INTERFACE);
        lbrace := p.expect(token.LBRACE);
-       list := new(vector.Vector);
+       var list vector.Vector;
        for p.tok == token.IDENT {
-               m := p.parseMethodSpec();
-               if p.tok != token.RBRACE {
-                       p.expect(token.SEMICOLON)
-               }
-               m.Comment = p.lineComment;
-               list.Push(m);
+               list.Push(p.parseMethodSpec())
        }
        rbrace := p.expect(token.RBRACE);
-       p.optSemi = true;
 
        // convert vector
        methods := make([]*ast.Field, list.Len());
@@ -804,28 +809,16 @@ func (p *parser) parseStmtList() []ast.Stmt {
                defer un(trace(p, "StatementList"))
        }
 
-       list := new(vector.Vector);
-       expectSemi := false;
+       var list vector.Vector;
        for p.tok != token.CASE && p.tok != token.DEFAULT && p.tok != token.RBRACE && p.tok != token.EOF {
-               if expectSemi {
-                       p.expect(token.SEMICOLON);
-                       expectSemi = false;
-               }
-               list.Push(p.parseStmt());
-               if p.tok == token.SEMICOLON {
-                       p.next()
-               } else if p.optSemi {
-                       p.optSemi = false       // "consume" optional semicolon
-               } else {
-                       expectSemi = true
-               }
+               list.Push(p.parseStmt())
        }
 
-       return makeStmtList(list);
+       return makeStmtList(&list);
 }
 
 
-func (p *parser) parseBlockStmt(idents []*ast.Ident) *ast.BlockStmt {
+func (p *parser) parseBlockStmt() *ast.BlockStmt {
        if p.trace {
                defer un(trace(p, "BlockStmt"))
        }
@@ -835,7 +828,6 @@ func (p *parser) parseBlockStmt(idents []*ast.Ident) *ast.BlockStmt {
        lbrace := p.expect(token.LBRACE);
        list := p.parseStmtList();
        rbrace := p.expect(token.RBRACE);
-       p.optSemi = true;
 
        return &ast.BlockStmt{lbrace, list, rbrace};
 }
@@ -844,31 +836,6 @@ func (p *parser) parseBlockStmt(idents []*ast.Ident) *ast.BlockStmt {
 // ----------------------------------------------------------------------------
 // Expressions
 
-func (p *parser) parseStringList(x *ast.BasicLit) []*ast.BasicLit {
-       if p.trace {
-               defer un(trace(p, "StringList"))
-       }
-
-       list := new(vector.Vector);
-       if x != nil {
-               list.Push(x)
-       }
-
-       for p.tok == token.STRING {
-               list.Push(&ast.BasicLit{p.pos, token.STRING, p.lit});
-               p.next();
-       }
-
-       // convert list
-       strings := make([]*ast.BasicLit, list.Len());
-       for i := 0; i < list.Len(); i++ {
-               strings[i] = list.At(i).(*ast.BasicLit)
-       }
-
-       return strings;
-}
-
-
 func (p *parser) parseFuncTypeOrLit() ast.Expr {
        if p.trace {
                defer un(trace(p, "FuncTypeOrLit"))
@@ -881,8 +848,7 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
        }
 
        p.exprLev++;
-       body := p.parseBlockStmt(nil);
-       p.optSemi = false;      // function body requires separating ";"
+       body := p.parseBlockStmt();
        p.exprLev--;
 
        return &ast.FuncLit{typ, body};
@@ -904,9 +870,6 @@ func (p *parser) parseOperand() ast.Expr {
        case token.INT, token.FLOAT, token.CHAR, token.STRING:
                x := &ast.BasicLit{p.pos, p.tok, p.lit};
                p.next();
-               if p.tok == token.STRING && p.tok == token.STRING {
-                       return &ast.StringList{p.parseStringList(x)}
-               }
                return x;
 
        case token.LPAREN:
@@ -993,14 +956,18 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
 
        lparen := p.expect(token.LPAREN);
        p.exprLev++;
-       var args []ast.Expr;
-       if p.tok != token.RPAREN {
-               args = p.parseExprList()
+       var list vector.Vector;
+       for p.tok != token.RPAREN && p.tok != token.EOF {
+               list.Push(p.parseExpr());
+               if p.tok != token.COMMA {
+                       break
+               }
+               p.next();
        }
        p.exprLev--;
        rparen := p.expect(token.RPAREN);
 
-       return &ast.CallExpr{fun, lparen, args, rparen};
+       return &ast.CallExpr{fun, lparen, makeExprList(&list), rparen};
 }
 
 
@@ -1025,23 +992,16 @@ func (p *parser) parseElementList() []ast.Expr {
                defer un(trace(p, "ElementList"))
        }
 
-       list := new(vector.Vector);
+       var list vector.Vector;
        for p.tok != token.RBRACE && p.tok != token.EOF {
                list.Push(p.parseElement());
-               if p.tok == token.COMMA {
-                       p.next()
-               } else {
+               if p.tok != token.COMMA {
                        break
                }
+               p.next();
        }
 
-       // convert list
-       elts := make([]ast.Expr, list.Len());
-       for i := 0; i < list.Len(); i++ {
-               elts[i] = list.At(i).(ast.Expr)
-       }
-
-       return elts;
+       return makeExprList(&list);
 }
 
 
@@ -1250,7 +1210,6 @@ func (p *parser) parseExpr() ast.Expr {
 // ----------------------------------------------------------------------------
 // Statements
 
-
 func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
        if p.trace {
                defer un(trace(p, "SimpleStmt"))
@@ -1319,10 +1278,12 @@ func (p *parser) parseGoStmt() ast.Stmt {
 
        pos := p.expect(token.GO);
        call := p.parseCallExpr();
-       if call != nil {
-               return &ast.GoStmt{pos, call}
+       p.expectSemi();
+       if call == nil {
+               return &ast.BadStmt{pos}
        }
-       return &ast.BadStmt{pos};
+
+       return &ast.GoStmt{pos, call};
 }
 
 
@@ -1333,10 +1294,12 @@ func (p *parser) parseDeferStmt() ast.Stmt {
 
        pos := p.expect(token.DEFER);
        call := p.parseCallExpr();
-       if call != nil {
-               return &ast.DeferStmt{pos, call}
+       p.expectSemi();
+       if call == nil {
+               return &ast.BadStmt{pos}
        }
-       return &ast.BadStmt{pos};
+
+       return &ast.DeferStmt{pos, call};
 }
 
 
@@ -1348,9 +1311,10 @@ func (p *parser) parseReturnStmt() *ast.ReturnStmt {
        pos := p.pos;
        p.expect(token.RETURN);
        var x []ast.Expr;
-       if p.tok != token.SEMICOLON && p.tok != token.CASE && p.tok != token.DEFAULT && p.tok != token.RBRACE {
+       if p.tok != token.SEMICOLON && p.tok != token.RBRACE {
                x = p.parseExprList()
        }
+       p.expectSemi();
 
        return &ast.ReturnStmt{pos, x};
 }
@@ -1366,6 +1330,7 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
        if tok != token.FALLTHROUGH && p.tok == token.IDENT {
                s.Label = p.parseIdent()
        }
+       p.expectSemi();
 
        return s;
 }
@@ -1398,7 +1363,7 @@ func (p *parser) parseControlClause(isForStmt bool) (s1, s2, s3 ast.Stmt) {
                        }
                        if isForStmt {
                                // for statements have a 3rd section
-                               p.expect(token.SEMICOLON);
+                               p.expectSemi();
                                if p.tok != token.LBRACE {
                                        s3 = p.parseSimpleStmt(false)
                                }
@@ -1424,11 +1389,13 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
 
        pos := p.expect(token.IF);
        s1, s2, _ := p.parseControlClause(false);
-       body := p.parseBlockStmt(nil);
+       body := p.parseBlockStmt();
        var else_ ast.Stmt;
        if p.tok == token.ELSE {
                p.next();
                else_ = p.parseStmt();
+       } else {
+               p.expectSemi()
        }
 
        return &ast.IfStmt{pos, s1, p.makeExpr(s2), body, else_};
@@ -1465,20 +1432,14 @@ func (p *parser) parseTypeList() []ast.Expr {
                defer un(trace(p, "TypeList"))
        }
 
-       list := new(vector.Vector);
+       var list vector.Vector;
        list.Push(p.parseType());
        for p.tok == token.COMMA {
                p.next();
                list.Push(p.parseType());
        }
 
-       // convert list
-       exprs := make([]ast.Expr, list.Len());
-       for i := 0; i < list.Len(); i++ {
-               exprs[i] = list.At(i).(ast.Expr)
-       }
-
-       return exprs;
+       return makeExprList(&list);
 }
 
 
@@ -1534,26 +1495,26 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
 
        if isExprSwitch(s2) {
                lbrace := p.expect(token.LBRACE);
-               cases := new(vector.Vector);
+               var cases vector.Vector;
                for p.tok == token.CASE || p.tok == token.DEFAULT {
                        cases.Push(p.parseCaseClause())
                }
                rbrace := p.expect(token.RBRACE);
-               p.optSemi = true;
-               body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace};
+               body := &ast.BlockStmt{lbrace, makeStmtList(&cases), rbrace};
+               p.expectSemi();
                return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body};
        }
 
        // type switch
        // TODO(gri): do all the checks!
        lbrace := p.expect(token.LBRACE);
-       cases := new(vector.Vector);
+       var cases vector.Vector;
        for p.tok == token.CASE || p.tok == token.DEFAULT {
                cases.Push(p.parseTypeCaseClause())
        }
        rbrace := p.expect(token.RBRACE);
-       p.optSemi = true;
-       body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace};
+       p.expectSemi();
+       body := &ast.BlockStmt{lbrace, makeStmtList(&cases), rbrace};
        return &ast.TypeSwitchStmt{pos, s1, s2, body};
 }
 
@@ -1609,13 +1570,13 @@ func (p *parser) parseSelectStmt() *ast.SelectStmt {
 
        pos := p.expect(token.SELECT);
        lbrace := p.expect(token.LBRACE);
-       cases := new(vector.Vector);
+       var cases vector.Vector;
        for p.tok == token.CASE || p.tok == token.DEFAULT {
                cases.Push(p.parseCommClause())
        }
        rbrace := p.expect(token.RBRACE);
-       p.optSemi = true;
-       body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace};
+       p.expectSemi();
+       body := &ast.BlockStmt{lbrace, makeStmtList(&cases), rbrace};
 
        return &ast.SelectStmt{pos, body};
 }
@@ -1631,7 +1592,8 @@ func (p *parser) parseForStmt() ast.Stmt {
 
        pos := p.expect(token.FOR);
        s1, s2, s3 := p.parseControlClause(true);
-       body := p.parseBlockStmt(nil);
+       body := p.parseBlockStmt();
+       p.expectSemi();
 
        if as, isAssign := s2.(*ast.AssignStmt); isAssign {
                // possibly a for statement with a range clause; check assignment operator
@@ -1673,70 +1635,69 @@ func (p *parser) parseForStmt() ast.Stmt {
 }
 
 
-func (p *parser) parseStmt() ast.Stmt {
+func (p *parser) parseStmt() (s ast.Stmt) {
        if p.trace {
                defer un(trace(p, "Statement"))
        }
 
        switch p.tok {
        case token.CONST, token.TYPE, token.VAR:
-               decl, _ := p.parseDecl(false);  // do not consume trailing semicolon
-               return &ast.DeclStmt{decl};
+               s = &ast.DeclStmt{p.parseDecl()}
        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, token.ADD, token.SUB, token.XOR:     // unary operators
-               return p.parseSimpleStmt(true)
+               s = p.parseSimpleStmt(true);
+               // because of the required look-ahead, labeled statements are
+               // parsed by parseSimpleStmt - don't expect a semicolon after
+               // them
+               if _, isLabeledStmt := s.(*ast.LabeledStmt); !isLabeledStmt {
+                       p.expectSemi()
+               }
        case token.GO:
-               return p.parseGoStmt()
+               s = p.parseGoStmt()
        case token.DEFER:
-               return p.parseDeferStmt()
+               s = p.parseDeferStmt()
        case token.RETURN:
-               return p.parseReturnStmt()
+               s = p.parseReturnStmt()
        case token.BREAK, token.CONTINUE, token.GOTO, token.FALLTHROUGH:
-               return p.parseBranchStmt(p.tok)
+               s = p.parseBranchStmt(p.tok)
        case token.LBRACE:
-               return p.parseBlockStmt(nil)
+               s = p.parseBlockStmt();
+               p.expectSemi();
        case token.IF:
-               return p.parseIfStmt()
+               s = p.parseIfStmt()
        case token.SWITCH:
-               return p.parseSwitchStmt()
+               s = p.parseSwitchStmt()
        case token.SELECT:
-               return p.parseSelectStmt()
+               s = p.parseSelectStmt()
        case token.FOR:
-               return p.parseForStmt()
-       case token.SEMICOLON, token.RBRACE:
-               // don't consume the ";", it is the separator following the empty statement
-               return &ast.EmptyStmt{p.pos}
+               s = p.parseForStmt()
+       case token.SEMICOLON:
+               p.next();
+               fallthrough;
+       case token.RBRACE:
+               // a semicolon may be omitted before a closing "}"
+               s = &ast.EmptyStmt{p.pos}
+       default:
+               // no statement found
+               p.errorExpected(p.pos, "statement");
+               p.next();       // make progress
+               s = &ast.BadStmt{p.pos};
        }
 
-       // no statement found
-       p.errorExpected(p.pos, "statement");
-       p.next();       // make progress
-       return &ast.BadStmt{p.pos};
+       return;
 }
 
 
 // ----------------------------------------------------------------------------
 // Declarations
 
-type parseSpecFunction func(p *parser, doc *ast.CommentGroup, getSemi bool) (spec ast.Spec, gotSemi bool)
+type parseSpecFunction func(p *parser, doc *ast.CommentGroup) ast.Spec
 
 
-// Consume semicolon if there is one and getSemi is set, and get any line comment.
-// Return the comment if any and indicate if a semicolon was consumed.
-//
-func (p *parser) parseComment(getSemi bool) (comment *ast.CommentGroup, gotSemi bool) {
-       if getSemi && p.tok == token.SEMICOLON {
-               p.next();
-               gotSemi = true;
-       }
-       return p.lineComment, gotSemi;
-}
-
-
-func parseImportSpec(p *parser, doc *ast.CommentGroup, getSemi bool) (spec ast.Spec, gotSemi bool) {
+func parseImportSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
        if p.trace {
                defer un(trace(p, "ImportSpec"))
        }
@@ -1751,18 +1712,19 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup, getSemi bool) (spec ast.S
 
        var path []*ast.BasicLit;
        if p.tok == token.STRING {
-               path = p.parseStringList(nil)
+               x := &ast.BasicLit{p.pos, p.tok, p.lit};
+               p.next();
+               path = []*ast.BasicLit{x};
        } else {
                p.expect(token.STRING)  // use expect() error handling
        }
+       p.expectSemi();
 
-       comment, gotSemi := p.parseComment(getSemi);
-
-       return &ast.ImportSpec{doc, ident, path, comment}, gotSemi;
+       return &ast.ImportSpec{doc, ident, path, p.lineComment};
 }
 
 
-func parseConstSpec(p *parser, doc *ast.CommentGroup, getSemi bool) (spec ast.Spec, gotSemi bool) {
+func parseConstSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
        if p.trace {
                defer un(trace(p, "ConstSpec"))
        }
@@ -1774,26 +1736,26 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup, getSemi bool) (spec ast.Sp
                p.expect(token.ASSIGN);
                values = p.parseExprList();
        }
-       comment, gotSemi := p.parseComment(getSemi);
+       p.expectSemi();
 
-       return &ast.ValueSpec{doc, idents, typ, values, comment}, gotSemi;
+       return &ast.ValueSpec{doc, idents, typ, values, p.lineComment};
 }
 
 
-func parseTypeSpec(p *parser, doc *ast.CommentGroup, getSemi bool) (spec ast.Spec, gotSemi bool) {
+func parseTypeSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
        if p.trace {
                defer un(trace(p, "TypeSpec"))
        }
 
        ident := p.parseIdent();
        typ := p.parseType();
-       comment, gotSemi := p.parseComment(getSemi);
+       p.expectSemi();
 
-       return &ast.TypeSpec{doc, ident, typ, comment}, gotSemi;
+       return &ast.TypeSpec{doc, ident, typ, p.lineComment};
 }
 
 
-func parseVarSpec(p *parser, doc *ast.CommentGroup, getSemi bool) (spec ast.Spec, gotSemi bool) {
+func parseVarSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
        if p.trace {
                defer un(trace(p, "VarSpec"))
        }
@@ -1805,13 +1767,13 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup, getSemi bool) (spec ast.Spec
                p.expect(token.ASSIGN);
                values = p.parseExprList();
        }
-       comment, gotSemi := p.parseComment(getSemi);
+       p.expectSemi();
 
-       return &ast.ValueSpec{doc, idents, typ, values, comment}, gotSemi;
+       return &ast.ValueSpec{doc, idents, typ, values, p.lineComment};
 }
 
 
-func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction, getSemi bool) (decl *ast.GenDecl, gotSemi bool) {
+func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
        if p.trace {
                defer un(trace(p, keyword.String()+"Decl"))
        }
@@ -1819,30 +1781,17 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction, getSemi
        doc := p.leadComment;
        pos := p.expect(keyword);
        var lparen, rparen token.Position;
-       list := new(vector.Vector);
+       var list vector.Vector;
        if p.tok == token.LPAREN {
                lparen = p.pos;
                p.next();
                for p.tok != token.RPAREN && p.tok != token.EOF {
-                       doc := p.leadComment;
-                       spec, semi := f(p, doc, true);  // consume semicolon if any
-                       list.Push(spec);
-                       if !semi {
-                               break
-                       }
+                       list.Push(f(p, p.leadComment))
                }
                rparen = p.expect(token.RPAREN);
-
-               if getSemi && p.tok == token.SEMICOLON {
-                       p.next();
-                       gotSemi = true;
-               } else {
-                       p.optSemi = true
-               }
+               p.expectSemi();
        } else {
-               spec, semi := f(p, nil, getSemi);
-               list.Push(spec);
-               gotSemi = semi;
+               list.Push(f(p, nil))
        }
 
        // convert vector
@@ -1851,7 +1800,7 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction, getSemi
                specs[i] = list.At(i).(ast.Spec)
        }
 
-       return &ast.GenDecl{doc, pos, keyword, lparen, specs, rparen}, gotSemi;
+       return &ast.GenDecl{doc, pos, keyword, lparen, specs, rparen};
 }
 
 
@@ -1902,14 +1851,15 @@ func (p *parser) parseFunctionDecl() *ast.FuncDecl {
 
        var body *ast.BlockStmt;
        if p.tok == token.LBRACE {
-               body = p.parseBlockStmt(nil)
+               body = p.parseBlockStmt()
        }
+       p.expectSemi();
 
        return &ast.FuncDecl{doc, recv, ident, &ast.FuncType{pos, params, results}, body};
 }
 
 
-func (p *parser) parseDecl(getSemi bool) (decl ast.Decl, gotSemi bool) {
+func (p *parser) parseDecl() ast.Decl {
        if p.trace {
                defer un(trace(p, "Declaration"))
        }
@@ -1926,20 +1876,17 @@ func (p *parser) parseDecl(getSemi bool) (decl ast.Decl, gotSemi bool) {
                f = parseVarSpec
 
        case token.FUNC:
-               decl = p.parseFunctionDecl();
-               _, gotSemi := p.parseComment(getSemi);
-               return decl, gotSemi;
+               return p.parseFunctionDecl()
 
        default:
                pos := p.pos;
                p.errorExpected(pos, "declaration");
-               decl = &ast.BadDecl{pos};
-               gotSemi = getSemi && p.tok == token.SEMICOLON;
+               decl := &ast.BadDecl{pos};
                p.next();       // make progress in any case
-               return decl, gotSemi;
+               return decl;
        }
 
-       return p.parseGenDecl(p.tok, f, getSemi);
+       return p.parseGenDecl(p.tok, f);
 }
 
 
@@ -1948,10 +1895,9 @@ func (p *parser) parseDeclList() []ast.Decl {
                defer un(trace(p, "DeclList"))
        }
 
-       list := new(vector.Vector);
+       var list vector.Vector;
        for p.tok != token.EOF {
-               decl, _ := p.parseDecl(true);   // consume optional semicolon
-               list.Push(decl);
+               list.Push(p.parseDecl())
        }
 
        // convert vector
@@ -1979,13 +1925,7 @@ func (p *parser) parseFile() *ast.File {
        doc := p.leadComment;
        pos := p.expect(token.PACKAGE);
        ident := p.parseIdent();
-
-       // Common error: semicolon after package clause.
-       // Accept and report it for better error synchronization.
-       if p.tok == token.SEMICOLON {
-               p.Error(p.pos, "expected declaration, found ';'");
-               p.next();
-       }
+       p.expectSemi();
 
        var decls []ast.Decl;
 
@@ -1994,17 +1934,15 @@ func (p *parser) parseFile() *ast.File {
 
        if p.ErrorCount() == 0 && p.mode&PackageClauseOnly == 0 {
                // import decls
-               list := new(vector.Vector);
+               var list vector.Vector;
                for p.tok == token.IMPORT {
-                       decl, _ := p.parseGenDecl(token.IMPORT, parseImportSpec, true); // consume optional semicolon
-                       list.Push(decl);
+                       list.Push(p.parseGenDecl(token.IMPORT, parseImportSpec))
                }
 
                if p.mode&ImportsOnly == 0 {
                        // rest of package body
                        for p.tok != token.EOF {
-                               decl, _ := p.parseDecl(true);   // consume optional semicolon
-                               list.Push(decl);
+                               list.Push(p.parseDecl())
                        }
                }
 
index 2aa1d436660a01429ed3dd0444cbdb8d53ae6057..ccb8a4511504c88c51d5321f00a570a8a43dcdc9 100644 (file)
@@ -29,9 +29,9 @@ func TestParseIllegalInputs(t *testing.T) {
 
 
 var validPrograms = []interface{}{
-       `package main`,
-       `package main import "fmt" func main() { fmt.Println("Hello, World!") }`,
-       `package main func main() { if f(T{}) {} }`,
+       `package main;`,
+       `package main; import "fmt"; func main() { fmt.Println("Hello, World!") }` + "\n",
+       `package main; func main() { if f(T{}) {} }` + "\n",
 }