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
// 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;
}
}
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.
// 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;
}
+func (p *parser) expectSemi() {
+ if p.tok != token.RPAREN && p.tok != token.RBRACE {
+ p.expect(token.SEMICOLON)
+ }
+}
+
+
// ----------------------------------------------------------------------------
// Scope support
defer un(trace(p, "IdentList"))
}
- list := new(vector.Vector);
+ var list vector.Vector;
list.Push(p.parseIdent());
for p.tok == token.COMMA {
p.next();
}
+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);
}
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
// 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 {
}
}
- return &ast.Field{doc, idents, typ, tag, nil};
+ p.expectSemi();
+
+ return &ast.Field{doc, idents, typ, tag, p.lineComment};
}
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());
}
// 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;
}
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 {
// embedded interface
typ = x
}
+ p.expectSemi();
- return &ast.Field{doc, idents, typ, nil, nil};
+ return &ast.Field{doc, idents, typ, nil, p.lineComment};
}
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());
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"))
}
lbrace := p.expect(token.LBRACE);
list := p.parseStmtList();
rbrace := p.expect(token.RBRACE);
- p.optSemi = true;
return &ast.BlockStmt{lbrace, list, rbrace};
}
// ----------------------------------------------------------------------------
// 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"))
}
p.exprLev++;
- body := p.parseBlockStmt(nil);
- p.optSemi = false; // function body requires separating ";"
+ body := p.parseBlockStmt();
p.exprLev--;
return &ast.FuncLit{typ, body};
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:
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};
}
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);
}
// ----------------------------------------------------------------------------
// Statements
-
func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
if p.trace {
defer un(trace(p, "SimpleStmt"))
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};
}
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};
}
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};
}
if tok != token.FALLTHROUGH && p.tok == token.IDENT {
s.Label = p.parseIdent()
}
+ p.expectSemi();
return s;
}
}
if isForStmt {
// for statements have a 3rd section
- p.expect(token.SEMICOLON);
+ p.expectSemi();
if p.tok != token.LBRACE {
s3 = p.parseSimpleStmt(false)
}
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_};
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);
}
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};
}
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};
}
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
}
-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"))
}
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"))
}
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"))
}
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"))
}
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
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};
}
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"))
}
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);
}
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
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;
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())
}
}