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
clean:
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
......@@ -46,5 +46,9 @@ platform.6: utils.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
$(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 (
"platform";
"compilation";
"printer";
"tabwriter";
"docprinter";
)
......@@ -29,6 +31,11 @@ var (
verbose = flag.Bool("v", false, "verbose mode");
port = flag.String("port", "6060", "server port");
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) {
}
c.SetHeader("content-type", "text/html; charset=utf-8");
Printer.Print(c, prog, true);
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);
}
}
......
......@@ -1045,85 +1045,101 @@ func (p *parser) parseCompositeLit(typ ast.Expr) ast.Expr {
}
// TODO apply these make functions more thoroughly
// (all uses of parseExpression; also should call
// them something better - verifyX?)
// TODO Consider different approach to checking syntax after parsing:
// Provide a arguments (set of flags) to parsing functions
// restricting what they are syupposed to accept depending
// on context.
// makeExpr makes sure x is an expression and not a type.
func (p *parser) makeExpr(x ast.Expr) ast.Expr {
// checkExpr checks that x is an expression (and not a type).
func (p *parser) checkExpr(x ast.Expr) ast.Expr {
// TODO should provide predicate in AST nodes
switch t := x.(type) {
case *ast.BadExpr: return x;
case *ast.Ident: return x;
case *ast.IntLit: return x;
case *ast.FloatLit: return x;
case *ast.CharLit: return x;
case *ast.StringLit: return x;
case *ast.StringList: return x;
case *ast.FunctionLit: return x;
case *ast.CompositeLit: return x;
case *ast.ParenExpr: p.makeExpr(t.X); return x;
case *ast.SelectorExpr: return x;
case *ast.IndexExpr: return x;
case *ast.SliceExpr: return x;
case *ast.TypeAssertExpr: return x;
case *ast.CallExpr: return x;
case *ast.StarExpr: return x;
case *ast.UnaryExpr: return x;
case *ast.BinaryExpr: return x;
case *ast.BadExpr:
case *ast.Ident:
case *ast.IntLit:
case *ast.FloatLit:
case *ast.CharLit:
case *ast.StringLit:
case *ast.StringList:
case *ast.FunctionLit:
case *ast.CompositeLit:
case *ast.ParenExpr:
case *ast.SelectorExpr:
case *ast.IndexExpr:
case *ast.SliceExpr:
case *ast.TypeAssertExpr:
case *ast.CallExpr:
case *ast.StarExpr:
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.BinaryExpr:
default:
// all other nodes are not proper expressions
p.error_expected(x.Pos(), "expression");
x = &ast.BadExpr{x.Pos()};
}
// all other nodes are not proper expressions
p.error_expected(x.Pos(), "expression");
return &ast.BadExpr{x.Pos()};
return x;
}
// makeTypeName makes sure that x is type name.
func (p *parser) makeTypeName(x ast.Expr) ast.Expr {
// checkTypeName checks that x is type name.
func (p *parser) checkTypeName(x ast.Expr) ast.Expr {
// TODO should provide predicate in AST nodes
switch t := x.(type) {
case *ast.BadExpr: return x;
case *ast.Ident: return x;
case *ast.ParenExpr: p.makeTypeName(t.X); return x; // TODO should (TypeName) be illegal?
case *ast.SelectorExpr: p.makeTypeName(t.X); return x;
case *ast.BadExpr:
case *ast.Ident:
case *ast.ParenExpr: p.checkTypeName(t.X); // TODO should (TypeName) be illegal?
case *ast.SelectorExpr: p.checkTypeName(t.X);
default:
// all other nodes are not type names
p.error_expected(x.Pos(), "type name");
x = &ast.BadExpr{x.Pos()};
}
// all other nodes are not type names
p.error_expected(x.Pos(), "type name");
return &ast.BadExpr{x.Pos()};
return x;
}
// makeCompositeLitType makes sure x is a legal composite literal type.
func (p *parser) makeCompositeLitType(x ast.Expr) ast.Expr {
// checkCompositeLitType checks that x is a legal composite literal type.
func (p *parser) checkCompositeLitType(x ast.Expr) ast.Expr {
// TODO should provide predicate in AST nodes
switch t := x.(type) {
case *ast.BadExpr: return x;
case *ast.Ident: return x;
case *ast.ParenExpr: p.makeCompositeLitType(t.X); return x;
case *ast.SelectorExpr: p.makeTypeName(t.X); return x;
case *ast.ParenExpr: p.checkCompositeLitType(t.X);
case *ast.SelectorExpr: p.checkTypeName(t.X);
case *ast.ArrayType: return x;
case *ast.SliceType: return x;
case *ast.StructType: return x;
case *ast.MapType: return x;
default:
// all other nodes are not legal composite literal types
p.error_expected(x.Pos(), "composite literal type");
x = &ast.BadExpr{x.Pos()};
}
// all other nodes are not legal composite literal types
p.error_expected(x.Pos(), "composite literal type");
return &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).
//
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
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 {
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 {
x := p.parseOperand();
for {
switch p.tok {
case token.PERIOD: x = p.parseSelectorOrTypeAssertion(p.makeExpr(x));
case token.LBRACK: x = p.parseIndexOrSlice(p.makeExpr(x));
case token.LPAREN: x = p.parseCallOrConversion(p.makeExprOrType(x));
case token.PERIOD: x = p.parseSelectorOrTypeAssertion(p.checkExpr(x));
case token.LBRACK: x = p.parseIndexOrSlice(p.checkExpr(x));
case token.LPAREN: x = p.parseCallOrConversion(p.checkExprOrType(x));
case token.LBRACE:
if p.expr_lev >= 0 {
x = p.parseCompositeLit(p.makeCompositeLitType(x));
x = p.parseCompositeLit(p.checkCompositeLitType(x));
} else {
return p.makeExprOrType(x);
return p.checkExprOrType(x);
}
default:
return p.makeExprOrType(x);
return p.checkExprOrType(x);
}
}
......@@ -1169,14 +1185,14 @@ func (p *parser) parseUnaryExpr() ast.Expr {
pos, op := p.pos, p.tok;
p.next();
x := p.parseUnaryExpr();
return &ast.UnaryExpr{pos, op, p.makeExpr(x)};
return &ast.UnaryExpr{pos, op, p.checkExpr(x)};
case token.MUL:
// unary "*" expression or pointer type
pos := p.pos;
p.next();
x := p.parseUnaryExpr();
return &ast.StarExpr{pos, p.makeExprOrType(x)};
return &ast.StarExpr{pos, p.checkExprOrType(x)};
}
return p.parsePrimaryExpr();
......@@ -1194,7 +1210,7 @@ func (p *parser) parseBinaryExpr(prec1 int) ast.Expr {
pos, op := p.pos, p.tok;
p.next();
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 {
// Statements
func (p *parser) parseSimpleStmt() ast.Stmt {
func (p *parser) parseSimpleStmt(label_ok bool) ast.Stmt {
if p.trace {
defer un(trace(p, "SimpleStmt"));
}
......@@ -1225,8 +1241,8 @@ func (p *parser) parseSimpleStmt() ast.Stmt {
switch p.tok {
case token.COLON:
// labeled statement
p.expect(token.COLON);
if len(x) == 1 {
p.next();
if label_ok && len(x) == 1 {
if label, is_ident := x[0].(*ast.Ident); is_ident {
return &ast.LabeledStmt{label, p.parseStatement()};
}
......@@ -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 {
return nil;
}
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");
return &ast.BadExpr{s.Pos()};
......@@ -1362,18 +1378,18 @@ func (p *parser) parseControlClause(isForStmt bool) (s1, s2, s3 ast.Stmt) {
p.expr_lev = -1;
if p.tok != token.SEMICOLON {
s1 = p.parseSimpleStmt();
s1 = p.parseSimpleStmt(false);
}
if p.tok == token.SEMICOLON {
p.next();
if p.tok != token.LBRACE && p.tok != token.SEMICOLON {
s2 = p.parseSimpleStmt();
s2 = p.parseSimpleStmt(false);
}
if isForStmt {
// for statements have a 3rd section
p.expect(token.SEMICOLON);
if p.tok != token.LBRACE {
s3 = p.parseSimpleStmt();
s3 = p.parseSimpleStmt(false);
}
}
} else {
......@@ -1401,7 +1417,7 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
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 {
rbrace := p.expect(token.RBRACE);
p.opt_semi = true;
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
......@@ -1585,7 +1601,7 @@ func (p *parser) parseForStmt() ast.Stmt {
}
} else {
// 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
......@@ -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.LBRACK, token.STRUCT, // composite type
token.MUL, token.AND, token.ARROW: // unary operators
return p.parseSimpleStmt();
return p.parseSimpleStmt(true);
case token.GO:
return p.parseGoStmt();
case token.DEFER:
......@@ -1778,7 +1794,7 @@ func (p *parser) parseReceiver() *ast.Field {
if ptr, is_ptr := base.(*ast.StarExpr); is_ptr {
base = ptr.X;
}
p.makeTypeName(base);
p.checkTypeName(base);
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