diff options
author | Robert Griesemer <gri@golang.org> | 2009-03-20 17:18:48 -0700 |
---|---|---|
committer | Robert Griesemer <gri@golang.org> | 2009-03-20 17:18:48 -0700 |
commit | 21bbab179109ac1e7b114adb7e6951392e84cc17 (patch) | |
tree | ac8f61c0bdf9479c947fbec61171add3ef4a5384 /usr/gri/pretty/parser.go | |
parent | 3308a5032636f93ce81335c42c4a31e5a42c80b5 (diff) | |
download | golang-21bbab179109ac1e7b114adb7e6951392e84cc17.tar.gz |
- completed AST cleanup
- implemented support for type switches
R=r
OCL=26608
CL=26608
Diffstat (limited to 'usr/gri/pretty/parser.go')
-rw-r--r-- | usr/gri/pretty/parser.go | 836 |
1 files changed, 429 insertions, 407 deletions
diff --git a/usr/gri/pretty/parser.go b/usr/gri/pretty/parser.go index ffe9615c9..5c13e5998 100644 --- a/usr/gri/pretty/parser.go +++ b/usr/gri/pretty/parser.go @@ -25,6 +25,11 @@ import ( type Position scanner.Location +type interval struct { + beg, end int; +} + + // A Parser holds the parser's internal state while processing // a given text. It can be allocated as part of another data // structure but must be initialized via Init before use. @@ -37,11 +42,11 @@ type Parser struct { trace bool; indent uint; - comments vector.Vector; - last_comment ast.CommentGroup; + comments vector.Vector; // list of collected, unassociated comments + last_doc interval; // last comments interval of consecutive comments // The next token - loc Position; // token location + pos Position; // token location tok int; // one token look-ahead val []byte; // token value @@ -51,9 +56,9 @@ type Parser struct { }; -// When we don't have a location use noloc. +// When we don't have a location use nopos. // TODO make sure we always have a location. -var noloc Position; +var nopos Position; // ---------------------------------------------------------------------------- @@ -95,32 +100,35 @@ func un/*trace*/(P *Parser) { func (P *Parser) next0() { - P.loc, P.tok, P.val = P.scanner.Scan(); + P.pos, P.tok, P.val = P.scanner.Scan(); P.opt_semi = false; 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.loc.Line, P.loc.Col, token.TokenString(P.tok), P.val); + fmt.Printf("%d:%d: %s = %s\n", P.pos.Line, P.pos.Col, token.TokenString(P.tok), P.val); case token.LPAREN: // don't print '(' - screws up selection in terminal window - fmt.Printf("%d:%d: LPAREN\n", P.loc.Line, P.loc.Col); + fmt.Printf("%d:%d: LPAREN\n", P.pos.Line, P.pos.Col); case token.RPAREN: // don't print ')' - screws up selection in terminal window - fmt.Printf("%d:%d: RPAREN\n", P.loc.Line, P.loc.Col); + fmt.Printf("%d:%d: RPAREN\n", P.pos.Line, P.pos.Col); default: - fmt.Printf("%d:%d: %s\n", P.loc.Line, P.loc.Col, token.TokenString(P.tok)); + fmt.Printf("%d:%d: %s\n", P.pos.Line, P.pos.Col, token.TokenString(P.tok)); } } } -func (P *Parser) getComment() *ast.Comment { - defer P.next0(); - - // for /*-style comments, the comment may end on a different line - endline := P.loc.Line; +// Collect a comment in the parser's comment list and return the line +// on which the comment ends. +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.val[1] == '*' { for i, b := range P.val { if b == '\n' { @@ -128,51 +136,30 @@ func (P *Parser) getComment() *ast.Comment { } } } + P.comments.Push(&ast.Comment{P.pos, P.val, endline}); + P.next0(); - return &ast.Comment{P.loc, endline, P.val}; -} - - -func (P *Parser) getCommentGroup() ast.CommentGroup { - list := vector.New(0); - - // group adjacent comments - // (an empty line terminates a group) - endline := P.loc.Line; - for P.tok == token.COMMENT && endline+1 >= P.loc.Line { - c := P.getComment(); - list.Push(c); - endline = c.EndLine; - } - - // convert list - group := make(ast.CommentGroup, list.Len()); - for i := 0; i < list.Len(); i++ { - group[i] = list.At(i).(*ast.Comment); - } - - return group; + return endline; } -func (P *Parser) getLastComment() ast.CommentGroup { - c := P.last_comment; - if c != nil && c[len(c) - 1].EndLine + 1 < P.loc.Line { - // empty line between last comment and current token, - // at least one line of space between last comment - // and current token; ignore this comment - return nil; +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(); } - return c; + end := P.comments.Len(); + return interval {beg, end}; } func (P *Parser) next() { P.next0(); - P.last_comment = nil; + P.last_doc = interval{0, 0}; for P.tok == token.COMMENT { - P.last_comment = P.getCommentGroup(); - P.comments.Push(P.last_comment); + P.last_doc = P.getComments(); } } @@ -186,8 +173,8 @@ func (P *Parser) Init(scanner *scanner.Scanner, err scanner.ErrorHandler, trace } -func (P *Parser) error(loc Position, msg string) { - P.err.Error(loc, msg); +func (P *Parser) error(pos Position, msg string) { + P.err.Error(pos, msg); } @@ -197,14 +184,36 @@ func (P *Parser) expect(tok int) Position { if token.IsLiteral(P.tok) { msg += " " + string(P.val); } - P.error(P.loc, msg); + P.error(P.pos, msg); } - loc := P.loc; + loc := P.pos; P.next(); // make progress in any case return loc; } +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 { + // no comments or empty line between last comment and current token; + // do not use as documentation + return nil; + } + + // found immediately adjacent comment interval; + // 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 + } + return c; +} + + // ---------------------------------------------------------------------------- // Common productions @@ -220,13 +229,13 @@ func (P *Parser) parseIdent() *ast.Ident { } if P.tok == token.IDENT { - x := &ast.Ident{string(P.val), P.loc}; + x := &ast.Ident{P.pos, P.val}; P.next(); return x; } - P.expect(token.IDENT); // use expect() error handling - return &ast.Ident{"", P.loc}; + + return &ast.Ident{P.pos, [0]byte{}}; } @@ -250,6 +259,7 @@ func (P *Parser) parseIdentList(x ast.Expr) []*ast.Ident { for i := 0; i < list.Len(); i++ { idents[i] = list.At(i).(*ast.Ident); } + return idents; } @@ -271,6 +281,7 @@ func (P *Parser) parseExpressionList() []ast.Expr { for i := 0; i < list.Len(); i++ { exprs[i] = list.At(i).(ast.Expr); } + return exprs; } @@ -283,13 +294,13 @@ func (P *Parser) parseType() ast.Expr { defer un(trace(P, "Type")); } - t := P.tryType(); - if t == nil { - P.error(P.loc, "type expected"); - t = &ast.BadExpr{P.loc}; + typ := P.tryType(); + if typ == nil { + P.error(P.pos, "type expected"); + typ = &ast.BadExpr{P.pos}; } - return t; + return typ; } @@ -309,12 +320,10 @@ func (P *Parser) parseQualifiedIdent() ast.Expr { var x ast.Expr = P.parseIdent(); for P.tok == token.PERIOD { - pos := P.loc; P.next(); sel := P.parseIdent(); - x = &ast.Selector{x, sel, pos}; + x = &ast.SelectorExpr{x, sel}; } - return x; } @@ -333,11 +342,10 @@ func (P *Parser) parseArrayType() *ast.ArrayType { defer un(trace(P, "ArrayType")); } - loc := P.loc; - P.expect(token.LBRACK); + lbrack := P.expect(token.LBRACK); var len ast.Expr; if P.tok == token.ELLIPSIS { - len = &ast.Ellipsis{P.loc}; + len = &ast.Ellipsis{P.pos}; P.next(); } else if P.tok != token.RBRACK { len = P.parseExpression(1); @@ -345,7 +353,7 @@ func (P *Parser) parseArrayType() *ast.ArrayType { P.expect(token.RBRACK); elt := P.parseType(); - return &ast.ArrayType{loc, len, elt}; + return &ast.ArrayType{lbrack, len, elt}; } @@ -354,28 +362,28 @@ func (P *Parser) parseChannelType() *ast.ChannelType { defer un(trace(P, "ChannelType")); } - loc := P.loc; - mode := ast.FULL; + pos := P.pos; + dir := ast.SEND | ast.RECV; if P.tok == token.CHAN { P.next(); if P.tok == token.ARROW { P.next(); - mode = ast.SEND; + dir = ast.SEND; } } else { P.expect(token.ARROW); P.expect(token.CHAN); - mode = ast.RECV; + dir = ast.RECV; } - val := P.parseVarType(); + value := P.parseVarType(); - return &ast.ChannelType{loc, mode, val}; + return &ast.ChannelType{pos, dir, value}; } func (P *Parser) tryParameterType() ast.Expr { if P.tok == token.ELLIPSIS { - loc := P.loc; + loc := P.pos; P.next(); return &ast.Ellipsis{loc}; } @@ -386,9 +394,10 @@ func (P *Parser) tryParameterType() ast.Expr { func (P *Parser) parseParameterType() ast.Expr { typ := P.tryParameterType(); if typ == nil { - P.error(P.loc, "type expected"); - typ = &ast.BadExpr{P.loc}; + P.error(P.pos, "type expected"); + typ = &ast.BadExpr{P.pos}; } + return typ; } @@ -431,20 +440,20 @@ func (P *Parser) parseParameterList(ellipsis_ok bool) []*ast.Field { idents[i] = list.At(i).(*ast.Ident); } list.Init(0); - list.Push(&ast.Field{idents, typ, nil, nil}); + list.Push(&ast.Field{nil, idents, typ, nil}); for P.tok == token.COMMA { P.next(); idents := P.parseIdentList(nil); typ := P.parseParameterType(); - list.Push(&ast.Field{idents, typ, nil, nil}); + list.Push(&ast.Field{nil, idents, typ, nil}); } } else { // Type { "," Type } // convert list of types into list of *Param for i := 0; i < list.Len(); i++ { - list.Set(i, &ast.Field{nil, list.At(i).(ast.Expr), nil, nil}); + list.Set(i, &ast.Field{nil, nil, list.At(i).(ast.Expr), nil}); } } @@ -487,7 +496,7 @@ func (P *Parser) parseResult() []*ast.Field { typ := P.tryType(); if typ != nil { result = make([]*ast.Field, 1); - result[0] = &ast.Field{nil, typ, nil, nil}; + result[0] = &ast.Field{nil, nil, typ, nil}; } } @@ -507,7 +516,7 @@ func (P *Parser) parseSignature() *ast.Signature { } params := P.parseParameters(true); // TODO find better solution - //t.End = P.loc; + //t.End = P.pos; result := P.parseResult(); return &ast.Signature{params, result}; @@ -519,11 +528,10 @@ func (P *Parser) parseFunctionType() *ast.FunctionType { defer un(trace(P, "FunctionType")); } - loc := P.loc; - P.expect(token.FUNC); + pos := P.expect(token.FUNC); sig := P.parseSignature(); - return &ast.FunctionType{loc, sig}; + return &ast.FunctionType{pos, sig}; } @@ -532,19 +540,20 @@ func (P *Parser) parseMethodSpec() *ast.Field { defer un(trace(P, "MethodSpec")); } + 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) { // method(s) idents = P.parseIdentList(x); - typ = &ast.FunctionType{noloc, P.parseSignature()}; + typ = &ast.FunctionType{nopos, P.parseSignature()}; } else { // embedded interface typ = x; } - return &ast.Field{idents, typ, nil, nil}; + return &ast.Field{doc, idents, typ, nil}; } @@ -553,12 +562,11 @@ func (P *Parser) parseInterfaceType() *ast.InterfaceType { defer un(trace(P, "InterfaceType")); } - loc := P.loc; - var end Position; + pos := P.expect(token.INTERFACE); + var lbrace, rbrace Position; var methods []*ast.Field; - - P.expect(token.INTERFACE); if P.tok == token.LBRACE { + lbrace = P.pos; P.next(); list := vector.New(0); @@ -569,8 +577,7 @@ func (P *Parser) parseInterfaceType() *ast.InterfaceType { } } - end = P.loc; - P.expect(token.RBRACE); + rbrace = P.expect(token.RBRACE); P.opt_semi = true; // convert vector @@ -580,7 +587,7 @@ func (P *Parser) parseInterfaceType() *ast.InterfaceType { } } - return &ast.InterfaceType{loc, methods, end}; + return &ast.InterfaceType{pos, lbrace, methods, rbrace}; } @@ -589,25 +596,24 @@ func (P *Parser) parseMapType() *ast.MapType { defer un(trace(P, "MapType")); } - loc := P.loc; - P.expect(token.MAP); + pos := P.expect(token.MAP); P.expect(token.LBRACK); key := P.parseVarType(); P.expect(token.RBRACK); - val := P.parseVarType(); + value := P.parseVarType(); - return &ast.MapType{loc, key, val}; + return &ast.MapType{pos, key, value}; } -func (P *Parser) parseStringLit() ast.Expr +func (P *Parser) parseStringLit(x *ast.BasicLit) *ast.StringLit func (P *Parser) parseFieldDecl() *ast.Field { if P.trace { defer un(trace(P, "FieldDecl")); } - comment := P.getLastComment(); + doc := P.getDoc(); // a list of identifiers looks like a list of type names list := vector.New(0); @@ -627,7 +633,7 @@ func (P *Parser) parseFieldDecl() *ast.Field { // optional tag var tag ast.Expr; if P.tok == token.STRING { - tag = P.parseStringLit(); + tag = P.parseStringLit(nil); } // analyze case @@ -648,25 +654,24 @@ func (P *Parser) parseFieldDecl() *ast.Field { // TODO should do more checks here typ = list.At(0).(ast.Expr); } else { - P.error(P.loc, "anonymous field expected"); + P.error(P.pos, "anonymous field expected"); } } - return &ast.Field{idents, typ, tag, comment}; + return &ast.Field{doc, idents, typ, tag}; } -func (P *Parser) parseStructType() ast.Expr { +func (P *Parser) parseStructType() *ast.StructType { if P.trace { defer un(trace(P, "StructType")); } - loc := P.loc; - var end Position; + pos := P.expect(token.STRUCT); + var lbrace, rbrace Position; var fields []*ast.Field; - - P.expect(token.STRUCT); if P.tok == token.LBRACE { + lbrace = P.pos; P.next(); list := vector.New(0); @@ -682,8 +687,7 @@ func (P *Parser) parseStructType() ast.Expr { P.next(); } - end = P.loc; - P.expect(token.RBRACE); + rbrace = P.expect(token.RBRACE); P.opt_semi = true; // convert vector @@ -693,20 +697,19 @@ func (P *Parser) parseStructType() ast.Expr { } } - return &ast.StructType{loc, fields, end}; + return &ast.StructType{pos, lbrace, fields, rbrace}; } -func (P *Parser) parsePointerType() ast.Expr { +func (P *Parser) parsePointerType() *ast.StarExpr { if P.trace { defer un(trace(P, "PointerType")); } - loc := P.loc; - P.expect(token.MUL); + star := P.expect(token.MUL); base := P.parseType(); - return &ast.PointerType{loc, base}; + return &ast.StarExpr{star, base}; } @@ -725,11 +728,11 @@ func (P *Parser) tryType() ast.Expr { case token.STRUCT: return P.parseStructType(); case token.MUL: return P.parsePointerType(); case token.LPAREN: - lparen := P.loc; + lparen := P.pos; P.next(); x := P.parseType(); rparen := P.expect(token.RPAREN); - return &ast.Group{x, lparen, rparen}; + return &ast.ParenExpr{lparen, x, rparen}; } // no type found @@ -740,12 +743,21 @@ func (P *Parser) tryType() ast.Expr { // ---------------------------------------------------------------------------- // Blocks +func asStatList(list *vector.Vector) []ast.Stat { + stats := make([]ast.Stat, list.Len()); + for i := 0; i < list.Len(); i++ { + stats[i] = list.At(i).(ast.Stat); + } + return stats; +} + -func (P *Parser) parseStatementList(list *vector.Vector) { +func (P *Parser) parseStatementList() []ast.Stat { 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 { if expect_semi { @@ -761,6 +773,8 @@ func (P *Parser) parseStatementList(list *vector.Vector) { expect_semi = true; } } + + return asStatList(list); } @@ -769,18 +783,15 @@ func (P *Parser) parseBlock(tok int) *ast.Block { defer un(trace(P, "Block")); } - b := ast.NewBlock(P.loc, tok); - P.expect(tok); - - P.parseStatementList(b.List); - + pos := P.expect(tok); + list := P.parseStatementList(); + var end scanner.Location; if tok == token.LBRACE { - b.End = P.loc; - P.expect(token.RBRACE); + end = P.expect(token.RBRACE); P.opt_semi = true; } - return b; + return &ast.Block{pos, tok, list, end}; } @@ -792,29 +803,28 @@ func (P *Parser) parseFunctionLit() ast.Expr { defer un(trace(P, "FunctionLit")); } - pos := P.loc; - P.expect(token.FUNC); + pos := P.expect(token.FUNC); typ := P.parseSignature(); P.expr_lev++; body := P.parseBlock(token.LBRACE); P.expr_lev--; - return &ast.FunctionLit{typ, body, pos}; + return &ast.FunctionLit{pos, typ, body}; } -func (P *Parser) parseStringLit() ast.Expr { +func (P *Parser) parseStringLit(x *ast.BasicLit) *ast.StringLit { if P.trace { defer un(trace(P, "StringLit")); } - if P.tok != token.STRING { - panic(); - } - list := vector.New(0); + if x != nil { + list.Push(x); + } + for P.tok == token.STRING { - list.Push(&ast.BasicLit{token.STRING, P.val, P.loc}); + list.Push(&ast.BasicLit{P.pos, token.STRING, P.val}); P.next(); } @@ -838,21 +848,26 @@ func (P *Parser) parseOperand() ast.Expr { return P.parseIdent(); case token.INT, token.FLOAT, token.CHAR: - x := &ast.BasicLit{P.tok, P.val, P.loc}; + x := &ast.BasicLit{P.pos, P.tok, P.val}; P.next(); return x; case token.STRING: - return P.parseStringLit(); + x := &ast.BasicLit{P.pos, token.STRING, P.val}; + P.next(); + if P.tok == token.STRING { + return P.parseStringLit(x); + } + return x; case token.LPAREN: - lparen := P.loc; + lparen := P.pos; P.next(); P.expr_lev++; x := P.parseExpression(1); P.expr_lev--; rparen := P.expect(token.RPAREN); - return &ast.Group{x, lparen, rparen}; + return &ast.ParenExpr{lparen, x, rparen}; case token.FUNC: return P.parseFunctionLit(); @@ -862,12 +877,12 @@ func (P *Parser) parseOperand() ast.Expr { if t != nil { return t; } else { - P.error(P.loc, "operand expected"); + P.error(P.pos, "operand expected"); P.next(); // make progress } } - return &ast.BadExpr{P.loc}; + return &ast.BadExpr{P.pos}; } @@ -876,25 +891,29 @@ func (P *Parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr { defer un(trace(P, "SelectorOrTypeAssertion")); } - period := P.expect(token.PERIOD); - + P.expect(token.PERIOD); if P.tok == token.IDENT { // selector sel := P.parseIdent(); - return &ast.Selector{x, sel, period}; - } - - // type assertion - lparen := P.expect(token.LPAREN); - var typ ast.Expr; - if P.tok == token.TYPE { - typ = &ast.TypeType{P.loc}; - P.next(); + return &ast.SelectorExpr{x, sel}; + } else { - typ = P.parseType(); + // type assertion + P.expect(token.LPAREN); + var typ ast.Expr; + if P.tok == token.TYPE { + // special case for type switch syntax + typ = &ast.Ident{P.pos, P.val}; + P.next(); + } else { + typ = P.parseType(); + } + P.expect(token.RPAREN); + return &ast.TypeAssertExpr{x, typ}; } - rparen := P.expect(token.RPAREN); - return &ast.TypeAssertion{x, typ, period, lparen, rparen}; + + unreachable(); + return nil; } @@ -903,29 +922,28 @@ func (P *Parser) parseIndexOrSlice(x ast.Expr) ast.Expr { defer un(trace(P, "IndexOrSlice")); } - lbrack := P.expect(token.LBRACK); + P.expect(token.LBRACK); P.expr_lev++; index := P.parseExpression(1); P.expr_lev--; if P.tok == token.RBRACK { // index - rbrack := P.loc; P.next(); - return &ast.Index{x, index, lbrack, rbrack}; + return &ast.IndexExpr{x, index}; } // slice - colon := P.expect(token.COLON); + P.expect(token.COLON); P.expr_lev++; end := P.parseExpression(1); P.expr_lev--; - rbrack := P.expect(token.RBRACK); - return &ast.Slice{x, index, end, lbrack, colon, rbrack}; + P.expect(token.RBRACK); + return &ast.SliceExpr{x, index, end}; } -func (P *Parser) parseCall(fun ast.Expr) *ast.Call { +func (P *Parser) parseCall(fun ast.Expr) *ast.CallExpr { if P.trace { defer un(trace(P, "Call")); } @@ -936,54 +954,7 @@ func (P *Parser) parseCall(fun ast.Expr) *ast.Call { args = P.parseExpressionList(); } rparen := P.expect(token.RPAREN); - return &ast.Call{fun, args, lparen, rparen}; -} - - -func (P *Parser) parseCompositeElements(close int) ast.Expr { - x := P.parseExpression(0); - if P.tok == token.COMMA { - loc := P.loc; - P.next(); - - // first element determines mode - singles := true; - if t, is_binary := x.(*ast.BinaryExpr); is_binary && t.Op == token.COLON { - singles = false; - } - - var last *ast.BinaryExpr; - for P.tok != close && P.tok != token.EOF { - y := P.parseExpression(0); - - if singles { - if t, is_binary := y.(*ast.BinaryExpr); is_binary && t.Op == token.COLON { - P.error(t.X.Pos(), "single value expected; found pair"); - } - } else { - if t, is_binary := y.(*ast.BinaryExpr); !is_binary || t.Op != token.COLON { - P.error(y.Pos(), "key:value pair expected; found single value"); - } - } - - if last == nil { - last = &ast.BinaryExpr{token.COMMA, x, y, loc}; - x = last; - } else { - last.Y = &ast.BinaryExpr{token.COMMA, last.Y, y, loc}; - last = last.Y.(*ast.BinaryExpr); - } - - if P.tok == token.COMMA { - loc = P.loc; - P.next(); - } else { - break; - } - - } - } - return x; + return &ast.CallExpr{fun, lparen, args, rparen}; } @@ -998,17 +969,17 @@ func (P *Parser) parseElementList() []ast.Expr { 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 { + if t, is_binary := x.(*ast.BinaryExpr); is_binary && t.Tok == token.COLON { singles = false; } } else { // not the first element - check syntax if singles { - if t, is_binary := x.(*ast.BinaryExpr); is_binary && t.Op == token.COLON { + if t, is_binary := x.(*ast.BinaryExpr); is_binary && t.Tok == token.COLON { P.error(t.X.Pos(), "single value expected; found pair"); } } else { - if t, is_binary := x.(*ast.BinaryExpr); !is_binary || t.Op != token.COLON { + if t, is_binary := x.(*ast.BinaryExpr); !is_binary || t.Tok != token.COLON { P.error(x.Pos(), "key:value pair expected; found single value"); } } @@ -1044,7 +1015,7 @@ func (P *Parser) parseCompositeLit(typ ast.Expr) ast.Expr { elts = P.parseElementList(); } rbrace := P.expect(token.RBRACE); - return &ast.CompositeLit{typ, elts, lbrace, rbrace}; + return &ast.CompositeLit{typ, lbrace, elts, rbrace}; } @@ -1081,11 +1052,18 @@ func (P *Parser) parseUnaryExpr() ast.Expr { } switch P.tok { - case token.ADD, token.SUB, token.MUL, token.NOT, token.XOR, token.ARROW, token.AND: - loc, tok := P.loc, 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(); - y := P.parseUnaryExpr(); - return &ast.UnaryExpr{tok, y, loc}; + 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(); + return &ast.StarExpr{pos, x}; } return P.parsePrimaryExpr(); @@ -1100,10 +1078,10 @@ func (P *Parser) parseBinaryExpr(prec1 int) ast.Expr { x := P.parseUnaryExpr(); for prec := token.Precedence(P.tok); prec >= prec1; prec-- { for token.Precedence(P.tok) == prec { - loc, tok := P.loc, P.tok; + pos, tok := P.pos, P.tok; P.next(); y := P.parseBinaryExpr(prec + 1); - x = &ast.BinaryExpr{tok, x, y, loc}; + x = &ast.BinaryExpr{x, pos, tok, y}; } } @@ -1128,13 +1106,7 @@ func (P *Parser) parseExpression(prec int) ast.Expr { // Statements -const /* mode */ ( - label_ok = 1 << iota; - range_ok; -) - - -func (P *Parser) parseSimpleStat(mode int) ast.Stat { +func (P *Parser) parseSimpleStat() ast.Stat { if P.trace { defer un(trace(P, "SimpleStat")); } @@ -1144,15 +1116,13 @@ func (P *Parser) parseSimpleStat(mode int) ast.Stat { switch P.tok { case token.COLON: // labeled statement - loc := P.loc; P.expect(token.COLON); - P.opt_semi = true; - if mode & label_ok != 0 && len(x) == 1 { + if len(x) == 1 { if label, is_ident := x[0].(*ast.Ident); is_ident { - return &ast.LabeledStat{loc, label, P.parseStatement()}; + return &ast.LabeledStat{label, P.parseStatement()}; } } - P.error(loc, "illegal label declaration"); + P.error(x[0].Pos(), "illegal label declaration"); return nil; case @@ -1161,34 +1131,29 @@ func (P *Parser) parseSimpleStat(mode int) ast.Stat { token.REM_ASSIGN, token.AND_ASSIGN, token.OR_ASSIGN, token.XOR_ASSIGN, token.SHL_ASSIGN, token.SHR_ASSIGN: // assignment statement or range clause - loc, tok := P.loc, P.tok; + pos, tok := P.pos, P.tok; P.next(); + /* if mode & range_ok != 0 && P.tok == token.RANGE { // range clause P.next(); if len(x) != 1 && len(x) != 2 { - P.error(loc, "expected 1 or 2 expressions on lhs of range clause"); + P.error(x[0].Pos(), "expected 1 or 2 expressions on lhs of range clause"); } if tok != token.DEFINE && tok != token.ASSIGN { - P.error(loc, "expected '=' or ':=', found '" + token.TokenString(tok) + "'"); + P.error(pos, "expected '=' or ':=', found '" + token.TokenString(tok) + "'"); } y := P.parseExpression(1); - return &ast.RangeClause{loc, tok, x, y}; + return &ast.RangeClause{x, pos, tok, y}; } else { - // assignment statement - y := P.parseExpressionList(); - xl, yl := len(x), len(y); - if xl > 1 && yl > 1 && xl != yl { - P.error(loc, "arity of lhs doesn't match rhs"); // TODO use better loc for error - } - if xl == 1 && yl == 1 { - // common case - use smaller node - return &ast.AssignmentStat{loc, tok, x[0], y[0]}; - } else { - // general case - return &ast.TupleAssignStat{loc, tok, x, y}; - } + */ + // assignment statement + y := P.parseExpressionList(); + xl, yl := len(x), len(y); + if xl > 1 && yl > 1 && xl != yl { + P.error(x[0].Pos(), "arity of lhs doesn't match rhs"); // TODO use better loc for error } + return &ast.AssignmentStat{x, pos, tok, y}; default: if len(x) > 1 { @@ -1196,13 +1161,12 @@ func (P *Parser) parseSimpleStat(mode int) ast.Stat { } if P.tok == token.INC || P.tok == token.DEC { - s := &ast.IncDecStat{P.loc, P.tok, x[0]}; + s := &ast.IncDecStat{x[0], P.tok}; P.next(); // consume "++" or "--" return s; } - // TODO change ILLEGAL -> NONE - return &ast.ExpressionStat{x[0].Pos(), token.ILLEGAL, x[0]}; + return &ast.ExprStat{x[0]}; } unreachable(); @@ -1210,14 +1174,25 @@ func (P *Parser) parseSimpleStat(mode int) ast.Stat { } -func (P *Parser) parseInvocationStat(keyword int) *ast.ExpressionStat { +func (P *Parser) parseGoStat() *ast.GoStat { if P.trace { - defer un(trace(P, "InvocationStat")); + defer un(trace(P, "GoStat")); } - loc := P.loc; - P.expect(keyword); - return &ast.ExpressionStat{loc, keyword, P.parseExpression(1)}; + pos := P.expect(token.GO); + call := P.parseExpression(1); + return &ast.GoStat{pos, call}; +} + + +func (P *Parser) parseDeferStat() *ast.DeferStat { + if P.trace { + defer un(trace(P, "DeferStat")); + } + + pos := P.expect(token.DEFER); + call := P.parseExpression(1); + return &ast.DeferStat{pos, call}; } @@ -1226,7 +1201,7 @@ func (P *Parser) parseReturnStat() *ast.ReturnStat { defer un(trace(P, "ReturnStat")); } - loc := P.loc; + loc := P.pos; P.expect(token.RETURN); var x []ast.Expr; if P.tok != token.SEMICOLON && P.tok != token.RBRACE { @@ -1242,7 +1217,7 @@ func (P *Parser) parseControlFlowStat(tok int) *ast.ControlFlowStat { defer un(trace(P, "ControlFlowStat")); } - s := &ast.ControlFlowStat{P.loc, tok, nil}; + s := &ast.ControlFlowStat{P.pos, tok, nil}; P.expect(tok); if tok != token.FALLTHROUGH && P.tok == token.IDENT { s.Label = P.parseIdent(); @@ -1252,7 +1227,33 @@ func (P *Parser) parseControlFlowStat(tok int) *ast.ControlFlowStat { } -func (P *Parser) parseControlClause(isForStat bool) (init ast.Stat, expr ast.Expr, post ast.Stat) { +/* +func (P *Parser) asIdent(x ast.Expr) *ast.Ident { + if name, ok := x.(*ast.Ident); ok { + return name; + } + P.error(x.Pos(), "identifier expected"); + return &ast.Ident{x.Pos(), [...]byte{'B', 'A', 'D'}}; +} + + +func (P *Parser) isTypeSwitch(init ast.Stat) (lhs *ast.Ident, rhs ast.Expr) { + if assign, ok := init.(*ast.AssignmentStat); ok { + if guard, ok := assign.Rhs.(*ast.TypeAssertion); ok { + if tmp, ok := guard.Typ.(*ast.TypeType); ok { + // we appear to have a type switch + // TODO various error checks + return P.asIdent(assign.Lhs), guard.X; + } + } + } + return nil, nil; +} +*/ + + + +func (P *Parser) parseControlClause(isForStat bool) (s1, s2, s3 ast.Stat) { if P.trace { defer un(trace(P, "ControlClause")); } @@ -1262,39 +1263,49 @@ func (P *Parser) parseControlClause(isForStat bool) (init ast.Stat, expr ast.Exp P.expr_lev = -1; if P.tok != token.SEMICOLON { - mode := 0; - if isForStat { - mode = range_ok; - } - init = P.parseSimpleStat(mode); + s1 = P.parseSimpleStat(); } - if dummy, is_range := init.(*ast.RangeClause); !is_range { - if P.tok == token.SEMICOLON { - P.next(); - if P.tok != token.SEMICOLON && P.tok != token.LBRACE { - expr = P.parseExpression(1); - } - if isForStat { - P.expect(token.SEMICOLON); - if P.tok != token.LBRACE { - post = P.parseSimpleStat(0); - } - } - } else { - if init != nil { // guard in case of errors - if s, is_expr_stat := init.(*ast.ExpressionStat); is_expr_stat { - expr, init = s.Expr, nil; - } else { - P.error(noloc, "illegal control clause"); - } + if P.tok == token.SEMICOLON { + P.next(); + if P.tok != token.LBRACE && P.tok != token.SEMICOLON { + s2 = P.parseSimpleStat(); + } + if isForStat { + // for statements have a 3rd section + P.expect(token.SEMICOLON); + if P.tok != token.LBRACE { + s3 = P.parseSimpleStat(); } } + } else { + s1, s2 = nil, s1; } - + P.expr_lev = prev_lev; } - return init, expr, post; + return s1, s2, s3; +} + + +func (P *Parser) isExpr(s ast.Stat) bool { + if s == nil { + return true; + } + dummy, is_expr := s.(*ast.ExprStat); + return is_expr; +} + + +func (P *Parser) asExpr(s ast.Stat) ast.Expr { + if s == nil { + return nil; + } + if es, is_expr := s.(*ast.ExprStat); is_expr { + return es.X; + } + P.error(s.Pos(), "condition expected; found simple statement"); + return &ast.BadExpr{s.Pos()}; } @@ -1303,9 +1314,8 @@ func (P *Parser) parseIfStat() *ast.IfStat { defer un(trace(P, "IfStat")); } - loc := P.loc; - P.expect(token.IF); - init, cond, dummy := P.parseControlClause(false); + pos := P.expect(token.IF); + s1, s2, dummy := P.parseControlClause(false); body := P.parseBlock(token.LBRACE); var else_ ast.Stat; if P.tok == token.ELSE { @@ -1313,92 +1323,84 @@ func (P *Parser) parseIfStat() *ast.IfStat { else_ = P.parseStatement(); } - return &ast.IfStat{loc, init, cond, body, else_}; + return &ast.IfStat{pos, s1, P.asExpr(s2), body, else_}; } -func (P *Parser) parseForStat() *ast.ForStat { +func (P *Parser) parseCaseClause() *ast.CaseClause { if P.trace { - defer un(trace(P, "ForStat")); + defer un(trace(P, "CaseClause")); } - loc := P.loc; - P.expect(token.FOR); - init, cond, post := P.parseControlClause(true); - body := P.parseBlock(token.LBRACE); - - return &ast.ForStat{loc, init, cond, post, body}; -} - - -func (P *Parser) asIdent(x ast.Expr) *ast.Ident { - if name, ok := x.(*ast.Ident); ok { - return name; + // SwitchCase + loc := P.pos; + var x []ast.Expr; + if P.tok == token.CASE { + P.next(); + x = P.parseExpressionList(); + } else { + P.expect(token.DEFAULT); } - P.error(x.Pos(), "identifier expected"); - return &ast.Ident{"BAD", noloc}; -} - -func (P *Parser) isTypeSwitch(init ast.Stat) (lhs *ast.Ident, rhs ast.Expr) { - if assign, ok := init.(*ast.AssignmentStat); ok { - if guard, ok := assign.Rhs.(*ast.TypeAssertion); ok { - if tmp, ok := guard.Typ.(*ast.TypeType); ok { - // we appear to have a type switch - // TODO various error checks - return P.asIdent(assign.Lhs), guard.X; - } - } - } - return nil, nil; + return &ast.CaseClause{loc, x, P.parseBlock(token.COLON)}; } -func (P *Parser) parseCaseClause() *ast.CaseClause { +func (P *Parser) parseTypeCaseClause() *ast.TypeCaseClause { if P.trace { defer un(trace(P, "CaseClause")); } - // SwitchCase - loc := P.loc; - var x []ast.Expr; + // TypeSwitchCase + pos := P.pos; + var typ ast.Expr; if P.tok == token.CASE { P.next(); - x = P.parseExpressionList(); + typ = P.parseType(); } else { P.expect(token.DEFAULT); } - return &ast.CaseClause{loc, x, P.parseBlock(token.COLON)}; + return &ast.TypeCaseClause{pos, typ, P.parseBlock(token.COLON)}; } -func (P *Parser) parseSwitchStat() *ast.SwitchStat { +func (P *Parser) parseSwitchStat() ast.Stat { if P.trace { defer un(trace(P, "SwitchStat")); } - loc := P.loc; - P.expect(token.SWITCH); - init, tag, post := P.parseControlClause(false); - body := ast.NewBlock(P.loc, token.LBRACE); - P.expect(token.LBRACE); - for P.tok != token.RBRACE && P.tok != token.EOF { - body.List.Push(P.parseCaseClause()); - } - body.End = P.loc; - P.expect(token.RBRACE); - P.opt_semi = true; + pos := P.expect(token.SWITCH); + s1, s2, dummy := P.parseControlClause(false); - if lhs, rhs := P.isTypeSwitch(init); lhs != nil { - if tag != nil { - P.error(loc, "illegal type switch clause"); + if P.isExpr(s2) { + // expression switch + lbrace := P.expect(token.LBRACE); + cases := vector.New(0); + for P.tok == token.CASE || P.tok == token.DEFAULT { + cases.Push(P.parseCaseClause()); } - // TODO fix location - init = &ast.TypeSwitchClause{loc, lhs, rhs}; + rbrace := P.expect(token.RBRACE); + P.opt_semi = true; + body := &ast.Block{lbrace, token.LBRACE, asStatList(cases), rbrace}; + return &ast.SwitchStat{pos, s1, P.asExpr(s2), body}; + + } else { + // type switch + // TODO do all the checks! + lbrace := P.expect(token.LBRACE); + cases := vector.New(0); + for P.tok == token.CASE || P.tok == token.DEFAULT { + cases.Push(P.parseTypeCaseClause()); + } + rbrace := P.expect(token.RBRACE); + P.opt_semi = true; + body := &ast.Block{lbrace, token.LBRACE, asStatList(cases), rbrace}; + return &ast.TypeSwitchStat{pos, s1, s2, body}; } - return &ast.SwitchStat{loc, init, tag, body}; + unreachable(); + return nil; } @@ -1408,7 +1410,7 @@ func (P *Parser) parseCommClause() *ast.CommClause { } // CommCase - loc := P.loc; + loc := P.pos; var tok int; var lhs, rhs ast.Expr; if P.tok == token.CASE { @@ -1445,18 +1447,40 @@ func (P *Parser) parseSelectStat() *ast.SelectStat { defer un(trace(P, "SelectStat")); } - loc := P.loc; - P.expect(token.SELECT); - body := ast.NewBlock(P.loc, token.LBRACE); - P.expect(token.LBRACE); - for P.tok != token.RBRACE && P.tok != token.EOF { - body.List.Push(P.parseCommClause()); + 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()); } - body.End = P.loc; - P.expect(token.RBRACE); + rbrace := P.expect(token.RBRACE); P.opt_semi = true; + body := &ast.Block{lbrace, token.LBRACE, asStatList(cases), rbrace}; - return &ast.SelectStat{loc, body}; + return &ast.SelectStat{pos, body}; +} + + +func (P *Parser) parseForStat() ast.Stat { + if P.trace { + defer un(trace(P, "ForStat")); + } + + pos := P.expect(token.FOR); + s1, s2, s3 := P.parseControlClause(true); + body := P.parseBlock(token.LBRACE); + + if as, is_as := s2.(*ast.AssignmentStat); is_as { + // probably a for statement with a range clause + // TODO do all the checks! + return &ast.RangeStat{pos, s2, body}; + } else { + // regular for statement + return &ast.ForStat{pos, s1, P.asExpr(s2), s3, body}; + } + + unreachable(); + return nil; } @@ -1467,15 +1491,17 @@ func (P *Parser) parseStatement() ast.Stat { switch P.tok { case token.CONST, token.TYPE, token.VAR: - return &ast.DeclarationStat{P.parseDeclaration()}; + return &ast.DeclStat{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.parseSimpleStat(label_ok); - case token.GO, token.DEFER: - return P.parseInvocationStat(P.tok); + return P.parseSimpleStat(); + case token.GO: + return P.parseGoStat(); + case token.DEFER: + return P.parseDeferStat(); case token.RETURN: return P.parseReturnStat(); case token.BREAK, token.CONTINUE, token.GOTO, token.FALLTHROUGH: @@ -1492,43 +1518,43 @@ func (P *Parser) parseStatement() ast.Stat { return P.parseSelectStat(); case token.SEMICOLON, token.RBRACE: // don't consume the ";", it is the separator following the empty statement - return &ast.EmptyStat{P.loc}; + return &ast.EmptyStat{P.pos}; } // no statement found - P.error(P.loc, "statement expected"); - return &ast.BadStat{P.loc}; + P.error(P.pos, "statement expected"); + return &ast.BadStat{P.pos}; } // ---------------------------------------------------------------------------- // Declarations -func (P *Parser) parseImportSpec(loc Position) *ast.ImportDecl { +func (P *Parser) parseImportSpec(pos 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.loc, `"import ." not yet handled properly`); + P.error(P.pos, `"import ." not yet handled properly`); P.next(); } else if P.tok == token.IDENT { ident = P.parseIdent(); } - var path ast.Expr; + var path *ast.StringLit; if P.tok == token.STRING { - path = P.parseStringLit(); + path = P.parseStringLit(nil); } else { P.expect(token.STRING); // use expect() error handling } - return &ast.ImportDecl{loc, ident, path}; + return &ast.ImportDecl{doc, pos, ident, path}; } -func (P *Parser) parseConstSpec(loc Position, comment ast.CommentGroup) *ast.ConstDecl { +func (P *Parser) parseConstSpec(pos Position, doc ast.Comments) *ast.ConstDecl { if P.trace { defer un(trace(P, "ConstSpec")); } @@ -1541,11 +1567,11 @@ func (P *Parser) parseConstSpec(loc Position, comment ast.CommentGroup) *ast.Con values = P.parseExpressionList(); } - return &ast.ConstDecl{loc, names, typ, values, comment}; + return &ast.ConstDecl{doc, pos, names, typ, values}; } -func (P *Parser) parseTypeSpec(loc Position, comment ast.CommentGroup) *ast.TypeDecl { +func (P *Parser) parseTypeSpec(pos Position, doc ast.Comments) *ast.TypeDecl { if P.trace { defer un(trace(P, "TypeSpec")); } @@ -1553,11 +1579,11 @@ func (P *Parser) parseTypeSpec(loc Position, comment ast.CommentGroup) *ast.Type ident := P.parseIdent(); typ := P.parseType(); - return &ast.TypeDecl{loc, ident, typ, comment}; + return &ast.TypeDecl{doc, pos, ident, typ}; } -func (P *Parser) parseVarSpec(loc Position, comment ast.CommentGroup) *ast.VarDecl { +func (P *Parser) parseVarSpec(pos Position, doc ast.Comments) *ast.VarDecl { if P.trace { defer un(trace(P, "VarSpec")); } @@ -1570,16 +1596,16 @@ func (P *Parser) parseVarSpec(loc Position, comment ast.CommentGroup) *ast.VarDe values = P.parseExpressionList(); } - return &ast.VarDecl{loc, names, typ, values, comment}; + return &ast.VarDecl{doc, pos, names, typ, values}; } -func (P *Parser) parseSpec(loc Position, comment ast.CommentGroup, keyword int) ast.Decl { +func (P *Parser) parseSpec(pos Position, doc ast.Comments, keyword int) ast.Decl { switch keyword { - case token.IMPORT: return P.parseImportSpec(loc); - case token.CONST: return P.parseConstSpec(loc, comment); - case token.TYPE: return P.parseTypeSpec(loc, comment); - case token.VAR: return P.parseVarSpec(loc, comment); + 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(); @@ -1592,22 +1618,21 @@ func (P *Parser) parseDecl(keyword int) ast.Decl { defer un(trace(P, "Decl")); } - comment := P.getLastComment(); - loc := P.loc; - P.expect(keyword); + 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(noloc, nil, keyword)); + list.Push(P.parseSpec(nopos, nil, keyword)); if P.tok == token.SEMICOLON { P.next(); } else { break; } } - end := P.loc; - P.expect(token.RPAREN); + rparen := P.expect(token.RPAREN); P.opt_semi = true; // convert vector @@ -1616,10 +1641,10 @@ func (P *Parser) parseDecl(keyword int) ast.Decl { decls[i] = list.At(i).(ast.Decl); } - return &ast.DeclList{loc, keyword, decls, end}; + return &ast.DeclList{doc, pos, keyword, lparen, decls, rparen}; } - return P.parseSpec(loc, comment, keyword); + return P.parseSpec(pos, doc, keyword); } @@ -1637,13 +1662,12 @@ func (P *Parser) parseFunctionDecl() *ast.FuncDecl { defer un(trace(P, "FunctionDecl")); } - comment := P.getLastComment(); - loc := P.loc; - P.expect(token.FUNC); + doc := P.getDoc(); + pos := P.expect(token.FUNC); var recv *ast.Field; if P.tok == token.LPAREN { - loc := P.loc; + loc := P.pos; tmp := P.parseParameters(true); if len(tmp) == 1 { recv = tmp[0]; @@ -1660,7 +1684,7 @@ func (P *Parser) parseFunctionDecl() *ast.FuncDecl { body = P.parseBlock(token.LBRACE); } - return &ast.FuncDecl{loc, recv, ident, sig, body, comment}; + return &ast.FuncDecl{doc, pos, recv, ident, sig, body}; } @@ -1676,7 +1700,7 @@ func (P *Parser) parseDeclaration() ast.Decl { return P.parseFunctionDecl(); } - loc := P.loc; + loc := P.pos; P.error(loc, "declaration expected"); P.next(); // make progress return &ast.BadDecl{loc}; @@ -1686,16 +1710,6 @@ func (P *Parser) parseDeclaration() ast.Decl { // ---------------------------------------------------------------------------- // Program -func (P *Parser) getComments() []ast.CommentGroup { - // convert comments vector - list := make([]ast.CommentGroup, P.comments.Len()); - for i := 0; i < P.comments.Len(); i++ { - list[i] = P.comments.At(i).(ast.CommentGroup); - } - return list; -} - - // The Parse function is parametrized with one of the following // constants. They control how much of the source text is parsed. // @@ -1710,19 +1724,18 @@ const ( // // foo bar // -func (P *Parser) Parse(mode int) *ast.Program { +func (P *Parser) Parse(mode int) *ast.Package { if P.trace { defer un(trace(P, "Program")); } // package clause - comment := P.getLastComment(); - loc := P.loc; - P.expect(token.PACKAGE); + comment := P.getDoc(); + pos := P.expect(token.PACKAGE); name := P.parseIdent(); if P.tok == token.SEMICOLON { // common error - P.error(P.loc, "extra semicolon"); + P.error(P.pos, "extra semicolon"); P.next(); } @@ -1748,12 +1761,21 @@ func (P *Parser) Parse(mode int) *ast.Program { } } - // convert list + // convert declaration list decls = make([]ast.Decl, list.Len()); for i := 0; i < list.Len(); i++ { decls[i] = list.At(i).(ast.Decl); } } - return &ast.Program{loc, name, decls, comment, P.getComments()}; + // 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); + } + } + + return &ast.Package{comment, pos, name, decls, comments}; } |