Commit 8971cf23 authored by Robert Griesemer's avatar Robert Griesemer

daily snapshot:

- separating printing of AST and documentation
- astprinter: will subsume ast printing functionality of printer
- docprinter: will subsume doc printing functionality of printer
        also: more logic to collect all the documentation pertaining
	      to all files of a package
- parser: some cleanups, stricter syntax checks
- gds: hooks to test new doc printer (disabled)

R=r
OCL=26915
CL=26915
parent 8e54729b
...@@ -28,7 +28,7 @@ install: pretty ...@@ -28,7 +28,7 @@ install: pretty
clean: clean:
rm -f pretty *.6 *.a *~ rm -f pretty *.6 *.a *~
gds.6: utils.6 platform.6 compilation.6 printer.6 gds.6: utils.6 platform.6 compilation.6 printer.6 docprinter.6 astprinter.6
pretty.6: platform.6 printer.6 compilation.6 pretty.6: platform.6 printer.6 compilation.6
...@@ -46,5 +46,9 @@ platform.6: utils.6 ...@@ -46,5 +46,9 @@ platform.6: utils.6
printer.6: utils.6 ast.6 symboltable.6 template.6 printer.6: utils.6 ast.6 symboltable.6 template.6
astprinter.6: utils.6 ast.6 symboltable.6 template.6
docprinter.6: ast.6 astprinter.6 template.6
%.6: %.go %.6: %.go
$(G) $(F) $< $(G) $(F) $<
This diff is collapsed.
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package docPrinter
import (
"vector";
"utf8";
"unicode";
"io";
"fmt";
"ast";
"astprinter";
"template";
)
// ----------------------------------------------------------------------------
// Elementary support
// TODO this should be an AST method
func isExported(name *ast.Ident) bool {
ch, len := utf8.DecodeRune(name.Lit);
return unicode.IsUpper(ch);
}
func hasExportedNames(names []*ast.Ident) bool {
for i, name := range names {
if isExported(name) {
return true;
}
}
return false;
}
// ----------------------------------------------------------------------------
type constDoc struct {
cast *ast.ConstDecl;
}
type varDoc struct {
vast *ast.VarDecl;
}
type funcDoc struct {
fast *ast.FuncDecl;
}
type typeDoc struct {
tast *ast.TypeDecl;
methods map[string] *funcDoc;
}
type PackageDoc struct {
name string; // package name
imports map[string] string;
consts map[string] *constDoc;
types map[string] *typeDoc;
vars map[string] *varDoc;
funcs map[string] *funcDoc;
}
// PackageDoc initializes a document to collect package documentation.
// The package name is provided as initial argument. Use AddPackage to
// add the AST for each source file belonging to the same package.
//
func (P *PackageDoc) Init(name string) {
P.name = name;
P.imports = make(map[string] string);
P.consts = make(map[string] *constDoc);
P.types = make(map[string] *typeDoc);
P.vars = make(map[string] *varDoc);
P.funcs = make(map[string] *funcDoc);
}
func (P *PackageDoc) addDecl(decl ast.Decl) {
switch d := decl.(type) {
case *ast.ImportDecl:
case *ast.ConstDecl:
if hasExportedNames(d.Names) {
}
case *ast.TypeDecl:
if isExported(d.Name) {
}
case *ast.VarDecl:
if hasExportedNames(d.Names) {
}
case *ast.FuncDecl:
if isExported(d.Name) {
if d.Recv != nil {
// method
} else {
// ordinary function
}
}
case *ast.DeclList:
for i, decl := range d.List {
P.addDecl(decl);
}
}
}
// AddPackage adds the AST of a source file belonging to the same
// package. The package names must match. If the package was added
// before, AddPackage is a no-op.
//
func (P *PackageDoc) AddPackage(pak *ast.Package) {
if P.name != string(pak.Name.Lit) {
panic("package names don't match");
}
// add all declarations
for i, decl := range pak.Decls {
P.addDecl(decl);
}
}
func (P *PackageDoc) printConsts(p *astPrinter.Printer) {
}
func (P *PackageDoc) printTypes(p *astPrinter.Printer) {
}
func (P *PackageDoc) printVars(p *astPrinter.Printer) {
}
func (P *PackageDoc) printFuncs(p *astPrinter.Printer) {
}
func (P *PackageDoc) printPackage(p *astPrinter.Printer) {
}
// TODO make this a parameter for Init or Print?
var templ = template.NewTemplateOrDie("template.html");
func (P *PackageDoc) Print(writer io.Write) {
var astp astPrinter.Printer;
astp.Init(writer, nil, true);
err := templ.Apply(writer, "<!--", template.Substitution {
"PACKAGE_NAME-->" : func() { fmt.Fprint(writer, P.name); },
"PACKAGE_COMMENT-->": func() { },
"PACKAGE_INTERFACE-->" : func() { },
"PACKAGE_BODY-->" : func() { },
});
if err != nil {
panic("print error - exiting");
}
}
...@@ -22,6 +22,8 @@ import ( ...@@ -22,6 +22,8 @@ import (
"platform"; "platform";
"compilation"; "compilation";
"printer"; "printer";
"tabwriter";
"docprinter";
) )
...@@ -29,6 +31,11 @@ var ( ...@@ -29,6 +31,11 @@ var (
verbose = flag.Bool("v", false, "verbose mode"); verbose = flag.Bool("v", false, "verbose mode");
port = flag.String("port", "6060", "server port"); port = flag.String("port", "6060", "server port");
root = flag.String("root", Platform.GOROOT, "go root directory"); root = flag.String("root", Platform.GOROOT, "go root directory");
// layout control
tabwidth = flag.Int("gds_tabwidth", 4, "tab width");
usetabs = flag.Bool("gds_usetabs", false, "align with tabs instead of blanks");
newdoc = flag.Bool("newdoc", false, "use new document printing"); // TODO remove once this works
) )
...@@ -159,7 +166,31 @@ func serveFile(c *http.Conn, filename string) { ...@@ -159,7 +166,31 @@ 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");
if *newdoc {
// initialize tabwriter for nicely aligned output
padchar := byte(' ');
if *usetabs {
padchar = '\t';
}
writer := tabwriter.NewWriter(c, *tabwidth, 1, padchar, tabwriter.FilterHTML);
// write documentation
var doc docPrinter.PackageDoc;
doc.Init(string(prog.Name.Lit));
doc.AddPackage(prog);
doc.Print(writer);
// flush any pending output
err := writer.Flush();
if err != nil {
panic("print error - exiting");
}
} else {
// TODO remove once the new document stuff works better
// than the old code
Printer.Print(c, prog, true); Printer.Print(c, prog, true);
}
} }
......
...@@ -1045,85 +1045,101 @@ func (p *parser) parseCompositeLit(typ ast.Expr) ast.Expr { ...@@ -1045,85 +1045,101 @@ func (p *parser) parseCompositeLit(typ ast.Expr) ast.Expr {
} }
// TODO apply these make functions more thoroughly // TODO Consider different approach to checking syntax after parsing:
// (all uses of parseExpression; also should call // Provide a arguments (set of flags) to parsing functions
// them something better - verifyX?) // restricting what they are syupposed to accept depending
// on context.
// makeExpr makes sure x is an expression and not a type. // checkExpr checks that x is an expression (and not a type).
func (p *parser) makeExpr(x ast.Expr) ast.Expr { func (p *parser) checkExpr(x ast.Expr) ast.Expr {
// TODO should provide predicate in AST nodes // TODO should provide predicate in AST nodes
switch t := x.(type) { switch t := x.(type) {
case *ast.BadExpr: return x; case *ast.BadExpr:
case *ast.Ident: return x; case *ast.Ident:
case *ast.IntLit: return x; case *ast.IntLit:
case *ast.FloatLit: return x; case *ast.FloatLit:
case *ast.CharLit: return x; case *ast.CharLit:
case *ast.StringLit: return x; case *ast.StringLit:
case *ast.StringList: return x; case *ast.StringList:
case *ast.FunctionLit: return x; case *ast.FunctionLit:
case *ast.CompositeLit: return x; case *ast.CompositeLit:
case *ast.ParenExpr: p.makeExpr(t.X); return x; case *ast.ParenExpr:
case *ast.SelectorExpr: return x; case *ast.SelectorExpr:
case *ast.IndexExpr: return x; case *ast.IndexExpr:
case *ast.SliceExpr: return x; case *ast.SliceExpr:
case *ast.TypeAssertExpr: return x; case *ast.TypeAssertExpr:
case *ast.CallExpr: return x; case *ast.CallExpr:
case *ast.StarExpr: return x; case *ast.StarExpr:
case *ast.UnaryExpr: return x; case *ast.UnaryExpr:
case *ast.BinaryExpr: return x; if t.Op == token.RANGE {
// the range operator is only allowed at the top of a for statement
p.error_expected(x.Pos(), "expression");
x = &ast.BadExpr{x.Pos()};
} }
case *ast.BinaryExpr:
default:
// all other nodes are not proper expressions // all other nodes are not proper expressions
p.error_expected(x.Pos(), "expression"); p.error_expected(x.Pos(), "expression");
return &ast.BadExpr{x.Pos()}; x = &ast.BadExpr{x.Pos()};
}
return x;
} }
// makeTypeName makes sure that x is type name. // checkTypeName checks that x is type name.
func (p *parser) makeTypeName(x ast.Expr) ast.Expr { func (p *parser) checkTypeName(x ast.Expr) ast.Expr {
// TODO should provide predicate in AST nodes // TODO should provide predicate in AST nodes
switch t := x.(type) { switch t := x.(type) {
case *ast.BadExpr: return x; case *ast.BadExpr:
case *ast.Ident: return x; case *ast.Ident:
case *ast.ParenExpr: p.makeTypeName(t.X); return x; // TODO should (TypeName) be illegal? case *ast.ParenExpr: p.checkTypeName(t.X); // TODO should (TypeName) be illegal?
case *ast.SelectorExpr: p.makeTypeName(t.X); return x; case *ast.SelectorExpr: p.checkTypeName(t.X);
} default:
// all other nodes are not type names // all other nodes are not type names
p.error_expected(x.Pos(), "type name"); p.error_expected(x.Pos(), "type name");
return &ast.BadExpr{x.Pos()}; x = &ast.BadExpr{x.Pos()};
}
return x;
} }
// makeCompositeLitType makes sure x is a legal composite literal type. // checkCompositeLitType checks that x is a legal composite literal type.
func (p *parser) makeCompositeLitType(x ast.Expr) ast.Expr { func (p *parser) checkCompositeLitType(x ast.Expr) ast.Expr {
// TODO should provide predicate in AST nodes // TODO should provide predicate in AST nodes
switch t := x.(type) { switch t := x.(type) {
case *ast.BadExpr: return x; case *ast.BadExpr: return x;
case *ast.Ident: return x; case *ast.Ident: return x;
case *ast.ParenExpr: p.makeCompositeLitType(t.X); return x; case *ast.ParenExpr: p.checkCompositeLitType(t.X);
case *ast.SelectorExpr: p.makeTypeName(t.X); return x; case *ast.SelectorExpr: p.checkTypeName(t.X);
case *ast.ArrayType: return x; case *ast.ArrayType: return x;
case *ast.SliceType: return x; case *ast.SliceType: return x;
case *ast.StructType: return x; case *ast.StructType: return x;
case *ast.MapType: return x; case *ast.MapType: return x;
} default:
// all other nodes are not legal composite literal types // all other nodes are not legal composite literal types
p.error_expected(x.Pos(), "composite literal type"); p.error_expected(x.Pos(), "composite literal type");
return &ast.BadExpr{x.Pos()}; x = &ast.BadExpr{x.Pos()};
}
return x;
} }
// makeExprOrType makes sure that x is an expression or a type // checkExprOrType checks that x is an expression or a type
// (and not a raw type such as [...]T). // (and not a raw type such as [...]T).
// //
func (p *parser) makeExprOrType(x ast.Expr) ast.Expr { func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
// TODO should provide predicate in AST nodes // TODO should provide predicate in AST nodes
if t, is_array := x.(*ast.ArrayType); is_array { switch t := x.(type) {
case *ast.UnaryExpr:
if t.Op == token.RANGE {
// the range operator is only allowed at the top of a for statement
p.error_expected(x.Pos(), "expression");
x = &ast.BadExpr{x.Pos()};
}
case *ast.ArrayType:
if len, is_ellipsis := t.Len.(*ast.Ellipsis); is_ellipsis { if len, is_ellipsis := t.Len.(*ast.Ellipsis); is_ellipsis {
p.error(len.Pos(), "expected array length, found '...'"); p.error(len.Pos(), "expected array length, found '...'");
return &ast.BadExpr{x.Pos()}; x = &ast.BadExpr{x.Pos()};
} }
} }
...@@ -1140,17 +1156,17 @@ func (p *parser) parsePrimaryExpr() ast.Expr { ...@@ -1140,17 +1156,17 @@ func (p *parser) parsePrimaryExpr() ast.Expr {
x := p.parseOperand(); x := p.parseOperand();
for { for {
switch p.tok { switch p.tok {
case token.PERIOD: x = p.parseSelectorOrTypeAssertion(p.makeExpr(x)); case token.PERIOD: x = p.parseSelectorOrTypeAssertion(p.checkExpr(x));
case token.LBRACK: x = p.parseIndexOrSlice(p.makeExpr(x)); case token.LBRACK: x = p.parseIndexOrSlice(p.checkExpr(x));
case token.LPAREN: x = p.parseCallOrConversion(p.makeExprOrType(x)); case token.LPAREN: x = p.parseCallOrConversion(p.checkExprOrType(x));
case token.LBRACE: case token.LBRACE:
if p.expr_lev >= 0 { if p.expr_lev >= 0 {
x = p.parseCompositeLit(p.makeCompositeLitType(x)); x = p.parseCompositeLit(p.checkCompositeLitType(x));
} else { } else {
return p.makeExprOrType(x); return p.checkExprOrType(x);
} }
default: default:
return p.makeExprOrType(x); return p.checkExprOrType(x);
} }
} }
...@@ -1169,14 +1185,14 @@ func (p *parser) parseUnaryExpr() ast.Expr { ...@@ -1169,14 +1185,14 @@ func (p *parser) parseUnaryExpr() ast.Expr {
pos, op := p.pos, p.tok; pos, op := p.pos, p.tok;
p.next(); p.next();
x := p.parseUnaryExpr(); x := p.parseUnaryExpr();
return &ast.UnaryExpr{pos, op, p.makeExpr(x)}; return &ast.UnaryExpr{pos, op, p.checkExpr(x)};
case token.MUL: case token.MUL:
// unary "*" expression or pointer type // unary "*" expression or pointer type
pos := p.pos; pos := p.pos;
p.next(); p.next();
x := p.parseUnaryExpr(); x := p.parseUnaryExpr();
return &ast.StarExpr{pos, p.makeExprOrType(x)}; return &ast.StarExpr{pos, p.checkExprOrType(x)};
} }
return p.parsePrimaryExpr(); return p.parsePrimaryExpr();
...@@ -1194,7 +1210,7 @@ func (p *parser) parseBinaryExpr(prec1 int) ast.Expr { ...@@ -1194,7 +1210,7 @@ func (p *parser) parseBinaryExpr(prec1 int) ast.Expr {
pos, op := p.pos, p.tok; pos, op := p.pos, p.tok;
p.next(); p.next();
y := p.parseBinaryExpr(prec + 1); y := p.parseBinaryExpr(prec + 1);
x = &ast.BinaryExpr{p.makeExpr(x), pos, op, p.makeExpr(y)}; x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)};
} }
} }
...@@ -1215,7 +1231,7 @@ func (p *parser) parseExpression() ast.Expr { ...@@ -1215,7 +1231,7 @@ func (p *parser) parseExpression() ast.Expr {
// Statements // Statements
func (p *parser) parseSimpleStmt() ast.Stmt { func (p *parser) parseSimpleStmt(label_ok bool) ast.Stmt {
if p.trace { if p.trace {
defer un(trace(p, "SimpleStmt")); defer un(trace(p, "SimpleStmt"));
} }
...@@ -1225,8 +1241,8 @@ func (p *parser) parseSimpleStmt() ast.Stmt { ...@@ -1225,8 +1241,8 @@ func (p *parser) parseSimpleStmt() ast.Stmt {
switch p.tok { switch p.tok {
case token.COLON: case token.COLON:
// labeled statement // labeled statement
p.expect(token.COLON); p.next();
if len(x) == 1 { if label_ok && len(x) == 1 {
if label, is_ident := x[0].(*ast.Ident); is_ident { if label, is_ident := x[0].(*ast.Ident); is_ident {
return &ast.LabeledStmt{label, p.parseStatement()}; return &ast.LabeledStmt{label, p.parseStatement()};
} }
...@@ -1344,12 +1360,12 @@ func (p *parser) isExpr(s ast.Stmt) bool { ...@@ -1344,12 +1360,12 @@ func (p *parser) isExpr(s ast.Stmt) bool {
} }
func (p *parser) asExpr(s ast.Stmt) ast.Expr { func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
if s == nil { if s == nil {
return nil; return nil;
} }
if es, is_expr := s.(*ast.ExprStmt); is_expr { if es, is_expr := s.(*ast.ExprStmt); is_expr {
return es.X; return p.checkExpr(es.X);
} }
p.error(s.Pos(), "expected condition, found simple statement"); p.error(s.Pos(), "expected condition, found simple statement");
return &ast.BadExpr{s.Pos()}; return &ast.BadExpr{s.Pos()};
...@@ -1362,18 +1378,18 @@ func (p *parser) parseControlClause(isForStmt bool) (s1, s2, s3 ast.Stmt) { ...@@ -1362,18 +1378,18 @@ func (p *parser) parseControlClause(isForStmt bool) (s1, s2, s3 ast.Stmt) {
p.expr_lev = -1; p.expr_lev = -1;
if p.tok != token.SEMICOLON { if p.tok != token.SEMICOLON {
s1 = p.parseSimpleStmt(); s1 = p.parseSimpleStmt(false);
} }
if p.tok == token.SEMICOLON { if p.tok == token.SEMICOLON {
p.next(); p.next();
if p.tok != token.LBRACE && p.tok != token.SEMICOLON { if p.tok != token.LBRACE && p.tok != token.SEMICOLON {
s2 = p.parseSimpleStmt(); s2 = p.parseSimpleStmt(false);
} }
if isForStmt { if isForStmt {
// for statements have a 3rd section // for statements have a 3rd section
p.expect(token.SEMICOLON); p.expect(token.SEMICOLON);
if p.tok != token.LBRACE { if p.tok != token.LBRACE {
s3 = p.parseSimpleStmt(); s3 = p.parseSimpleStmt(false);
} }
} }
} else { } else {
...@@ -1401,7 +1417,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt { ...@@ -1401,7 +1417,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
else_ = p.parseStatement(); else_ = p.parseStatement();
} }
return &ast.IfStmt{pos, s1, p.asExpr(s2), body, else_}; return &ast.IfStmt{pos, s1, p.makeExpr(s2), body, else_};
} }
...@@ -1467,7 +1483,7 @@ func (p *parser) parseSwitchStmt() ast.Stmt { ...@@ -1467,7 +1483,7 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
rbrace := p.expect(token.RBRACE); rbrace := p.expect(token.RBRACE);
p.opt_semi = true; p.opt_semi = true;
body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace}; body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace};
return &ast.SwitchStmt{pos, s1, p.asExpr(s2), body}; return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body};
} }
// type switch // type switch
...@@ -1585,7 +1601,7 @@ func (p *parser) parseForStmt() ast.Stmt { ...@@ -1585,7 +1601,7 @@ func (p *parser) parseForStmt() ast.Stmt {
} }
} else { } else {
// regular for statement // regular for statement
return &ast.ForStmt{pos, s1, p.asExpr(s2), s3, body}; return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body};
} }
panic(); // unreachable panic(); // unreachable
...@@ -1606,7 +1622,7 @@ func (p *parser) parseStatement() ast.Stmt { ...@@ -1606,7 +1622,7 @@ func (p *parser) parseStatement() ast.Stmt {
token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operand token.IDENT, token.INT, token.FLOAT, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operand
token.LBRACK, token.STRUCT, // composite type token.LBRACK, token.STRUCT, // composite type
token.MUL, token.AND, token.ARROW: // unary operators token.MUL, token.AND, token.ARROW: // unary operators
return p.parseSimpleStmt(); return p.parseSimpleStmt(true);
case token.GO: case token.GO:
return p.parseGoStmt(); return p.parseGoStmt();
case token.DEFER: case token.DEFER:
...@@ -1778,7 +1794,7 @@ func (p *parser) parseReceiver() *ast.Field { ...@@ -1778,7 +1794,7 @@ func (p *parser) parseReceiver() *ast.Field {
if ptr, is_ptr := base.(*ast.StarExpr); is_ptr { if ptr, is_ptr := base.(*ast.StarExpr); is_ptr {
base = ptr.X; base = ptr.X;
} }
p.makeTypeName(base); p.checkTypeName(base);
return recv; return recv;
} }
......
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