Commit e06a654c authored by Robert Griesemer's avatar Robert Griesemer

daily snapshot:

- correctly associate comments with declarations
  (available through AST)
- very raw printing of interface
- much more functionality, now needs some formatting, sorting, etc.

R=r
OCL=26213
CL=26213
parent ce9417ee
...@@ -28,6 +28,21 @@ func assert(pred bool) { ...@@ -28,6 +28,21 @@ func assert(pred bool) {
} }
// ----------------------------------------------------------------------------
// Comments
type Comment struct {
Loc scanner.Location;
EndLine int; // the line where the comment ends
Text []byte;
}
// A CommentGroup is a sequence of consequtive comments
// with no other tokens and no empty lines inbetween.
type CommentGroup []*Comment
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Expressions // Expressions
...@@ -132,6 +147,7 @@ type ( ...@@ -132,6 +147,7 @@ type (
Idents []*Ident; Idents []*Ident;
Typ Expr; Typ Expr;
Tag Expr; // nil = no tag Tag Expr; // nil = no tag
Comment CommentGroup;
}; };
StructType struct { StructType struct {
...@@ -445,12 +461,14 @@ type ( ...@@ -445,12 +461,14 @@ type (
Idents []*Ident; Idents []*Ident;
Typ Expr; Typ Expr;
Vals Expr; Vals Expr;
Comment CommentGroup;
}; };
TypeDecl struct { TypeDecl struct {
Loc scanner.Location; // if > 0: position of "type" Loc scanner.Location; // if > 0: position of "type"
Ident *Ident; Ident *Ident;
Typ Expr; Typ Expr;
Comment CommentGroup;
}; };
VarDecl struct { VarDecl struct {
...@@ -458,6 +476,7 @@ type ( ...@@ -458,6 +476,7 @@ type (
Idents []*Ident; Idents []*Ident;
Typ Expr; Typ Expr;
Vals Expr; Vals Expr;
Comment CommentGroup;
}; };
FuncDecl struct { FuncDecl struct {
...@@ -466,6 +485,7 @@ type ( ...@@ -466,6 +485,7 @@ type (
Ident *Ident; Ident *Ident;
Sig *Signature; Sig *Signature;
Body *Block; Body *Block;
Comment CommentGroup;
}; };
DeclList struct { DeclList struct {
...@@ -500,17 +520,13 @@ func (d *DeclList) Visit(v DeclVisitor) { v.DoDeclList(d); } ...@@ -500,17 +520,13 @@ func (d *DeclList) Visit(v DeclVisitor) { v.DoDeclList(d); }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Program // Program
type Comment struct { // TODO rename to Package
Loc scanner.Location;
Text []byte;
}
type Program struct { type Program struct {
Loc scanner.Location; // tok is token.PACKAGE Loc scanner.Location; // tok is token.PACKAGE
Ident *Ident; Ident *Ident;
Decls []Decl; Decls []Decl;
Comments []*Comment; Comment CommentGroup;
Comments []CommentGroup;
} }
......
...@@ -112,7 +112,7 @@ func Compile(src_file string, flags *Flags) (*AST.Program, int) { ...@@ -112,7 +112,7 @@ func Compile(src_file string, flags *Flags) (*AST.Program, int) {
var parser Parser.Parser; var parser Parser.Parser;
parser.Init(&scanner, &err, flags.Verbose); parser.Init(&scanner, &err, flags.Verbose);
prog := parser.ParseProgram(); prog := parser.Parse(Parser.ParseEntirePackage);
if err.nerrors == 0 { if err.nerrors == 0 {
TypeChecker.CheckProgram(&err, prog); TypeChecker.CheckProgram(&err, prog);
......
...@@ -108,7 +108,7 @@ func serveFile(c *http.Conn, filename string) { ...@@ -108,7 +108,7 @@ func serveFile(c *http.Conn, filename string) {
} }
c.SetHeader("content-type", "text/html; charset=utf-8"); c.SetHeader("content-type", "text/html; charset=utf-8");
Printer.Print(c, true, prog); Printer.Print(c, prog, true);
} }
......
...@@ -33,7 +33,8 @@ type Parser struct { ...@@ -33,7 +33,8 @@ type Parser struct {
trace bool; trace bool;
indent uint; indent uint;
comments *vector.Vector; comments vector.Vector;
last_comment ast.CommentGroup;
// The next token // The next token
loc scanner.Location; // token location loc scanner.Location; // token location
...@@ -42,8 +43,6 @@ type Parser struct { ...@@ -42,8 +43,6 @@ type Parser struct {
// Non-syntactic parser control // Non-syntactic parser control
opt_semi bool; // true if semicolon separator is optional in statement list opt_semi bool; // true if semicolon separator is optional in statement list
// Nesting levels
expr_lev int; // < 0: in control clause, >= 0: in expression expr_lev int; // < 0: in control clause, >= 0: in expression
}; };
...@@ -113,9 +112,63 @@ func (P *Parser) next0() { ...@@ -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() { func (P *Parser) next() {
for P.next0(); P.tok == token.COMMENT; P.next0() { P.next0();
P.comments.Push(&ast.Comment{P.loc, P.val}); 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() { ...@@ -123,14 +176,9 @@ func (P *Parser) next() {
func (P *Parser) Init(scanner *scanner.Scanner, err scanner.ErrorHandler, trace bool) { func (P *Parser) Init(scanner *scanner.Scanner, err scanner.ErrorHandler, trace bool) {
P.scanner = scanner; P.scanner = scanner;
P.err = err; P.err = err;
P.trace = trace; P.trace = trace;
P.indent = 0; P.comments.Init(0);
P.comments = vector.New(0);
P.next(); P.next();
P.expr_lev = 0;
} }
...@@ -382,20 +430,20 @@ func (P *Parser) parseParameterList(ellipsis_ok bool) []*ast.Field { ...@@ -382,20 +430,20 @@ func (P *Parser) parseParameterList(ellipsis_ok bool) []*ast.Field {
idents[i] = list.At(i).(*ast.Ident); idents[i] = list.At(i).(*ast.Ident);
} }
list.Init(0); list.Init(0);
list.Push(&ast.Field{idents, typ, nil}); list.Push(&ast.Field{idents, typ, nil, nil});
for P.tok == token.COMMA { for P.tok == token.COMMA {
P.next(); P.next();
idents := P.parseIdentList2(nil); idents := P.parseIdentList2(nil);
typ := P.parseParameterType(); typ := P.parseParameterType();
list.Push(&ast.Field{idents, typ, nil}); list.Push(&ast.Field{idents, typ, nil, nil});
} }
} else { } else {
// Type { "," Type } // Type { "," Type }
// convert list of types into list of *Param // convert list of types into list of *Param
for i := 0; i < list.Len(); i++ { 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 { ...@@ -438,7 +486,7 @@ func (P *Parser) parseResult() []*ast.Field {
typ := P.tryType(); typ := P.tryType();
if typ != nil { if typ != nil {
result = make([]*ast.Field, 1); 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 { ...@@ -495,7 +543,7 @@ func (P *Parser) parseMethodSpec() *ast.Field {
typ = x; 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 { ...@@ -558,6 +606,8 @@ func (P *Parser) parseFieldDecl() *ast.Field {
defer un(trace(P, "FieldDecl")); defer un(trace(P, "FieldDecl"));
} }
comment := P.getLastComment();
// a list of identifiers looks like a list of type names // a list of identifiers looks like a list of type names
list := vector.New(0); list := vector.New(0);
for { for {
...@@ -601,7 +651,7 @@ func (P *Parser) parseFieldDecl() *ast.Field { ...@@ -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 { ...@@ -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 { if P.trace {
defer un(trace(P, "ConstSpec")); defer un(trace(P, "ConstSpec"));
} }
idents := P.parseIdentList2(nil); idents := P.parseIdentList2(nil);
typ := P.tryType(); typ := P.tryType();
var vals ast.Expr; var vals ast.Expr;
if P.tok == token.ASSIGN { if P.tok == token.ASSIGN {
P.next(); P.next();
vals = P.parseExpressionList(); 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 { if P.trace {
defer un(trace(P, "TypeSpec")); defer un(trace(P, "TypeSpec"));
} }
...@@ -1402,11 +1453,11 @@ func (P *Parser) parseTypeSpec(loc scanner.Location) *ast.TypeDecl { ...@@ -1402,11 +1453,11 @@ func (P *Parser) parseTypeSpec(loc scanner.Location) *ast.TypeDecl {
ident := P.parseIdent(); ident := P.parseIdent();
typ := P.parseType(); 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 { if P.trace {
defer un(trace(P, "VarSpec")); defer un(trace(P, "VarSpec"));
} }
...@@ -1425,16 +1476,16 @@ func (P *Parser) parseVarSpec(loc scanner.Location) *ast.VarDecl { ...@@ -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 { switch keyword {
case token.IMPORT: return P.parseImportSpec(loc); case token.IMPORT: return P.parseImportSpec(loc);
case token.CONST: return P.parseConstSpec(loc); case token.CONST: return P.parseConstSpec(loc, comment);
case token.TYPE: return P.parseTypeSpec(loc); case token.TYPE: return P.parseTypeSpec(loc, comment);
case token.VAR: return P.parseVarSpec(loc); case token.VAR: return P.parseVarSpec(loc, comment);
} }
unreachable(); unreachable();
...@@ -1447,13 +1498,14 @@ func (P *Parser) parseDecl(keyword int) ast.Decl { ...@@ -1447,13 +1498,14 @@ func (P *Parser) parseDecl(keyword int) ast.Decl {
defer un(trace(P, "Decl")); defer un(trace(P, "Decl"));
} }
comment := P.getLastComment();
loc := P.loc; loc := P.loc;
P.expect(keyword); P.expect(keyword);
if P.tok == token.LPAREN { if P.tok == token.LPAREN {
P.next(); P.next();
list := vector.New(0); list := vector.New(0);
for P.tok != token.RPAREN && P.tok != token.EOF { 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 { if P.tok == token.SEMICOLON {
P.next(); P.next();
} else { } else {
...@@ -1473,7 +1525,7 @@ func (P *Parser) parseDecl(keyword int) ast.Decl { ...@@ -1473,7 +1525,7 @@ func (P *Parser) parseDecl(keyword int) ast.Decl {
return &ast.DeclList{loc, keyword, decls, end}; 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 { ...@@ -1491,6 +1543,7 @@ func (P *Parser) parseFunctionDecl() *ast.FuncDecl {
defer un(trace(P, "FunctionDecl")); defer un(trace(P, "FunctionDecl"));
} }
comment := P.getLastComment();
loc := P.loc; loc := P.loc;
P.expect(token.FUNC); P.expect(token.FUNC);
...@@ -1513,7 +1566,7 @@ func (P *Parser) parseFunctionDecl() *ast.FuncDecl { ...@@ -1513,7 +1566,7 @@ func (P *Parser) parseFunctionDecl() *ast.FuncDecl {
body = P.parseBlock(token.LBRACE); body = P.parseBlock(token.LBRACE);
} }
return &ast.FuncDecl{loc, recv, ident, sig, body}; return &ast.FuncDecl{loc, recv, ident, sig, body, comment};
} }
...@@ -1539,35 +1592,44 @@ func (P *Parser) parseDeclaration() ast.Decl { ...@@ -1539,35 +1592,44 @@ func (P *Parser) parseDeclaration() ast.Decl {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Program // Program
// The top level parsing routines: func (P *Parser) getComments() []ast.CommentGroup {
// // convert comments vector
// ParsePackageClause list := make([]ast.CommentGroup, P.comments.Len());
// - parses the package clause only and returns the package name for i := 0; i < P.comments.Len(); i++ {
// list[i] = P.comments.At(i).(ast.CommentGroup);
// ParseImportDecls }
// - parses all import declarations and returns a list of them return list;
// - the package clause must have been parsed before }
// - useful to determine package dependencies
// The Parse function is parametrized with one of the following
// constants. They control how much of the source text is parsed.
// //
// ParseProgram const (
// - parses the entire program and returns the complete AST ParseEntirePackage = iota;
ParseImportDeclsOnly;
ParsePackageClauseOnly;
)
func (P *Parser) ParsePackageClause() *ast.Ident { // Parse parses the source...
//
// foo bar
//
func (P *Parser) Parse(mode int) *ast.Program {
if P.trace { if P.trace {
defer un(trace(P, "PackageClause")); defer un(trace(P, "Program"));
} }
// package clause
comment := P.getLastComment();
loc := P.loc;
P.expect(token.PACKAGE); P.expect(token.PACKAGE);
return P.parseIdent(); name := P.parseIdent();
} var decls []ast.Decl;
func (P *Parser) parseImportDecls() *vector.Vector {
if P.trace {
defer un(trace(P, "ImportDecls"));
}
if mode <= ParseImportDeclsOnly {
// import decls
list := vector.New(0); list := vector.New(0);
for P.tok == token.IMPORT { for P.tok == token.IMPORT {
list.Push(P.parseDecl(token.IMPORT)); list.Push(P.parseDecl(token.IMPORT));
...@@ -1576,61 +1638,22 @@ func (P *Parser) parseImportDecls() *vector.Vector { ...@@ -1576,61 +1638,22 @@ func (P *Parser) parseImportDecls() *vector.Vector {
} }
} }
return list; if mode <= ParseEntirePackage {
} // rest of package body
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 {
// convert comments vector
list := make([]*ast.Comment, P.comments.Len());
for i := 0; i < P.comments.Len(); i++ {
list[i] = P.comments.At(i).(*ast.Comment);
}
return list;
}
func (P *Parser) ParseProgram() *ast.Program {
if P.trace {
defer un(trace(P, "Program"));
}
p := ast.NewProgram(P.loc);
p.Ident = P.ParsePackageClause();
// package body
list := P.parseImportDecls();
for P.tok != token.EOF { for P.tok != token.EOF {
list.Push(P.parseDeclaration()); list.Push(P.parseDeclaration());
if P.tok == token.SEMICOLON { if P.tok == token.SEMICOLON {
P.next(); P.next();
} }
} }
}
// convert list // convert list
p.Decls = make([]ast.Decl, list.Len()); decls = make([]ast.Decl, list.Len());
for i := 0; i < list.Len(); i++ { for i := 0; i < list.Len(); i++ {
p.Decls[i] = list.At(i).(ast.Decl); decls[i] = list.At(i).(ast.Decl);
}
} }
p.Comments = P.Comments(); return &ast.Program{loc, name, decls, comment, P.getComments()};
return p;
} }
...@@ -53,7 +53,7 @@ func main() { ...@@ -53,7 +53,7 @@ func main() {
sys.Exit(1); sys.Exit(1);
} }
if !*silent { if !*silent {
Printer.Print(os.Stdout, *html, prog); Printer.Print(os.Stdout, prog, *html);
} }
} }
} }
......
...@@ -24,12 +24,11 @@ import ( ...@@ -24,12 +24,11 @@ import (
var ( var (
debug = flag.Bool("debug", false, "print debugging information"); debug = flag.Bool("debug", false, "print debugging information");
def = flag.Bool("def", false, "print 'def' instead of 'const', 'type', 'func' - experimental");
// layout control // layout control
tabwidth = flag.Int("tabwidth", 8, "tab width"); tabwidth = flag.Int("tabwidth", 8, "tab width");
usetabs = flag.Bool("usetabs", true, "align with tabs instead of blanks"); usetabs = flag.Bool("usetabs", true, "align with tabs instead of blanks");
newlines = flag.Bool("newlines", true, "respect newlines in source"); newlines = flag.Bool("newlines", false, "respect newlines in source");
maxnewlines = flag.Int("maxnewlines", 3, "max. number of consecutive newlines"); maxnewlines = flag.Int("maxnewlines", 3, "max. number of consecutive newlines");
// formatting control // formatting control
...@@ -63,6 +62,23 @@ func assert(pred bool) { ...@@ -63,6 +62,23 @@ func assert(pred bool) {
} }
// TODO this should be an AST method
func isExported(name *ast.Ident) bool {
ch, len := utf8.DecodeRuneInString(name.Str, 0);
return unicode.IsUpper(ch);
}
func hasExportedNames(names []*ast.Ident) bool {
for i, name := range names {
if isExported(name) {
return true;
}
}
return false;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Printer // Printer
...@@ -91,14 +107,15 @@ type Printer struct { ...@@ -91,14 +107,15 @@ type Printer struct {
// formatting control // formatting control
html bool; html bool;
full bool; // if false, print interface only; print all otherwise
// comments // comments
comments []*ast.Comment; // the list of all comments comments []ast.CommentGroup; // the list of all comments groups
cindex int; // the current comments index cindex int; // the current comment group index
cpos int; // the position of the next comment cloc scanner.Location; // the position of the next comment group
// current state // current state
lastpos int; // pos after last string lastloc scanner.Location; // location after last string
level int; // scope level level int; // scope level
indentation int; // indentation level (may be different from scope level) indentation int; // indentation level (may be different from scope level)
...@@ -116,22 +133,22 @@ type Printer struct { ...@@ -116,22 +133,22 @@ type Printer struct {
} }
func (P *Printer) HasComment(pos int) bool { func (P *Printer) hasComment(loc scanner.Location) bool {
return *comments && P.cpos < pos; return *comments && P.cloc.Pos < loc.Pos;
} }
func (P *Printer) NextComment() { func (P *Printer) nextCommentGroup() {
P.cindex++; P.cindex++;
if P.comments != nil && P.cindex < len(P.comments) { if P.comments != nil && P.cindex < len(P.comments) {
P.cpos = P.comments[P.cindex].Loc.Pos; P.cloc = P.comments[P.cindex][0].Loc;
} else { } else {
P.cpos = 1<<30; // infinite P.cloc = scanner.Location{1<<30, 1<<30, 1}; // infinite
} }
} }
func (P *Printer) Init(text io.Write, html bool, comments []*ast.Comment) { func (P *Printer) Init(text io.Write, comments []ast.CommentGroup, html bool) {
// writers // writers
P.text = text; P.text = text;
...@@ -141,7 +158,7 @@ func (P *Printer) Init(text io.Write, html bool, comments []*ast.Comment) { ...@@ -141,7 +158,7 @@ func (P *Printer) Init(text io.Write, html bool, comments []*ast.Comment) {
// comments // comments
P.comments = comments; P.comments = comments;
P.cindex = -1; P.cindex = -1;
P.NextComment(); P.nextCommentGroup();
// formatting parameters & semantic state initialized correctly by default // formatting parameters & semantic state initialized correctly by default
...@@ -194,14 +211,15 @@ func (P *Printer) Printf(format string, s ...) { ...@@ -194,14 +211,15 @@ func (P *Printer) Printf(format string, s ...) {
} }
func (P *Printer) Newline(n int) { func (P *Printer) newline(n int) {
if n > 0 { if n > 0 {
m := int(*maxnewlines); m := int(*maxnewlines);
if n > m { if n > m {
n = m; n = m;
} }
for ; n > 0; n-- { for n > 0 {
P.Printf("\n"); P.Printf("\n");
n--;
} }
for i := P.indentation; i > 0; i-- { for i := P.indentation; i > 0; i-- {
P.Printf("\t"); P.Printf("\t");
...@@ -214,7 +232,7 @@ func (P *Printer) TaggedString(loc scanner.Location, tag, s, endtag string) { ...@@ -214,7 +232,7 @@ func (P *Printer) TaggedString(loc scanner.Location, tag, s, endtag string) {
// use estimate for pos if we don't have one // use estimate for pos if we don't have one
pos := loc.Pos; pos := loc.Pos;
if pos == 0 { if pos == 0 {
pos = P.lastpos; pos = P.lastloc.Pos;
} }
// -------------------------------- // --------------------------------
...@@ -252,26 +270,22 @@ func (P *Printer) TaggedString(loc scanner.Location, tag, s, endtag string) { ...@@ -252,26 +270,22 @@ func (P *Printer) TaggedString(loc scanner.Location, tag, s, endtag string) {
// -------------------------------- // --------------------------------
// interleave comments, if any // interleave comments, if any
nlcount := 0; nlcount := 0;
for ; P.HasComment(pos); P.NextComment() { if P.full {
// we have a comment/newline that comes before the string for ; P.hasComment(loc); P.nextCommentGroup() {
comment := P.comments[P.cindex]; // we have a comment group that comes before the string
comment := P.comments[P.cindex][0]; // TODO broken
ctext := string(comment.Text); // TODO get rid of string conversion here ctext := string(comment.Text); // TODO get rid of string conversion here
if ctext == "\n" {
// found a newline in src - count it
nlcount++;
} else {
// classify comment (len(ctext) >= 2) // classify comment (len(ctext) >= 2)
//-style comment //-style comment
if nlcount > 0 || P.cpos == 0 { if nlcount > 0 || P.cloc.Pos == 0 {
// only white space before comment on this line // only white space before comment on this line
// or file starts with comment // or file starts with comment
// - indent // - indent
if !*newlines && P.cpos != 0 { if !*newlines && P.cloc.Pos != 0 {
nlcount = 1; nlcount = 1;
} }
P.Newline(nlcount); P.newline(nlcount);
nlcount = 0; nlcount = 0;
} else { } else {
...@@ -304,23 +318,16 @@ func (P *Printer) TaggedString(loc scanner.Location, tag, s, endtag string) { ...@@ -304,23 +318,16 @@ func (P *Printer) TaggedString(loc scanner.Location, tag, s, endtag string) {
// print comment // print comment
if *debug { if *debug {
P.Printf("[%d]", P.cpos); P.Printf("[%d]", P.cloc.Pos);
} }
// calling untabify increases the change for idempotent output // calling untabify increases the change for idempotent output
// since tabs in comments are also interpreted by tabwriter // since tabs in comments are also interpreted by tabwriter
P.Printf("%s", P.htmlEscape(untabify(ctext))); P.Printf("%s", P.htmlEscape(untabify(ctext)));
if ctext[1] == '/' {
//-style comments must end in newline
if P.newlines == 0 { // don't add newlines if not needed
P.newlines = 1;
}
}
}
} }
// At this point we may have nlcount > 0: In this case we found newlines // At this point we may have nlcount > 0: In this case we found newlines
// that were not followed by a comment. They are recognized (or not) when // that were not followed by a comment. They are recognized (or not) when
// printing newlines below. // printing newlines below.
}
// -------------------------------- // --------------------------------
// interpret state // interpret state
...@@ -346,7 +353,7 @@ func (P *Printer) TaggedString(loc scanner.Location, tag, s, endtag string) { ...@@ -346,7 +353,7 @@ func (P *Printer) TaggedString(loc scanner.Location, tag, s, endtag string) {
P.newlines = nlcount; P.newlines = nlcount;
} }
nlcount = 0; nlcount = 0;
P.Newline(P.newlines); P.newline(P.newlines);
P.newlines = 0; P.newlines = 0;
// -------------------------------- // --------------------------------
...@@ -375,7 +382,9 @@ func (P *Printer) TaggedString(loc scanner.Location, tag, s, endtag string) { ...@@ -375,7 +382,9 @@ func (P *Printer) TaggedString(loc scanner.Location, tag, s, endtag string) {
// -------------------------------- // --------------------------------
// done // done
P.opt_semi = false; P.opt_semi = false;
P.lastpos = pos + len(s); // rough estimate loc.Pos += len(s); // rough estimate
loc.Col += len(s); // rough estimate
P.lastloc = loc;
} }
...@@ -437,15 +446,20 @@ func (P *Printer) HtmlPackageName(loc scanner.Location, name string) { ...@@ -437,15 +446,20 @@ func (P *Printer) HtmlPackageName(loc scanner.Location, name string) {
func (P *Printer) Expr(x ast.Expr) func (P *Printer) Expr(x ast.Expr)
func (P *Printer) Idents(list []*ast.Ident) { func (P *Printer) Idents(list []*ast.Ident, full bool) int {
n := 0;
for i, x := range list { for i, x := range list {
if i > 0 { if n > 0 {
P.Token(noloc, token.COMMA); P.Token(noloc, token.COMMA);
P.separator = blank; P.separator = blank;
P.state = inside_list; P.state = inside_list;
} }
if full || isExported(x) {
P.Expr(x); P.Expr(x);
n++;
}
} }
return n;
} }
...@@ -456,8 +470,8 @@ func (P *Printer) Parameters(list []*ast.Field) { ...@@ -456,8 +470,8 @@ func (P *Printer) Parameters(list []*ast.Field) {
if i > 0 { if i > 0 {
P.separator = comma; P.separator = comma;
} }
if len(par.Idents) > 0 { n := P.Idents(par.Idents, true);
P.Idents(par.Idents); if n > 0 {
P.separator = blank P.separator = blank
}; };
P.Expr(par.Typ); P.Expr(par.Typ);
...@@ -501,10 +515,13 @@ func (P *Printer) Fields(list []*ast.Field, end scanner.Location, is_interface b ...@@ -501,10 +515,13 @@ func (P *Printer) Fields(list []*ast.Field, end scanner.Location, is_interface b
P.separator = semicolon; P.separator = semicolon;
P.newlines = 1; P.newlines = 1;
} }
if len(fld.Idents) > 0 { n := P.Idents(fld.Idents, P.full);
P.Idents(fld.Idents); if n > 0 {
// at least one identifier
P.separator = tab P.separator = tab
}; };
if n > 0 || len(fld.Idents) == 0 {
// at least one identifier or anonymous field
if is_interface { if is_interface {
if ftyp, is_ftyp := fld.Typ.(*ast.FunctionType); is_ftyp { if ftyp, is_ftyp := fld.Typ.(*ast.FunctionType); is_ftyp {
P.Signature(ftyp.Sig); P.Signature(ftyp.Sig);
...@@ -519,6 +536,7 @@ func (P *Printer) Fields(list []*ast.Field, end scanner.Location, is_interface b ...@@ -519,6 +536,7 @@ func (P *Printer) Fields(list []*ast.Field, end scanner.Location, is_interface b
} }
} }
} }
}
P.newlines = 1; P.newlines = 1;
} }
...@@ -977,7 +995,7 @@ func (P *Printer) DoConstDecl(d *ast.ConstDecl) { ...@@ -977,7 +995,7 @@ func (P *Printer) DoConstDecl(d *ast.ConstDecl) {
P.Token(d.Loc, token.CONST); P.Token(d.Loc, token.CONST);
P.separator = blank; P.separator = blank;
} }
P.Idents(d.Idents); P.Idents(d.Idents, P.full);
if d.Typ != nil { if d.Typ != nil {
P.separator = blank; // TODO switch to tab? (indentation problem with structs) P.separator = blank; // TODO switch to tab? (indentation problem with structs)
P.Expr(d.Typ); P.Expr(d.Typ);
...@@ -1009,7 +1027,7 @@ func (P *Printer) DoVarDecl(d *ast.VarDecl) { ...@@ -1009,7 +1027,7 @@ func (P *Printer) DoVarDecl(d *ast.VarDecl) {
P.Token(d.Loc, token.VAR); P.Token(d.Loc, token.VAR);
P.separator = blank; P.separator = blank;
} }
P.Idents(d.Idents); P.Idents(d.Idents, P.full);
if d.Typ != nil { if d.Typ != nil {
P.separator = blank; // TODO switch to tab? (indentation problem with structs) P.separator = blank; // TODO switch to tab? (indentation problem with structs)
P.Expr(d.Typ); P.Expr(d.Typ);
...@@ -1025,7 +1043,7 @@ func (P *Printer) DoVarDecl(d *ast.VarDecl) { ...@@ -1025,7 +1043,7 @@ func (P *Printer) DoVarDecl(d *ast.VarDecl) {
} }
func (P *Printer) funcDecl(d *ast.FuncDecl, with_body bool) { func (P *Printer) DoFuncDecl(d *ast.FuncDecl) {
P.Token(d.Loc, token.FUNC); P.Token(d.Loc, token.FUNC);
P.separator = blank; P.separator = blank;
if recv := d.Recv; recv != nil { if recv := d.Recv; recv != nil {
...@@ -1041,7 +1059,7 @@ func (P *Printer) funcDecl(d *ast.FuncDecl, with_body bool) { ...@@ -1041,7 +1059,7 @@ func (P *Printer) funcDecl(d *ast.FuncDecl, with_body bool) {
} }
P.Expr(d.Ident); P.Expr(d.Ident);
P.Signature(d.Sig); P.Signature(d.Sig);
if with_body && d.Body != nil { if P.full && d.Body != nil {
P.separator = blank; P.separator = blank;
P.Block(d.Body, true); P.Block(d.Body, true);
} }
...@@ -1049,17 +1067,8 @@ func (P *Printer) funcDecl(d *ast.FuncDecl, with_body bool) { ...@@ -1049,17 +1067,8 @@ func (P *Printer) funcDecl(d *ast.FuncDecl, with_body bool) {
} }
func (P *Printer) DoFuncDecl(d *ast.FuncDecl) {
P.funcDecl(d, true);
}
func (P *Printer) DoDeclList(d *ast.DeclList) { func (P *Printer) DoDeclList(d *ast.DeclList) {
if !*def || d.Tok == token.IMPORT || d.Tok == token.VAR {
P.Token(d.Loc, d.Tok); P.Token(d.Loc, d.Tok);
} else {
P.String(d.Loc, "def");
}
P.separator = blank; P.separator = blank;
// group of parenthesized declarations // group of parenthesized declarations
...@@ -1090,26 +1099,111 @@ func (P *Printer) Decl(d ast.Decl) { ...@@ -1090,26 +1099,111 @@ func (P *Printer) Decl(d ast.Decl) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Package interface // Package interface
// TODO this should be an AST method func stripWhiteSpace(s []byte) []byte {
func isExported(name *ast.Ident) bool { i, j := 0, len(s);
ch, len := utf8.DecodeRuneInString(name.Str, 0); for i < len(s) && s[i] <= ' ' {
return unicode.IsUpper(ch); i++;
}
for j > i && s[j-1] <= ' ' {
j--
}
return s[i : j];
}
func cleanComment(s []byte) []byte {
switch s[1] {
case '/': s = s[2 : len(s)-1];
case '*': s = s[2 : len(s)-2];
default : panic("illegal comment");
}
return stripWhiteSpace(s);
}
func (P *Printer) printComment(comment ast.CommentGroup) {
in_paragraph := false;
for i, c := range comment {
s := cleanComment(c.Text);
if len(s) > 0 {
if !in_paragraph {
P.Printf("<p>\n");
in_paragraph = true;
}
P.Printf("%s\n", P.htmlEscape(untabify(string(s))));
} else {
if in_paragraph {
P.Printf("</p>\n");
in_paragraph = false;
}
}
}
if in_paragraph {
P.Printf("</p>\n");
}
} }
func (P *Printer) Interface(p *ast.Program) { func (P *Printer) Interface(p *ast.Program) {
P.full = false;
for i := 0; i < len(p.Decls); i++ { for i := 0; i < len(p.Decls); i++ {
switch d := p.Decls[i].(type) { switch d := p.Decls[i].(type) {
case *ast.ConstDecl:
if hasExportedNames(d.Idents) {
P.Printf("<h2>Constants</h2>\n");
P.Printf("<p><pre>");
P.DoConstDecl(d);
P.String(noloc, "");
P.Printf("</pre></p>\n");
if d.Comment != nil {
P.printComment(d.Comment);
}
}
case *ast.TypeDecl:
if isExported(d.Ident) {
P.Printf("<h2>type %s</h2>\n", d.Ident.Str);
P.Printf("<p><pre>");
P.DoTypeDecl(d);
P.String(noloc, "");
P.Printf("</pre></p>\n");
if d.Comment != nil {
P.printComment(d.Comment);
}
}
case *ast.VarDecl:
if hasExportedNames(d.Idents) {
P.Printf("<h2>Variables</h2>\n");
P.Printf("<p><pre>");
P.DoVarDecl(d);
P.String(noloc, "");
P.Printf("</pre></p>\n");
if d.Comment != nil {
P.printComment(d.Comment);
}
}
case *ast.FuncDecl: case *ast.FuncDecl:
if isExported(d.Ident) { if isExported(d.Ident) {
P.Printf("<h2>%s</h2>\n", d.Ident.Str); if d.Recv != nil {
/* P.Printf("<h3>func (");
P.Expr(d.Recv.Typ);
P.Printf(") %s</h3>\n", d.Ident.Str);
} else {
P.Printf("<h2>func %s</h2>\n", d.Ident.Str);
}
P.Printf("<p><code>"); P.Printf("<p><code>");
P.funcDecl(d, false); P.DoFuncDecl(d);
P.String(noloc, ""); P.String(noloc, "");
P.Printf("</code></p>"); P.Printf("</code></p>\n");
*/ if d.Comment != nil {
P.printComment(d.Comment);
}
} }
case *ast.DeclList:
} }
} }
} }
...@@ -1119,6 +1213,7 @@ func (P *Printer) Interface(p *ast.Program) { ...@@ -1119,6 +1213,7 @@ func (P *Printer) Interface(p *ast.Program) {
// Program // Program
func (P *Printer) Program(p *ast.Program) { func (P *Printer) Program(p *ast.Program) {
P.full = true;
P.Token(p.Loc, token.PACKAGE); P.Token(p.Loc, token.PACKAGE);
P.separator = blank; P.separator = blank;
P.Expr(p.Ident); P.Expr(p.Ident);
...@@ -1140,7 +1235,7 @@ func init() { ...@@ -1140,7 +1235,7 @@ func init() {
} }
func Print(writer io.Write, html bool, prog *ast.Program) { func Print(writer io.Write, prog *ast.Program, html bool) {
// setup // setup
var P Printer; var P Printer;
padchar := byte(' '); padchar := byte(' ');
...@@ -1152,13 +1247,14 @@ func Print(writer io.Write, html bool, prog *ast.Program) { ...@@ -1152,13 +1247,14 @@ func Print(writer io.Write, html bool, prog *ast.Program) {
flags |= tabwriter.FilterHTML; flags |= tabwriter.FilterHTML;
} }
text := tabwriter.NewWriter(writer, *tabwidth, 1, padchar, flags); text := tabwriter.NewWriter(writer, *tabwidth, 1, padchar, flags);
P.Init(text, html, prog.Comments); P.Init(text, nil /* prog.Comments */, html);
if P.html { if P.html {
err := templ.Apply(text, "<!--", template.Substitution { err := templ.Apply(text, "<!--", template.Substitution {
"PACKAGE-->" : func() { P.Printf("%s", prog.Ident.Str); }, "PACKAGE_NAME-->" : func() { P.Printf("%s", prog.Ident.Str); },
"INTERFACE-->" : func() { P.Interface(prog); }, "PACKAGE_COMMENT-->": func() { P.printComment(prog.Comment); },
"BODY-->" : func() { P.Program(prog); }, "PACKAGE_INTERFACE-->" : func() { P.Interface(prog); },
"PACKAGE_BODY-->" : func() { P.Program(prog); },
}); });
if err != nil { if err != nil {
panic("print error - exiting"); panic("print error - exiting");
......
<h1>package <!--PACKAGE--></h1> <font color=red>THIS SECTION IS CURRENTLY UNDER CONSTRUCTION</font>
<!--INTERFACE--> <h1>package <!--PACKAGE_NAME--></h1>
<!--PACKAGE_COMMENT-->
<!--PACKAGE_INTERFACE-->
<hr /> <hr />
<h1>Implementation</h1>
<h1>package <!--PACKAGE--></h1> <font color=grey>Comments are currently not shown in the source.</font>
<pre> <pre>
<!--BODY--> <!--PACKAGE_BODY-->
</pre> </pre>
</div> <!-- content --> </div> <!-- content -->
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment