From 97a08f7a813ce76ab05fddf5be27f9264d3f7a18 Mon Sep 17 00:00:00 2001
From: Robert Griesemer <gri@golang.org>
Date: Fri, 11 Dec 2009 15:31:24 -0800
Subject: [PATCH] parser changed to reflect new semicolon rules

R=rsc
https://golang.org/cl/175046
---
 src/pkg/go/parser/parser.go      | 390 +++++++++++++------------------
 src/pkg/go/parser/parser_test.go |   6 +-
 2 files changed, 167 insertions(+), 229 deletions(-)

diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go
index 98f57d3702..fa6fb545ed 100644
--- a/src/pkg/go/parser/parser.go
+++ b/src/pkg/go/parser/parser.go
@@ -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())
 			}
 		}
 
diff --git a/src/pkg/go/parser/parser_test.go b/src/pkg/go/parser/parser_test.go
index 2aa1d43666..ccb8a45115 100644
--- a/src/pkg/go/parser/parser_test.go
+++ b/src/pkg/go/parser/parser_test.go
@@ -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",
 }
 
 
-- 
2.30.9