summaryrefslogtreecommitdiff
path: root/usr/gri/pretty/parser.go
diff options
context:
space:
mode:
Diffstat (limited to 'usr/gri/pretty/parser.go')
-rw-r--r--usr/gri/pretty/parser.go239
1 files changed, 131 insertions, 108 deletions
diff --git a/usr/gri/pretty/parser.go b/usr/gri/pretty/parser.go
index 21075beae..2e9b34e57 100644
--- a/usr/gri/pretty/parser.go
+++ b/usr/gri/pretty/parser.go
@@ -33,7 +33,8 @@ type Parser struct {
trace bool;
indent uint;
- comments *vector.Vector;
+ comments vector.Vector;
+ last_comment ast.CommentGroup;
// The next token
loc scanner.Location; // token location
@@ -42,8 +43,6 @@ type Parser struct {
// Non-syntactic parser control
opt_semi bool; // true if semicolon separator is optional in statement list
-
- // Nesting levels
expr_lev int; // < 0: in control clause, >= 0: in expression
};
@@ -113,9 +112,63 @@ func (P *Parser) next0() {
}
+func (P *Parser) getComment() *ast.Comment {
+ defer P.next0();
+
+ // for /*-style comments, the comment may end on a different line
+ endline := P.loc.Line;
+ if P.val[1] == '*' {
+ for i, b := range P.val {
+ if b == '\n' {
+ endline++;
+ }
+ }
+ }
+
+ 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;
+}
+
+
+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;
+ }
+ return c;
+}
+
+
func (P *Parser) next() {
- for P.next0(); P.tok == token.COMMENT; P.next0() {
- P.comments.Push(&ast.Comment{P.loc, P.val});
+ P.next0();
+ P.last_comment = nil;
+ for P.tok == token.COMMENT {
+ P.last_comment = P.getCommentGroup();
+ P.comments.Push(P.last_comment);
}
}
@@ -123,14 +176,9 @@ func (P *Parser) next() {
func (P *Parser) Init(scanner *scanner.Scanner, err scanner.ErrorHandler, trace bool) {
P.scanner = scanner;
P.err = err;
-
P.trace = trace;
- P.indent = 0;
-
- P.comments = vector.New(0);
-
+ P.comments.Init(0);
P.next();
- P.expr_lev = 0;
}
@@ -382,20 +430,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});
+ list.Push(&ast.Field{idents, typ, nil, nil});
for P.tok == token.COMMA {
P.next();
idents := P.parseIdentList2(nil);
typ := P.parseParameterType();
- list.Push(&ast.Field{idents, typ, nil});
+ list.Push(&ast.Field{idents, typ, nil, 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});
+ list.Set(i, &ast.Field{nil, list.At(i).(ast.Expr), nil, nil});
}
}
@@ -438,7 +486,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};
+ result[0] = &ast.Field{nil, typ, nil, nil};
}
}
@@ -495,7 +543,7 @@ func (P *Parser) parseMethodSpec() *ast.Field {
typ = x;
}
- return &ast.Field{idents, typ, nil};
+ return &ast.Field{idents, typ, nil, nil};
}
@@ -558,6 +606,8 @@ func (P *Parser) parseFieldDecl() *ast.Field {
defer un(trace(P, "FieldDecl"));
}
+ comment := P.getLastComment();
+
// a list of identifiers looks like a list of type names
list := vector.New(0);
for {
@@ -601,7 +651,7 @@ func (P *Parser) parseFieldDecl() *ast.Field {
}
}
- return &ast.Field{idents, typ, tag};
+ return &ast.Field{idents, typ, tag, comment};
}
@@ -1377,24 +1427,25 @@ func (P *Parser) parseImportSpec(loc scanner.Location) *ast.ImportDecl {
}
-func (P *Parser) parseConstSpec(loc scanner.Location) *ast.ConstDecl {
+func (P *Parser) parseConstSpec(loc scanner.Location, comment ast.CommentGroup) *ast.ConstDecl {
if P.trace {
defer un(trace(P, "ConstSpec"));
}
idents := P.parseIdentList2(nil);
typ := P.tryType();
+
var vals ast.Expr;
if P.tok == token.ASSIGN {
P.next();
vals = P.parseExpressionList();
}
- return &ast.ConstDecl{loc, idents, typ, vals};
+ return &ast.ConstDecl{loc, idents, typ, vals, comment};
}
-func (P *Parser) parseTypeSpec(loc scanner.Location) *ast.TypeDecl {
+func (P *Parser) parseTypeSpec(loc scanner.Location, comment ast.CommentGroup) *ast.TypeDecl {
if P.trace {
defer un(trace(P, "TypeSpec"));
}
@@ -1402,11 +1453,11 @@ func (P *Parser) parseTypeSpec(loc scanner.Location) *ast.TypeDecl {
ident := P.parseIdent();
typ := P.parseType();
- return &ast.TypeDecl{loc, ident, typ};
+ return &ast.TypeDecl{loc, ident, typ, comment};
}
-func (P *Parser) parseVarSpec(loc scanner.Location) *ast.VarDecl {
+func (P *Parser) parseVarSpec(loc scanner.Location, comment ast.CommentGroup) *ast.VarDecl {
if P.trace {
defer un(trace(P, "VarSpec"));
}
@@ -1425,16 +1476,16 @@ func (P *Parser) parseVarSpec(loc scanner.Location) *ast.VarDecl {
}
}
- return &ast.VarDecl{loc, idents, typ, vals};
+ return &ast.VarDecl{loc, idents, typ, vals, comment};
}
-func (P *Parser) parseSpec(loc scanner.Location, keyword int) ast.Decl {
+func (P *Parser) parseSpec(loc scanner.Location, comment ast.CommentGroup, keyword int) ast.Decl {
switch keyword {
case token.IMPORT: return P.parseImportSpec(loc);
- case token.CONST: return P.parseConstSpec(loc);
- case token.TYPE: return P.parseTypeSpec(loc);
- case token.VAR: return P.parseVarSpec(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);
}
unreachable();
@@ -1447,13 +1498,14 @@ func (P *Parser) parseDecl(keyword int) ast.Decl {
defer un(trace(P, "Decl"));
}
+ comment := P.getLastComment();
loc := P.loc;
P.expect(keyword);
if P.tok == token.LPAREN {
P.next();
list := vector.New(0);
for P.tok != token.RPAREN && P.tok != token.EOF {
- list.Push(P.parseSpec(noloc, keyword));
+ list.Push(P.parseSpec(noloc, nil, keyword));
if P.tok == token.SEMICOLON {
P.next();
} else {
@@ -1473,7 +1525,7 @@ func (P *Parser) parseDecl(keyword int) ast.Decl {
return &ast.DeclList{loc, keyword, decls, end};
}
- return P.parseSpec(loc, keyword);
+ return P.parseSpec(loc, comment, keyword);
}
@@ -1491,6 +1543,7 @@ func (P *Parser) parseFunctionDecl() *ast.FuncDecl {
defer un(trace(P, "FunctionDecl"));
}
+ comment := P.getLastComment();
loc := P.loc;
P.expect(token.FUNC);
@@ -1513,7 +1566,7 @@ func (P *Parser) parseFunctionDecl() *ast.FuncDecl {
body = P.parseBlock(token.LBRACE);
}
- return &ast.FuncDecl{loc, recv, ident, sig, body};
+ return &ast.FuncDecl{loc, recv, ident, sig, body, comment};
}
@@ -1539,98 +1592,68 @@ func (P *Parser) parseDeclaration() ast.Decl {
// ----------------------------------------------------------------------------
// Program
-// The top level parsing routines:
-//
-// ParsePackageClause
-// - parses the package clause only and returns the package name
-//
-// ParseImportDecls
-// - parses all import declarations and returns a list of them
-// - the package clause must have been parsed before
-// - useful to determine package dependencies
-//
-// ParseProgram
-// - parses the entire program and returns the complete AST
-
-
-func (P *Parser) ParsePackageClause() *ast.Ident {
- if P.trace {
- defer un(trace(P, "PackageClause"));
- }
-
- P.expect(token.PACKAGE);
- return P.parseIdent();
-}
-
-
-func (P *Parser) parseImportDecls() *vector.Vector {
- if P.trace {
- defer un(trace(P, "ImportDecls"));
- }
-
- list := vector.New(0);
- for P.tok == token.IMPORT {
- list.Push(P.parseDecl(token.IMPORT));
- if P.tok == token.SEMICOLON {
- P.next();
- }
- }
-
- return list;
-}
-
-
-func (P *Parser) ParseImportDecls() []ast.Decl {
- list := P.parseImportDecls();
-
- // convert list
- imports := make([]ast.Decl, list.Len());
- for i := 0; i < list.Len(); i++ {
- imports[i] = list.At(i).(ast.Decl);
- }
-
- return imports;
-}
-
-
-// Returns the list of comments accumulated during parsing, if any.
-// (The scanner must return token.COMMENT tokens for comments to be
-// collected in the first place.)
-
-func (P *Parser) Comments() []*ast.Comment {
+func (P *Parser) getComments() []ast.CommentGroup {
// convert comments vector
- list := make([]*ast.Comment, P.comments.Len());
+ list := make([]ast.CommentGroup, P.comments.Len());
for i := 0; i < P.comments.Len(); i++ {
- list[i] = P.comments.At(i).(*ast.Comment);
+ list[i] = P.comments.At(i).(ast.CommentGroup);
}
return list;
}
-func (P *Parser) ParseProgram() *ast.Program {
+// The Parse function is parametrized with one of the following
+// constants. They control how much of the source text is parsed.
+//
+const (
+ ParseEntirePackage = iota;
+ ParseImportDeclsOnly;
+ ParsePackageClauseOnly;
+)
+
+
+// Parse parses the source...
+//
+// foo bar
+//
+func (P *Parser) Parse(mode int) *ast.Program {
if P.trace {
defer un(trace(P, "Program"));
}
- p := ast.NewProgram(P.loc);
- p.Ident = P.ParsePackageClause();
+ // package clause
+ comment := P.getLastComment();
+ loc := P.loc;
+ P.expect(token.PACKAGE);
+ name := P.parseIdent();
+ var decls []ast.Decl;
- // package body
- list := P.parseImportDecls();
- for P.tok != token.EOF {
- list.Push(P.parseDeclaration());
- if P.tok == token.SEMICOLON {
- P.next();
+ if mode <= ParseImportDeclsOnly {
+ // import decls
+ list := vector.New(0);
+ for P.tok == token.IMPORT {
+ list.Push(P.parseDecl(token.IMPORT));
+ if P.tok == token.SEMICOLON {
+ P.next();
+ }
}
- }
- // convert list
- p.Decls = make([]ast.Decl, list.Len());
- for i := 0; i < list.Len(); i++ {
- p.Decls[i] = list.At(i).(ast.Decl);
- }
+ if mode <= ParseEntirePackage {
+ // rest of package body
+ for P.tok != token.EOF {
+ list.Push(P.parseDeclaration());
+ if P.tok == token.SEMICOLON {
+ P.next();
+ }
+ }
+ }
- p.Comments = P.Comments();
+ // convert list
+ decls = make([]ast.Decl, list.Len());
+ for i := 0; i < list.Len(); i++ {
+ decls[i] = list.At(i).(ast.Decl);
+ }
+ }
- return p;
+ return &ast.Program{loc, name, decls, comment, P.getComments()};
}