From 8f628f4955a7b2a70ac7fbdcdf7225cf566d1000 Mon Sep 17 00:00:00 2001
From: Robert Griesemer
Date: Tue, 31 Mar 2009 16:53:58 -0700
Subject: [PATCH] daily snapshot: - adjustments to match new ast/parser
interface - removed printer.go; functionality now in astprinter.go and
docprinter.go (more cleanups pending) - enabled new doc printing in gds
(lots of fine tuning missing, but pieces falling into place; e.g. methods
associated with types. Consts, Vars, to come. Collection of all files
belonging to a package to come)
R=r
OCL=26970
CL=26972
---
usr/gri/pretty/Makefile | 10 +-
usr/gri/pretty/astprinter.go | 213 +---
usr/gri/pretty/compilation.go | 2 +-
usr/gri/pretty/docprinter.go | 256 ++++-
usr/gri/pretty/gds.go | 44 +-
usr/gri/pretty/parser.go | 1968 ---------------------------------
usr/gri/pretty/pretty.go | 34 +-
usr/gri/pretty/printer.go | 1413 -----------------------
usr/gri/pretty/template.html | 12 +-
usr/gri/pretty/typechecker.go | 4 +-
10 files changed, 336 insertions(+), 3620 deletions(-)
delete mode 100644 usr/gri/pretty/parser.go
delete mode 100644 usr/gri/pretty/printer.go
diff --git a/usr/gri/pretty/Makefile b/usr/gri/pretty/Makefile
index 71754ba215a..fae4d97d07e 100644
--- a/usr/gri/pretty/Makefile
+++ b/usr/gri/pretty/Makefile
@@ -28,11 +28,11 @@ install: pretty
clean:
rm -f pretty *.6 *.a *~
-gds.6: utils.6 platform.6 compilation.6 printer.6 docprinter.6 astprinter.6
+gds.6: utils.6 platform.6 compilation.6 docprinter.6
-pretty.6: platform.6 printer.6 compilation.6
+pretty.6: platform.6 ast.6 astprinter.6 compilation.6
-compilation.6: platform.6 parser.6 ast.6 typechecker.6
+compilation.6: platform.6 ast.6 typechecker.6
typechecker.6: ast.6
@@ -40,12 +40,8 @@ ast.6: symboltable.6
symboltable.6:
-parser.6: ast.6 symboltable.6
-
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
diff --git a/usr/gri/pretty/astprinter.go b/usr/gri/pretty/astprinter.go
index 981b70efe45..ddc5e52d27f 100644
--- a/usr/gri/pretty/astprinter.go
+++ b/usr/gri/pretty/astprinter.go
@@ -5,7 +5,6 @@
package astPrinter
import (
- "os";
"io";
"vector";
"tabwriter";
@@ -35,9 +34,8 @@ var (
)
-// When we don't have a position use nopos.
-// TODO make sure we always have a position.
-var nopos token.Position;
+// When we don't have a position use noPos.
+var noPos token.Position;
// ----------------------------------------------------------------------------
@@ -448,7 +446,7 @@ func (P *Printer) Idents(list []*ast.Ident, full bool) int {
n := 0;
for i, x := range list {
if n > 0 {
- P.Token(nopos, token.COMMA);
+ P.Token(noPos, token.COMMA);
P.separator = blank;
P.state = inside_list;
}
@@ -464,7 +462,7 @@ func (P *Printer) Idents(list []*ast.Ident, full bool) int {
func (P *Printer) Exprs(list []ast.Expr) {
for i, x := range list {
if i > 0 {
- P.Token(nopos, token.COMMA);
+ P.Token(noPos, token.COMMA);
P.separator = blank;
P.state = inside_list;
}
@@ -474,7 +472,7 @@ func (P *Printer) Exprs(list []ast.Expr) {
func (P *Printer) Parameters(list []*ast.Field) {
- P.Token(nopos, token.LPAREN);
+ P.Token(noPos, token.LPAREN);
if len(list) > 0 {
for i, par := range list {
if i > 0 {
@@ -487,7 +485,7 @@ func (P *Printer) Parameters(list []*ast.Field) {
P.Expr(par.Type);
}
}
- P.Token(nopos, token.RPAREN);
+ P.Token(noPos, token.RPAREN);
}
@@ -502,7 +500,7 @@ func (P *Printer) Signature(params, result []*ast.Field) {
// single anonymous result
// => no parentheses needed unless it's a function type
fld := result[0];
- if dummy, is_ftyp := fld.Type.(*ast.FunctionType); !is_ftyp {
+ if dummy, is_ftyp := fld.Type.(*ast.FuncType); !is_ftyp {
P.Expr(fld.Type);
return;
}
@@ -533,7 +531,7 @@ func (P *Printer) Fields(lbrace token.Position, list []*ast.Field, rbrace token.
if n > 0 || len(fld.Names) == 0 {
// at least one identifier or anonymous field
if is_interface {
- if ftyp, is_ftyp := fld.Type.(*ast.FunctionType); is_ftyp {
+ if ftyp, is_ftyp := fld.Type.(*ast.FuncType); is_ftyp {
P.Signature(ftyp.Params, ftyp.Results);
} else {
P.Expr(fld.Type);
@@ -564,7 +562,7 @@ func (P *Printer) Stmt(s ast.Stmt)
func (P *Printer) DoBadExpr(x *ast.BadExpr) {
- P.String(nopos, "BadExpr");
+ P.String(noPos, "BadExpr");
}
@@ -576,7 +574,7 @@ func (P *Printer) DoIdent(x *ast.Ident) {
func (P *Printer) DoBinaryExpr(x *ast.BinaryExpr) {
prec := x.Op.Precedence();
if prec < P.prec {
- P.Token(nopos, token.LPAREN);
+ P.Token(noPos, token.LPAREN);
}
P.Expr1(x.X, prec);
P.separator = blank;
@@ -584,7 +582,7 @@ func (P *Printer) DoBinaryExpr(x *ast.BinaryExpr) {
P.separator = blank;
P.Expr1(x.Y, prec);
if prec < P.prec {
- P.Token(nopos, token.RPAREN);
+ P.Token(noPos, token.RPAREN);
}
}
@@ -607,7 +605,7 @@ func (P *Printer) DoStarExpr(x *ast.StarExpr) {
func (P *Printer) DoUnaryExpr(x *ast.UnaryExpr) {
prec := token.UnaryPrec;
if prec < P.prec {
- P.Token(nopos, token.LPAREN);
+ P.Token(noPos, token.LPAREN);
}
P.Token(x.Pos(), x.Op);
if x.Op == token.RANGE {
@@ -615,7 +613,7 @@ func (P *Printer) DoUnaryExpr(x *ast.UnaryExpr) {
}
P.Expr1(x.X, prec);
if prec < P.prec {
- P.Token(nopos, token.RPAREN);
+ P.Token(noPos, token.RPAREN);
}
}
@@ -654,10 +652,10 @@ func (P *Printer) DoStringList(x *ast.StringList) {
}
-func (P *Printer) DoFunctionType(x *ast.FunctionType)
+func (P *Printer) DoFuncType(x *ast.FuncType)
-func (P *Printer) DoFunctionLit(x *ast.FunctionLit) {
- P.DoFunctionType(x.Type);
+func (P *Printer) DoFuncLit(x *ast.FuncLit) {
+ P.DoFuncType(x.Type);
P.separator = blank;
P.Stmt(x.Body);
P.newlines = 0;
@@ -673,35 +671,35 @@ func (P *Printer) DoParenExpr(x *ast.ParenExpr) {
func (P *Printer) DoSelectorExpr(x *ast.SelectorExpr) {
P.Expr1(x.X, token.HighestPrec);
- P.Token(nopos, token.PERIOD);
+ P.Token(noPos, token.PERIOD);
P.Expr1(x.Sel, token.HighestPrec);
}
func (P *Printer) DoTypeAssertExpr(x *ast.TypeAssertExpr) {
P.Expr1(x.X, token.HighestPrec);
- P.Token(nopos, token.PERIOD);
- P.Token(nopos, token.LPAREN);
+ P.Token(noPos, token.PERIOD);
+ P.Token(noPos, token.LPAREN);
P.Expr(x.Type);
- P.Token(nopos, token.RPAREN);
+ P.Token(noPos, token.RPAREN);
}
func (P *Printer) DoIndexExpr(x *ast.IndexExpr) {
P.Expr1(x.X, token.HighestPrec);
- P.Token(nopos, token.LBRACK);
+ P.Token(noPos, token.LBRACK);
P.Expr(x.Index);
- P.Token(nopos, token.RBRACK);
+ P.Token(noPos, token.RBRACK);
}
func (P *Printer) DoSliceExpr(x *ast.SliceExpr) {
P.Expr1(x.X, token.HighestPrec);
- P.Token(nopos, token.LBRACK);
+ P.Token(noPos, token.LBRACK);
P.Expr(x.Begin);
- P.Token(nopos, token.COLON);
+ P.Token(noPos, token.COLON);
P.Expr(x.End);
- P.Token(nopos, token.RBRACK);
+ P.Token(noPos, token.RBRACK);
}
@@ -729,14 +727,14 @@ func (P *Printer) DoEllipsis(x *ast.Ellipsis) {
func (P *Printer) DoArrayType(x *ast.ArrayType) {
P.Token(x.Pos(), token.LBRACK);
P.Expr(x.Len);
- P.Token(nopos, token.RBRACK);
+ P.Token(noPos, token.RBRACK);
P.Expr(x.Elt);
}
func (P *Printer) DoSliceType(x *ast.SliceType) {
P.Token(x.Pos(), token.LBRACK);
- P.Token(nopos, token.RBRACK);
+ P.Token(noPos, token.RBRACK);
P.Expr(x.Elt);
}
@@ -749,7 +747,7 @@ func (P *Printer) DoStructType(x *ast.StructType) {
}
-func (P *Printer) DoFunctionType(x *ast.FunctionType) {
+func (P *Printer) DoFuncType(x *ast.FuncType) {
P.Token(x.Pos(), token.FUNC);
P.Signature(x.Params, x.Results);
}
@@ -766,24 +764,24 @@ func (P *Printer) DoInterfaceType(x *ast.InterfaceType) {
func (P *Printer) DoMapType(x *ast.MapType) {
P.Token(x.Pos(), token.MAP);
P.separator = blank;
- P.Token(nopos, token.LBRACK);
+ P.Token(noPos, token.LBRACK);
P.Expr(x.Key);
- P.Token(nopos, token.RBRACK);
+ P.Token(noPos, token.RBRACK);
P.Expr(x.Value);
}
-func (P *Printer) DoChannelType(x *ast.ChannelType) {
+func (P *Printer) DoChanType(x *ast.ChanType) {
switch x.Dir {
case ast.SEND | ast.RECV:
P.Token(x.Pos(), token.CHAN);
case ast.RECV:
P.Token(x.Pos(), token.ARROW);
- P.Token(nopos, token.CHAN);
+ P.Token(noPos, token.CHAN);
case ast.SEND:
P.Token(x.Pos(), token.CHAN);
P.separator = blank;
- P.Token(nopos, token.ARROW);
+ P.Token(noPos, token.ARROW);
}
P.separator = blank;
P.Expr(x.Value);
@@ -835,7 +833,7 @@ func (P *Printer) DoEmptyStmt(s *ast.EmptyStmt) {
func (P *Printer) DoLabeledStmt(s *ast.LabeledStmt) {
P.indentation--;
P.Expr(s.Label);
- P.Token(nopos, token.COLON);
+ P.Token(noPos, token.COLON);
P.indentation++;
// TODO be more clever if s.Stmt is a labeled stat as well
P.separator = tab;
@@ -850,7 +848,7 @@ func (P *Printer) DoExprStmt(s *ast.ExprStmt) {
func (P *Printer) DoIncDecStmt(s *ast.IncDecStmt) {
P.Expr(s.X);
- P.Token(nopos, s.Tok);
+ P.Token(noPos, s.Tok);
}
@@ -931,7 +929,7 @@ func (P *Printer) Block(list []ast.Stmt, indent bool) {
P.Token(b.Rbrace, token.RBRACE);
P.opt_semi = true;
} else {
- P.String(nopos, ""); // process closing_scope state transition!
+ P.String(noPos, ""); // process closing_scope state transition!
}
}
*/
@@ -964,14 +962,14 @@ func (P *Printer) ControlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po
P.Stmt(init);
P.separator = none;
}
- P.Token(nopos, token.SEMICOLON);
+ P.Token(noPos, token.SEMICOLON);
P.separator = blank;
if expr != nil {
P.Expr(expr);
P.separator = none;
}
if isForStmt {
- P.Token(nopos, token.SEMICOLON);
+ P.Token(noPos, token.SEMICOLON);
P.separator = blank;
if post != nil {
P.Stmt(post);
@@ -988,7 +986,7 @@ func (P *Printer) DoIfStmt(s *ast.IfStmt) {
P.Stmt(s.Body);
if s.Else != nil {
P.separator = blank;
- P.Token(nopos, token.ELSE);
+ P.Token(noPos, token.ELSE);
P.separator = blank;
P.Stmt(s.Else);
}
@@ -1040,7 +1038,7 @@ func (P *Printer) DoTypeSwitchStmt(s *ast.TypeSwitchStmt) {
if s.Init != nil {
P.Stmt(s.Init);
P.separator = none;
- P.Token(nopos, token.SEMICOLON);
+ P.Token(noPos, token.SEMICOLON);
}
P.separator = blank;
P.Stmt(s.Assign);
@@ -1056,7 +1054,7 @@ func (P *Printer) DoCommClause(s *ast.CommClause) {
if s.Lhs != nil {
P.Expr(s.Lhs);
P.separator = blank;
- P.Token(nopos, s.Tok);
+ P.Token(noPos, s.Tok);
P.separator = blank;
}
P.Expr(s.Rhs);
@@ -1090,7 +1088,7 @@ func (P *Printer) DoRangeStmt(s *ast.RangeStmt) {
P.separator = blank;
P.Expr(s.Key);
if s.Value != nil {
- P.Token(nopos, token.COMMA);
+ P.Token(noPos, token.COMMA);
P.separator = blank;
P.state = inside_list;
P.Expr(s.Value);
@@ -1098,7 +1096,7 @@ func (P *Printer) DoRangeStmt(s *ast.RangeStmt) {
P.separator = blank;
P.Token(s.TokPos, s.Tok);
P.separator = blank;
- P.Token(nopos, token.RANGE);
+ P.Token(noPos, token.RANGE);
P.separator = blank;
P.Expr(s.X);
P.separator = blank;
@@ -1146,7 +1144,7 @@ func (P *Printer) DoConstDecl(d *ast.ConstDecl) {
}
if d.Values != nil {
P.separator = tab;
- P.Token(nopos, token.ASSIGN);
+ P.Token(noPos, token.ASSIGN);
P.separator = blank;
P.Exprs(d.Values);
}
@@ -1179,7 +1177,7 @@ func (P *Printer) DoVarDecl(d *ast.VarDecl) {
}
if d.Values != nil {
P.separator = tab;
- P.Token(nopos, token.ASSIGN);
+ P.Token(noPos, token.ASSIGN);
P.separator = blank;
P.Exprs(d.Values);
}
@@ -1192,13 +1190,13 @@ func (P *Printer) DoFuncDecl(d *ast.FuncDecl) {
P.separator = blank;
if recv := d.Recv; recv != nil {
// method: print receiver
- P.Token(nopos, token.LPAREN);
+ P.Token(noPos, token.LPAREN);
if len(recv.Names) > 0 {
P.Expr(recv.Names[0]);
P.separator = blank;
}
P.Expr(recv.Type);
- P.Token(nopos, token.RPAREN);
+ P.Token(noPos, token.RPAREN);
P.separator = blank;
}
P.Expr(d.Name);
@@ -1217,7 +1215,7 @@ func (P *Printer) DoDeclList(d *ast.DeclList) {
// group of parenthesized declarations
P.state = opening_scope;
- P.Token(nopos, token.LPAREN);
+ P.Token(noPos, token.LPAREN);
if len(d.List) > 0 {
P.newlines = 1;
for i := 0; i < len(d.List); i++ {
@@ -1240,123 +1238,10 @@ func (P *Printer) Decl(d ast.Decl) {
}
-// ----------------------------------------------------------------------------
-// Package interface
-
-func stripWhiteSpace(s []byte) []byte {
- i, j := 0, len(s);
- for i < len(s) && s[i] <= ' ' {
- 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.Comments) {
- in_paragraph := false;
- for i, c := range comment {
- s := cleanComment(c.Text);
- if len(s) > 0 {
- if !in_paragraph {
- P.Printf("\n");
- in_paragraph = true;
- }
- P.Printf("%s\n", P.htmlEscape(untabify(string(s))));
- } else {
- if in_paragraph {
- P.Printf("
\n");
- in_paragraph = false;
- }
- }
- }
- if in_paragraph {
- P.Printf("
\n");
- }
-}
-
-
-func (P *Printer) Interface(p *ast.Package) {
- P.full = false;
- for i := 0; i < len(p.Decls); i++ {
- switch d := p.Decls[i].(type) {
- case *ast.ConstDecl:
- if hasExportedNames(d.Names) {
- P.Printf("Constants
\n");
- P.Printf("");
- P.DoConstDecl(d);
- P.String(nopos, "");
- P.Printf("
\n");
- if d.Doc != nil {
- P.printComment(d.Doc);
- }
- }
-
- case *ast.TypeDecl:
- if isExported(d.Name) {
- P.Printf("type %s
\n", d.Name.Lit);
- P.Printf("");
- P.DoTypeDecl(d);
- P.String(nopos, "");
- P.Printf("
\n");
- if d.Doc != nil {
- P.printComment(d.Doc);
- }
- }
-
- case *ast.VarDecl:
- if hasExportedNames(d.Names) {
- P.Printf("Variables
\n");
- P.Printf("");
- P.DoVarDecl(d);
- P.String(nopos, "");
- P.Printf("
\n");
- if d.Doc != nil {
- P.printComment(d.Doc);
- }
- }
-
- case *ast.FuncDecl:
- if isExported(d.Name) {
- if d.Recv != nil {
- P.Printf("func (");
- P.Expr(d.Recv.Type);
- P.Printf(") %s
\n", d.Name.Lit);
- } else {
- P.Printf("func %s
\n", d.Name.Lit);
- }
- P.Printf("");
- P.DoFuncDecl(d);
- P.String(nopos, "");
- P.Printf("
\n");
- if d.Doc != nil {
- P.printComment(d.Doc);
- }
- }
-
- case *ast.DeclList:
-
- }
- }
-}
-
-
// ----------------------------------------------------------------------------
// Program
-func (P *Printer) Program(p *ast.Package) {
+func (P *Printer) DoProgram(p *ast.Program) {
P.full = true;
P.Token(p.Pos(), token.PACKAGE);
P.separator = blank;
diff --git a/usr/gri/pretty/compilation.go b/usr/gri/pretty/compilation.go
index b6b95f30bcc..7dd2bccb5b4 100644
--- a/usr/gri/pretty/compilation.go
+++ b/usr/gri/pretty/compilation.go
@@ -82,7 +82,7 @@ func (h *errorHandler) Error(pos token.Position, msg string) {
}
-func Compile(filename string, flags *Flags) (*ast.Package, ErrorList) {
+func Compile(filename string, flags *Flags) (*ast.Program, ErrorList) {
src, os_err := os.Open(filename, os.O_RDONLY, 0);
defer src.Close();
if os_err != nil {
diff --git a/usr/gri/pretty/docprinter.go b/usr/gri/pretty/docprinter.go
index 5efef277d37..87449b3db8e 100644
--- a/usr/gri/pretty/docprinter.go
+++ b/usr/gri/pretty/docprinter.go
@@ -40,22 +40,22 @@ func hasExportedNames(names []*ast.Ident) bool {
// ----------------------------------------------------------------------------
type constDoc struct {
- cast *ast.ConstDecl;
+ decl *ast.ConstDecl;
}
type varDoc struct {
- vast *ast.VarDecl;
+ decl *ast.VarDecl;
}
type funcDoc struct {
- fast *ast.FuncDecl;
+ decl *ast.FuncDecl;
}
type typeDoc struct {
- tast *ast.TypeDecl;
+ decl *ast.TypeDecl;
methods map[string] *funcDoc;
}
@@ -74,94 +74,284 @@ type PackageDoc struct {
// 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 (doc *PackageDoc) Init(name string) {
+ doc.name = name;
+ doc.imports = make(map[string] string);
+ doc.consts = make(map[string] *constDoc);
+ doc.types = make(map[string] *typeDoc);
+ doc.vars = make(map[string] *varDoc);
+ doc.funcs = make(map[string] *funcDoc);
}
-func (P *PackageDoc) addDecl(decl ast.Decl) {
+func (doc *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) {
+ // TODO only add if not there already - or ignore?
+ name := string(d.Name.Lit);
+ tdoc := &typeDoc{d, make(map[string] *funcDoc)};
+ doc.types[name] = tdoc;
}
+
case *ast.VarDecl:
if hasExportedNames(d.Names) {
}
+
case *ast.FuncDecl:
if isExported(d.Name) {
if d.Recv != nil {
// method
+ // determine receiver type name
+ var name string;
+ switch t := d.Recv.Type.(type) {
+ case *ast.Ident:
+ name = string(t.Lit);
+ case *ast.StarExpr:
+ // recv must be of the form *name
+ name = string(t.X.(*ast.Ident).Lit)
+ }
+ typ, found := doc.types[name];
+ if found {
+ fdoc := &funcDoc{d};
+ typ.methods[string(d.Name.Lit)] = fdoc;
+ }
+ // otherwise ignore
} else {
// ordinary function
+ fdoc := &funcDoc{d};
+ doc.funcs[string(d.Name.Lit)] = fdoc;
}
}
+
case *ast.DeclList:
for i, decl := range d.List {
- P.addDecl(decl);
+ doc.addDecl(decl);
}
}
}
-// AddPackage adds the AST of a source file belonging to the same
+// AddProgram 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) {
+func (doc *PackageDoc) AddProgram(pak *ast.Program) {
+ if doc.name != string(pak.Name.Lit) {
panic("package names don't match");
}
// add all declarations
for i, decl := range pak.Decls {
- P.addDecl(decl);
+ doc.addDecl(decl);
}
}
-func (P *PackageDoc) printConsts(p *astPrinter.Printer) {
+// ----------------------------------------------------------------------------
+// Printing
+
+func htmlEscape(s string) string {
+ var esc string;
+ for i := 0; i < len(s); i++ {
+ switch s[i] {
+ case '<': esc = "<";
+ case '&': esc = "&";
+ default: continue;
+ }
+ return s[0 : i] + esc + htmlEscape(s[i+1 : len(s)]);
+ }
+ return s;
}
-func (P *PackageDoc) printTypes(p *astPrinter.Printer) {
+// Reduce contiguous sequences of '\t' in a string to a single '\t'.
+func untabify(s string) string {
+ for i := 0; i < len(s); i++ {
+ if s[i] == '\t' {
+ j := i;
+ for j < len(s) && s[j] == '\t' {
+ j++;
+ }
+ if j-i > 1 { // more then one tab
+ return s[0 : i+1] + untabify(s[j : len(s)]);
+ }
+ }
+ }
+ return s;
}
-func (P *PackageDoc) printVars(p *astPrinter.Printer) {
+func stripWhiteSpace(s []byte) []byte {
+ i, j := 0, len(s);
+ for i < len(s) && s[i] <= ' ' {
+ i++;
+ }
+ for j > i && s[j-1] <= ' ' {
+ j--
+ }
+ return s[i : j];
}
-func (P *PackageDoc) printFuncs(p *astPrinter.Printer) {
+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 *PackageDoc) printPackage(p *astPrinter.Printer) {
+func printComment(p *astPrinter.Printer, comment ast.Comments) {
+ in_paragraph := false;
+ for i, c := range comment {
+ s := cleanComment(c.Text);
+ if len(s) > 0 {
+ if !in_paragraph {
+ p.Printf("\n");
+ in_paragraph = true;
+ }
+ p.Printf("%s\n", htmlEscape(untabify(string(s))));
+ } else {
+ if in_paragraph {
+ p.Printf("
\n");
+ in_paragraph = false;
+ }
+ }
+ }
+ if in_paragraph {
+ p.Printf("\n");
+ }
}
+func (c *constDoc) printConsts(p *astPrinter.Printer) {
+}
+
+
+func (f *funcDoc) print(p *astPrinter.Printer) {
+ d := f.decl;
+ if d.Recv != nil {
+ p.Printf("func (");
+ p.Expr(d.Recv.Type);
+ p.Printf(") %s
\n", d.Name.Lit);
+ } else {
+ p.Printf("func %s
\n", d.Name.Lit);
+ }
+ p.Printf("");
+ p.DoFuncDecl(d);
+ p.Printf("
\n");
+ if d.Doc != nil {
+ printComment(p, d.Doc);
+ }
+}
+
+
+func (t *typeDoc) print(p *astPrinter.Printer) {
+ d := t.decl;
+ p.Printf("type %s
\n", string(d.Name.Lit));
+ p.Printf("");
+ p.DoTypeDecl(d);
+ p.Printf("
\n");
+ if d.Doc != nil {
+ printComment(p, d.Doc);
+ }
+
+ // print associated methods, if any
+ for name, m := range t.methods {
+ m.print(p);
+ }
+}
+
+
+func (v *varDoc) print(p *astPrinter.Printer) {
+}
+
+
+/*
+func (P *Printer) Interface(p *ast.Program) {
+ P.full = false;
+ for i := 0; i < len(p.Decls); i++ {
+ switch d := p.Decls[i].(type) {
+ case *ast.ConstDecl:
+ if hasExportedNames(d.Names) {
+ P.Printf("Constants
\n");
+ P.Printf("");
+ P.DoConstDecl(d);
+ P.String(nopos, "");
+ P.Printf("
\n");
+ if d.Doc != nil {
+ P.printComment(d.Doc);
+ }
+ }
+
+ case *ast.VarDecl:
+ if hasExportedNames(d.Names) {
+ P.Printf("Variables
\n");
+ P.Printf("");
+ P.DoVarDecl(d);
+ P.String(nopos, "");
+ P.Printf("
\n");
+ if d.Doc != nil {
+ P.printComment(d.Doc);
+ }
+ }
+
+ case *ast.DeclList:
+
+ }
+ }
+}
+*/
+
+
// 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);
+func (doc *PackageDoc) Print(writer io.Write) {
+ var p astPrinter.Printer;
+ p.Init(writer, nil, true);
- err := templ.Apply(writer, "" : func() { fmt.Fprint(writer, P.name); },
- "PACKAGE_COMMENT-->": func() { },
- "PACKAGE_INTERFACE-->" : func() { },
- "PACKAGE_BODY-->" : func() { },
+ // TODO propagate Apply errors
+ templ.Apply(writer, "" :
+ func() {
+ fmt.Fprint(writer, doc.name);
+ },
+
+ "PROGRAM_HEADER-->":
+ func() {
+ },
+
+ "CONSTANTS-->" :
+ func() {
+ },
+
+ "TYPES-->" :
+ func() {
+ for name, t := range doc.types {
+ p.Printf("
\n");
+ t.print(&p);
+ }
+ },
+
+ "VARIABLES-->" :
+ func() {
+ },
+
+ "FUNCTIONS-->" :
+ func() {
+ for name, f := range doc.funcs {
+ p.Printf("
\n");
+ f.print(&p);
+ }
+ },
});
- if err != nil {
- panic("print error - exiting");
- }
}
diff --git a/usr/gri/pretty/gds.go b/usr/gri/pretty/gds.go
index 3a91a361095..a004ad22304 100644
--- a/usr/gri/pretty/gds.go
+++ b/usr/gri/pretty/gds.go
@@ -17,12 +17,11 @@ import (
"sort";
"log";
"template";
+ "tabwriter";
"utils";
"platform";
"compilation";
- "printer";
- "tabwriter";
"docprinter";
)
@@ -33,9 +32,8 @@ var (
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
+ tabwidth = flag.Int("tabwidth", 4, "tab width");
+ usetabs = flag.Bool("usetabs", false, "align with tabs instead of blanks");
)
@@ -167,29 +165,23 @@ func serveFile(c *http.Conn, filename string) {
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);
+ // 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);
+ // write documentation
+ var doc docPrinter.PackageDoc;
+ doc.Init(string(prog.Name.Lit));
+ doc.AddProgram(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);
+ // flush any pending output
+ err := writer.Flush();
+ if err != nil {
+ panic("print error - exiting");
}
}
diff --git a/usr/gri/pretty/parser.go b/usr/gri/pretty/parser.go
deleted file mode 100644
index e60893abfdb..00000000000
--- a/usr/gri/pretty/parser.go
+++ /dev/null
@@ -1,1968 +0,0 @@
-// 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.
-
-// A parser for Go source text. The input is a stream of lexical tokens
-// provided via the Scanner interface. The output is an abstract syntax
-// tree (AST) representing the Go source. The parser is invoked by calling
-// Parse.
-//
-package parser
-
-import (
- "ast";
- "fmt";
- "io";
- "scanner";
- "token";
- "vector";
-)
-
-
-// An implementation of an ErrorHandler may be provided to the parser.
-// If a syntax error is encountered and a handler was installed, Error
-// is called with a position and an error message. The position points
-// to the beginning of the offending token.
-//
-type ErrorHandler interface {
- Error(pos token.Position, msg string);
-}
-
-
-type interval struct {
- beg, end int;
-}
-
-
-// The parser structure holds the parser's internal state.
-type parser struct {
- scanner scanner.Scanner;
- err ErrorHandler; // nil if no handler installed
- errorCount int;
-
- // Tracing/debugging
- mode uint; // parsing mode
- trace bool; // == (mode & Trace != 0)
- indent uint; // indentation used for tracing output
-
- // Comments
- comments vector.Vector; // list of collected, unassociated comments
- last_doc interval; // last comments interval of consecutive comments
-
- // The next token
- pos token.Position; // token position
- tok token.Token; // one token look-ahead
- lit []byte; // token literal
-
- // Non-syntactic parser control
- opt_semi bool; // true if semicolon separator is optional in statement list
- expr_lev int; // < 0: in control clause, >= 0: in expression
-};
-
-
-// noPos is used when there is no corresponding source position for a token
-var noPos token.Position;
-
-
-// ----------------------------------------------------------------------------
-// Parsing support
-
-func (p *parser) printTrace(a ...) {
- const dots =
- ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
- ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ";
- const n = uint(len(dots));
- fmt.Printf("%5d:%3d: ", p.pos.Line, p.pos.Column);
- i := 2*p.indent;
- for ; i > n; i -= n {
- fmt.Print(dots);
- }
- fmt.Print(dots[0 : i]);
- fmt.Println(a);
-}
-
-
-func trace(p *parser, msg string) *parser {
- p.printTrace(msg, "(");
- p.indent++;
- return p;
-}
-
-
-func un/*trace*/(p *parser) {
- p.indent--;
- p.printTrace(")");
-}
-
-
-func (p *parser) next0() {
- // Because of one-token look-ahead, print the previous token
- // when tracing as it provides a more readable output. The
- // very first token (p.pos.Line == 0) is not initialized (it
- // is token.ILLEGAL), so don't print it .
- if p.trace && p.pos.Line > 0 {
- s := p.tok.String();
- switch {
- case p.tok.IsLiteral():
- p.printTrace(s, string(p.lit));
- case p.tok.IsOperator(), p.tok.IsKeyword():
- p.printTrace("\"" + s + "\"");
- default:
- p.printTrace(s);
- }
- }
-
- p.pos, p.tok, p.lit = p.scanner.Scan();
- p.opt_semi = false;
-}
-
-
-// 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.lit[1] == '*' {
- for i, b := range p.lit {
- if b == '\n' {
- endline++;
- }
- }
- }
- p.comments.Push(&ast.Comment{p.pos, p.lit, endline});
- p.next0();
-
- return endline;
-}
-
-
-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();
- }
- end := p.comments.Len();
- return interval {beg, end};
-}
-
-
-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);
- }
-
- // remove comments from the general list
- p.comments.Cut(doc.beg, doc.end);
-
- return c;
-}
-
-
-func (p *parser) next() {
- p.next0();
- p.last_doc = interval{0, 0};
- for p.tok == token.COMMENT {
- p.last_doc = p.getComments();
- }
-}
-
-
-func (p *parser) error(pos token.Position, msg string) {
- if p.err != nil {
- p.err.Error(pos, msg);
- }
- p.errorCount++;
-}
-
-
-func (p *parser) error_expected(pos token.Position, msg string) {
- msg = "expected " + msg;
- if pos.Offset == p.pos.Offset {
- // the error happened at the current position;
- // make the error message more specific
- msg += ", found '" + p.tok.String() + "'";
- if p.tok.IsLiteral() {
- msg += " " + string(p.lit);
- }
- }
- p.error(pos, msg);
-}
-
-
-func (p *parser) expect(tok token.Token) token.Position {
- pos := p.pos;
- if p.tok != tok {
- p.error_expected(pos, "'" + tok.String() + "'");
- }
- p.next(); // make progress in any case
- return pos;
-}
-
-
-// ----------------------------------------------------------------------------
-// Common productions
-
-func (p *parser) tryType() ast.Expr;
-func (p *parser) parseStringList(x *ast.StringLit) []*ast.StringLit
-func (p *parser) parseExpression() ast.Expr;
-func (p *parser) parseStatement() ast.Stmt;
-func (p *parser) parseDeclaration() ast.Decl;
-
-
-func (p *parser) parseIdent() *ast.Ident {
- if p.tok == token.IDENT {
- x := &ast.Ident{p.pos, p.lit};
- p.next();
- return x;
- }
- p.expect(token.IDENT); // use expect() error handling
- return &ast.Ident{p.pos, [0]byte{}};
-}
-
-
-func (p *parser) parseIdentList(x ast.Expr) []*ast.Ident {
- if p.trace {
- defer un(trace(p, "IdentList"));
- }
-
- list := vector.New(0);
- if x == nil {
- x = p.parseIdent();
- }
- list.Push(x);
- for p.tok == token.COMMA {
- p.next();
- list.Push(p.parseIdent());
- }
-
- // convert vector
- idents := make([]*ast.Ident, list.Len());
- for i := 0; i < list.Len(); i++ {
- idents[i] = list.At(i).(*ast.Ident);
- }
-
- return idents;
-}
-
-
-func (p *parser) parseExpressionList() []ast.Expr {
- if p.trace {
- defer un(trace(p, "ExpressionList"));
- }
-
- list := vector.New(0);
- list.Push(p.parseExpression());
- for p.tok == token.COMMA {
- p.next();
- list.Push(p.parseExpression());
- }
-
- // convert list
- exprs := make([]ast.Expr, list.Len());
- for i := 0; i < list.Len(); i++ {
- exprs[i] = list.At(i).(ast.Expr);
- }
-
- return exprs;
-}
-
-
-// ----------------------------------------------------------------------------
-// Types
-
-func (p *parser) parseType() ast.Expr {
- if p.trace {
- defer un(trace(p, "Type"));
- }
-
- typ := p.tryType();
-
- if typ == nil {
- p.error_expected(p.pos, "type");
- return &ast.BadExpr{p.pos};
- }
-
- return typ;
-}
-
-
-func (p *parser) parseQualifiedIdent() ast.Expr {
- if p.trace {
- defer un(trace(p, "QualifiedIdent"));
- }
-
- var x ast.Expr = p.parseIdent();
- if p.tok == token.PERIOD {
- // first identifier is a package identifier
- p.next();
- sel := p.parseIdent();
- x = &ast.SelectorExpr{x, sel};
- }
- return x;
-}
-
-
-func (p *parser) parseTypeName() ast.Expr {
- if p.trace {
- defer un(trace(p, "TypeName"));
- }
-
- return p.parseQualifiedIdent();
-}
-
-
-func (p *parser) parseArrayOrSliceType(ellipsis_ok bool) ast.Expr {
- if p.trace {
- defer un(trace(p, "ArrayOrSliceType"));
- }
-
- lbrack := p.expect(token.LBRACK);
- var len ast.Expr;
- if ellipsis_ok && p.tok == token.ELLIPSIS {
- len = &ast.Ellipsis{p.pos};
- p.next();
- } else if p.tok != token.RBRACK {
- len = p.parseExpression();
- }
- p.expect(token.RBRACK);
- elt := p.parseType();
-
- if len != nil {
- return &ast.ArrayType{lbrack, len, elt};
- }
-
- return &ast.SliceType{lbrack, elt};
-}
-
-
-func (p *parser) makeIdentList(list *vector.Vector) []*ast.Ident {
- idents := make([]*ast.Ident, list.Len());
- for i := 0; i < list.Len(); i++ {
- ident, is_ident := list.At(i).(*ast.Ident);
- if !is_ident {
- pos := list.At(i).(ast.Expr).Pos();
- p.error_expected(pos, "identifier");
- idents[i] = &ast.Ident{pos, []byte{}};
- }
- idents[i] = ident;
- }
- return idents;
-}
-
-
-func (p *parser) parseFieldDecl() *ast.Field {
- if p.trace {
- defer un(trace(p, "FieldDecl"));
- }
-
- doc := p.getDoc();
-
- // a list of identifiers looks like a list of type names
- list := vector.New(0);
- for {
- // TODO do not allow ()'s here
- list.Push(p.parseType());
- if p.tok == token.COMMA {
- p.next();
- } else {
- break;
- }
- }
-
- // if we had a list of identifiers, it must be followed by a type
- typ := p.tryType();
-
- // optional tag
- var tag []*ast.StringLit;
- if p.tok == token.STRING {
- tag = p.parseStringList(nil);
- }
-
- // analyze case
- var idents []*ast.Ident;
- if typ != nil {
- // IdentifierList Type
- idents = p.makeIdentList(list);
- } else {
- // Type (anonymous field)
- if list.Len() == 1 {
- // TODO check that this looks like a type
- typ = list.At(0).(ast.Expr);
- } else {
- p.error_expected(p.pos, "anonymous field");
- typ = &ast.BadExpr{p.pos};
- }
- }
-
- return &ast.Field{doc, idents, typ, tag};
-}
-
-
-func (p *parser) parseStructType() *ast.StructType {
- if p.trace {
- defer un(trace(p, "StructType"));
- }
-
- pos := p.expect(token.STRUCT);
- var lbrace, rbrace token.Position;
- var fields []*ast.Field;
- if p.tok == token.LBRACE {
- lbrace = p.pos;
- p.next();
-
- list := vector.New(0);
- for p.tok != token.RBRACE && p.tok != token.EOF {
- list.Push(p.parseFieldDecl());
- if p.tok == token.SEMICOLON {
- p.next();
- } else {
- break;
- }
- }
- if p.tok == token.SEMICOLON {
- p.next();
- }
-
- rbrace = p.expect(token.RBRACE);
- p.opt_semi = true;
-
- // convert vector
- fields = make([]*ast.Field, list.Len());
- for i := list.Len() - 1; i >= 0; i-- {
- fields[i] = list.At(i).(*ast.Field);
- }
- }
-
- return &ast.StructType{pos, lbrace, fields, rbrace};
-}
-
-
-func (p *parser) parsePointerType() *ast.StarExpr {
- if p.trace {
- defer un(trace(p, "PointerType"));
- }
-
- star := p.expect(token.MUL);
- base := p.parseType();
-
- return &ast.StarExpr{star, base};
-}
-
-
-func (p *parser) tryParameterType(ellipsis_ok bool) ast.Expr {
- if ellipsis_ok && p.tok == token.ELLIPSIS {
- pos := p.pos;
- p.next();
- if p.tok != token.RPAREN {
- // "..." always must be at the very end of a parameter list
- p.error(pos, "expected type, found '...'");
- }
- return &ast.Ellipsis{pos};
- }
- return p.tryType();
-}
-
-
-func (p *parser) parseParameterType(ellipsis_ok bool) ast.Expr {
- typ := p.tryParameterType(ellipsis_ok);
- if typ == nil {
- p.error_expected(p.pos, "type");
- typ = &ast.BadExpr{p.pos};
- }
- return typ;
-}
-
-
-func (p *parser) parseParameterDecl(ellipsis_ok bool) (*vector.Vector, ast.Expr) {
- if p.trace {
- defer un(trace(p, "ParameterDecl"));
- }
-
- // a list of identifiers looks like a list of type names
- list := vector.New(0);
- for {
- // TODO do not allow ()'s here
- list.Push(p.parseParameterType(ellipsis_ok));
- if p.tok == token.COMMA {
- p.next();
- } else {
- break;
- }
- }
-
- // if we had a list of identifiers, it must be followed by a type
- typ := p.tryParameterType(ellipsis_ok);
-
- return list, typ;
-}
-
-
-func (p *parser) parseParameterList(ellipsis_ok bool) []*ast.Field {
- if p.trace {
- defer un(trace(p, "ParameterList"));
- }
-
- list, typ := p.parseParameterDecl(ellipsis_ok);
- if typ != nil {
- // IdentifierList Type
- idents := p.makeIdentList(list);
- list.Init(0);
- list.Push(&ast.Field{nil, idents, typ, nil});
-
- for p.tok == token.COMMA {
- p.next();
- idents := p.parseIdentList(nil);
- typ := p.parseParameterType(ellipsis_ok);
- list.Push(&ast.Field{nil, idents, typ, nil});
- }
-
- } else {
- // Type { "," Type } (anonymous parameters)
- // convert list of types into list of *Param
- for i := 0; i < list.Len(); i++ {
- list.Set(i, &ast.Field{nil, nil, list.At(i).(ast.Expr), nil});
- }
- }
-
- // convert list
- params := make([]*ast.Field, list.Len());
- for i := 0; i < list.Len(); i++ {
- params[i] = list.At(i).(*ast.Field);
- }
-
- return params;
-}
-
-
-func (p *parser) parseParameters(ellipsis_ok bool) []*ast.Field {
- if p.trace {
- defer un(trace(p, "Parameters"));
- }
-
- var params []*ast.Field;
- p.expect(token.LPAREN);
- if p.tok != token.RPAREN {
- params = p.parseParameterList(ellipsis_ok);
- }
- p.expect(token.RPAREN);
-
- return params;
-}
-
-
-func (p *parser) parseResult() []*ast.Field {
- if p.trace {
- defer un(trace(p, "Result"));
- }
-
- var results []*ast.Field;
- if p.tok == token.LPAREN {
- results = p.parseParameters(false);
- } else if p.tok != token.FUNC {
- typ := p.tryType();
- if typ != nil {
- results = make([]*ast.Field, 1);
- results[0] = &ast.Field{nil, nil, typ, nil};
- }
- }
-
- return results;
-}
-
-
-func (p *parser) parseSignature() (params []*ast.Field, results []*ast.Field) {
- if p.trace {
- defer un(trace(p, "Signature"));
- }
-
- params = p.parseParameters(true);
- results = p.parseResult();
-
- return params, results;
-}
-
-
-func (p *parser) parseFunctionType() *ast.FunctionType {
- if p.trace {
- defer un(trace(p, "FunctionType"));
- }
-
- pos := p.expect(token.FUNC);
- params, results := p.parseSignature();
-
- return &ast.FunctionType{pos, params, results};
-}
-
-
-func (p *parser) parseMethodSpec() *ast.Field {
- if p.trace {
- 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) {
- // methods
- idents = p.parseIdentList(x);
- params, results := p.parseSignature();
- typ = &ast.FunctionType{noPos, params, results};
- } else {
- // embedded interface
- typ = x;
- }
-
- return &ast.Field{doc, idents, typ, nil};
-}
-
-
-func (p *parser) parseInterfaceType() *ast.InterfaceType {
- if p.trace {
- defer un(trace(p, "InterfaceType"));
- }
-
- pos := p.expect(token.INTERFACE);
- var lbrace, rbrace token.Position;
- var methods []*ast.Field;
- if p.tok == token.LBRACE {
- lbrace = p.pos;
- p.next();
-
- list := vector.New(0);
- for p.tok == token.IDENT {
- list.Push(p.parseMethodSpec());
- if p.tok != token.RBRACE {
- p.expect(token.SEMICOLON);
- }
- }
-
- rbrace = p.expect(token.RBRACE);
- p.opt_semi = true;
-
- // convert vector
- methods = make([]*ast.Field, list.Len());
- for i := list.Len() - 1; i >= 0; i-- {
- methods[i] = list.At(i).(*ast.Field);
- }
- }
-
- return &ast.InterfaceType{pos, lbrace, methods, rbrace};
-}
-
-
-func (p *parser) parseMapType() *ast.MapType {
- if p.trace {
- defer un(trace(p, "MapType"));
- }
-
- pos := p.expect(token.MAP);
- p.expect(token.LBRACK);
- key := p.parseType();
- p.expect(token.RBRACK);
- value := p.parseType();
-
- return &ast.MapType{pos, key, value};
-}
-
-
-func (p *parser) parseChannelType() *ast.ChannelType {
- if p.trace {
- defer un(trace(p, "ChannelType"));
- }
-
- pos := p.pos;
- dir := ast.SEND | ast.RECV;
- if p.tok == token.CHAN {
- p.next();
- if p.tok == token.ARROW {
- p.next();
- dir = ast.SEND;
- }
- } else {
- p.expect(token.ARROW);
- p.expect(token.CHAN);
- dir = ast.RECV;
- }
- value := p.parseType();
-
- return &ast.ChannelType{pos, dir, value};
-}
-
-
-func (p *parser) tryRawType(ellipsis_ok bool) ast.Expr {
- switch p.tok {
- case token.IDENT: return p.parseTypeName();
- case token.LBRACK: return p.parseArrayOrSliceType(ellipsis_ok);
- case token.STRUCT: return p.parseStructType();
- case token.MUL: return p.parsePointerType();
- case token.FUNC: return p.parseFunctionType();
- case token.INTERFACE: return p.parseInterfaceType();
- case token.MAP: return p.parseMapType();
- case token.CHAN, token.ARROW: return p.parseChannelType();
- case token.LPAREN:
- lparen := p.pos;
- p.next();
- typ := p.parseType();
- rparen := p.expect(token.RPAREN);
- return &ast.ParenExpr{lparen, typ, rparen};
- }
-
- // no type found
- return nil;
-}
-
-
-func (p *parser) tryType() ast.Expr {
- return p.tryRawType(false);
-}
-
-
-// ----------------------------------------------------------------------------
-// Blocks
-
-func makeStmtList(list *vector.Vector) []ast.Stmt {
- stats := make([]ast.Stmt, list.Len());
- for i := 0; i < list.Len(); i++ {
- stats[i] = list.At(i).(ast.Stmt);
- }
- return stats;
-}
-
-
-func (p *parser) parseStatementList() []ast.Stmt {
- 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 {
- p.expect(token.SEMICOLON);
- expect_semi = false;
- }
- list.Push(p.parseStatement());
- if p.tok == token.SEMICOLON {
- p.next();
- } else if p.opt_semi {
- p.opt_semi = false; // "consume" optional semicolon
- } else {
- expect_semi = true;
- }
- }
-
- return makeStmtList(list);
-}
-
-
-func (p *parser) parseBlockStmt() *ast.BlockStmt {
- if p.trace {
- defer un(trace(p, "BlockStmt"));
- }
-
- lbrace := p.expect(token.LBRACE);
- list := p.parseStatementList();
- rbrace := p.expect(token.RBRACE);
- p.opt_semi = true;
-
- return &ast.BlockStmt{lbrace, list, rbrace};
-}
-
-
-// ----------------------------------------------------------------------------
-// Expressions
-
-func (p *parser) parseStringList(x *ast.StringLit) []*ast.StringLit {
- if p.trace {
- defer un(trace(p, "StringList"));
- }
-
- list := vector.New(0);
- if x != nil {
- list.Push(x);
- }
-
- for p.tok == token.STRING {
- list.Push(&ast.StringLit{p.pos, p.lit});
- p.next();
- }
-
- // convert list
- strings := make([]*ast.StringLit, list.Len());
- for i := 0; i < list.Len(); i++ {
- strings[i] = list.At(i).(*ast.StringLit);
- }
-
- return strings;
-}
-
-
-func (p *parser) parseFunctionLit() ast.Expr {
- if p.trace {
- defer un(trace(p, "FunctionLit"));
- }
-
- typ := p.parseFunctionType();
- p.expr_lev++;
- body := p.parseBlockStmt();
- p.expr_lev--;
-
- return &ast.FunctionLit{typ, body};
-}
-
-
-// parseOperand may return an expression or a raw type (incl. array
-// types of the form [...]T. Callers must verify the result.
-//
-func (p *parser) parseOperand() ast.Expr {
- if p.trace {
- defer un(trace(p, "Operand"));
- }
-
- switch p.tok {
- case token.IDENT:
- return p.parseIdent();
-
- case token.INT:
- x := &ast.IntLit{p.pos, p.lit};
- p.next();
- return x;
-
- case token.FLOAT:
- x := &ast.FloatLit{p.pos, p.lit};
- p.next();
- return x;
-
- case token.CHAR:
- x := &ast.CharLit{p.pos, p.lit};
- p.next();
- return x;
-
- case token.STRING:
- x := &ast.StringLit{p.pos, p.lit};
- p.next();
- if p.tok == token.STRING {
- return &ast.StringList{p.parseStringList(x)};
- }
- return x;
-
- case token.LPAREN:
- lparen := p.pos;
- p.next();
- p.expr_lev++;
- x := p.parseExpression();
- p.expr_lev--;
- rparen := p.expect(token.RPAREN);
- return &ast.ParenExpr{lparen, x, rparen};
-
- case token.FUNC:
- return p.parseFunctionLit();
-
- default:
- t := p.tryRawType(true); // could be type for composite literal
- if t != nil {
- return t;
- }
- }
-
- p.error_expected(p.pos, "operand");
- p.next(); // make progress
- return &ast.BadExpr{p.pos};
-}
-
-
-func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr {
- if p.trace {
- defer un(trace(p, "SelectorOrTypeAssertion"));
- }
-
- p.expect(token.PERIOD);
- if p.tok == token.IDENT {
- // selector
- sel := p.parseIdent();
- return &ast.SelectorExpr{x, sel};
- }
-
- // type assertion
- p.expect(token.LPAREN);
- var typ ast.Expr;
- if p.tok == token.TYPE {
- // special case for type switch
- typ = &ast.Ident{p.pos, p.lit};
- p.next();
- } else {
- typ = p.parseType();
- }
- p.expect(token.RPAREN);
-
- return &ast.TypeAssertExpr{x, typ};
-}
-
-
-func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
- if p.trace {
- defer un(trace(p, "IndexOrSlice"));
- }
-
- p.expect(token.LBRACK);
- p.expr_lev++;
- begin := p.parseExpression();
- var end ast.Expr;
- if p.tok == token.COLON {
- p.next();
- end = p.parseExpression();
- }
- p.expr_lev--;
- p.expect(token.RBRACK);
-
- if end != nil {
- return &ast.SliceExpr{x, begin, end};
- }
-
- return &ast.IndexExpr{x, begin};
-}
-
-
-func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
- if p.trace {
- defer un(trace(p, "CallOrConversion"));
- }
-
- lparen := p.expect(token.LPAREN);
- var args []ast.Expr;
- if p.tok != token.RPAREN {
- args = p.parseExpressionList();
- }
- rparen := p.expect(token.RPAREN);
-
- return &ast.CallExpr{fun, lparen, args, rparen};
-}
-
-
-func (p *parser) parseKeyValueExpr() ast.Expr {
- if p.trace {
- defer un(trace(p, "KeyValueExpr"));
- }
-
- key := p.parseExpression();
-
- if p.tok == token.COLON {
- colon := p.pos;
- p.next();
- value := p.parseExpression();
- return &ast.KeyValueExpr{key, colon, value};
- }
-
- return key;
-}
-
-
-func isPair(x ast.Expr) bool {
- tmp, is_pair := x.(*ast.KeyValueExpr);
- return is_pair;
-}
-
-
-func (p *parser) parseExpressionOrKeyValueList() []ast.Expr {
- if p.trace {
- defer un(trace(p, "ExpressionOrKeyValueList"));
- }
-
- var pairs bool;
- list := vector.New(0);
- for p.tok != token.RBRACE && p.tok != token.EOF {
- x := p.parseKeyValueExpr();
-
- if list.Len() == 0 {
- pairs = isPair(x);
- } else {
- // not the first element - check syntax
- if pairs != isPair(x) {
- p.error_expected(x.Pos(), "all single expressions or all key-value pairs");
- }
- }
-
- list.Push(x);
-
- if p.tok == token.COMMA {
- p.next();
- } else {
- break;
- }
- }
-
- // convert list
- elts := make([]ast.Expr, list.Len());
- for i := 0; i < list.Len(); i++ {
- elts[i] = list.At(i).(ast.Expr);
- }
-
- return elts;
-}
-
-
-func (p *parser) parseCompositeLit(typ ast.Expr) ast.Expr {
- if p.trace {
- defer un(trace(p, "CompositeLit"));
- }
-
- lbrace := p.expect(token.LBRACE);
- var elts []ast.Expr;
- if p.tok != token.RBRACE {
- elts = p.parseExpressionOrKeyValueList();
- }
- rbrace := p.expect(token.RBRACE);
- return &ast.CompositeLit{typ, lbrace, elts, rbrace};
-}
-
-
-// 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.
-
-// 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:
- 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()};
- }
- return x;
-}
-
-
-// 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:
- 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()};
- }
- return x;
-}
-
-
-// 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.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()};
- }
- return x;
-}
-
-
-// checkExprOrType checks that x is an expression or a type
-// (and not a raw type such as [...]T).
-//
-func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
- // TODO should provide predicate in AST nodes
- 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 '...'");
- x = &ast.BadExpr{x.Pos()};
- }
- }
-
- // all other nodes are expressions or types
- return x;
-}
-
-
-func (p *parser) parsePrimaryExpr() ast.Expr {
- if p.trace {
- defer un(trace(p, "PrimaryExpr"));
- }
-
- x := p.parseOperand();
- for {
- switch p.tok {
- 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.checkCompositeLitType(x));
- } else {
- return p.checkExprOrType(x);
- }
- default:
- return p.checkExprOrType(x);
- }
- }
-
- panic(); // unreachable
- return nil;
-}
-
-
-func (p *parser) parseUnaryExpr() ast.Expr {
- if p.trace {
- defer un(trace(p, "UnaryExpr"));
- }
-
- switch p.tok {
- case token.ADD, token.SUB, token.NOT, token.XOR, token.ARROW, token.AND, token.RANGE:
- pos, op := p.pos, p.tok;
- p.next();
- x := p.parseUnaryExpr();
- 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.checkExprOrType(x)};
- }
-
- return p.parsePrimaryExpr();
-}
-
-
-func (p *parser) parseBinaryExpr(prec1 int) ast.Expr {
- if p.trace {
- defer un(trace(p, "BinaryExpr"));
- }
-
- x := p.parseUnaryExpr();
- for prec := p.tok.Precedence(); prec >= prec1; prec-- {
- for p.tok.Precedence() == prec {
- pos, op := p.pos, p.tok;
- p.next();
- y := p.parseBinaryExpr(prec + 1);
- x = &ast.BinaryExpr{p.checkExpr(x), pos, op, p.checkExpr(y)};
- }
- }
-
- return x;
-}
-
-
-func (p *parser) parseExpression() ast.Expr {
- if p.trace {
- defer un(trace(p, "Expression"));
- }
-
- return p.parseBinaryExpr(token.LowestPrec + 1);
-}
-
-
-// ----------------------------------------------------------------------------
-// Statements
-
-
-func (p *parser) parseSimpleStmt(label_ok bool) ast.Stmt {
- if p.trace {
- defer un(trace(p, "SimpleStmt"));
- }
-
- x := p.parseExpressionList();
-
- switch p.tok {
- case token.COLON:
- // labeled statement
- p.next();
- if label_ok && len(x) == 1 {
- if label, is_ident := x[0].(*ast.Ident); is_ident {
- return &ast.LabeledStmt{label, p.parseStatement()};
- }
- }
- p.error(x[0].Pos(), "illegal label declaration");
- return &ast.BadStmt{x[0].Pos()};
-
- case
- token.DEFINE, token.ASSIGN, token.ADD_ASSIGN,
- token.SUB_ASSIGN, token.MUL_ASSIGN, token.QUO_ASSIGN,
- token.REM_ASSIGN, token.AND_ASSIGN, token.OR_ASSIGN,
- token.XOR_ASSIGN, token.SHL_ASSIGN, token.SHR_ASSIGN:
- // assignment statement
- pos, tok := p.pos, p.tok;
- p.next();
- y := p.parseExpressionList();
- if len(x) > 1 && len(y) > 1 && len(x) != len(y) {
- p.error(x[0].Pos(), "arity of lhs doesn't match rhs");
- }
- return &ast.AssignStmt{x, pos, tok, y};
- }
-
- if len(x) > 1 {
- p.error(x[0].Pos(), "only one expression allowed");
- // continue with first expression
- }
-
- if p.tok == token.INC || p.tok == token.DEC {
- // increment or decrement
- s := &ast.IncDecStmt{x[0], p.tok};
- p.next(); // consume "++" or "--"
- return s;
- }
-
- // expression
- return &ast.ExprStmt{x[0]};
-}
-
-
-func (p *parser) parseCallExpr() *ast.CallExpr {
- x := p.parseExpression();
- if call, is_call := x.(*ast.CallExpr); is_call {
- return call;
- }
- p.error_expected(x.Pos(), "function/method call");
- return nil;
-}
-
-
-func (p *parser) parseGoStmt() ast.Stmt {
- if p.trace {
- defer un(trace(p, "GoStmt"));
- }
-
- pos := p.expect(token.GO);
- call := p.parseCallExpr();
- if call != nil {
- return &ast.GoStmt{pos, call};
- }
- return &ast.BadStmt{pos};
-}
-
-
-func (p *parser) parseDeferStmt() ast.Stmt {
- if p.trace {
- defer un(trace(p, "DeferStmt"));
- }
-
- pos := p.expect(token.DEFER);
- call := p.parseCallExpr();
- if call != nil {
- return &ast.DeferStmt{pos, call};
- }
- return &ast.BadStmt{pos};
-}
-
-
-func (p *parser) parseReturnStmt() *ast.ReturnStmt {
- if p.trace {
- defer un(trace(p, "ReturnStmt"));
- }
-
- pos := p.pos;
- p.expect(token.RETURN);
- var x []ast.Expr;
- if p.tok != token.SEMICOLON && p.tok != token.RBRACE {
- x = p.parseExpressionList();
- }
-
- return &ast.ReturnStmt{pos, x};
-}
-
-
-func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
- if p.trace {
- defer un(trace(p, "BranchStmt"));
- }
-
- s := &ast.BranchStmt{p.pos, tok, nil};
- p.expect(tok);
- if tok != token.FALLTHROUGH && p.tok == token.IDENT {
- s.Label = p.parseIdent();
- }
-
- return s;
-}
-
-
-func (p *parser) isExpr(s ast.Stmt) bool {
- if s == nil {
- return true;
- }
- dummy, is_expr := s.(*ast.ExprStmt);
- return is_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 p.checkExpr(es.X);
- }
- p.error(s.Pos(), "expected condition, found simple statement");
- return &ast.BadExpr{s.Pos()};
-}
-
-
-func (p *parser) parseControlClause(isForStmt bool) (s1, s2, s3 ast.Stmt) {
- if p.tok != token.LBRACE {
- prev_lev := p.expr_lev;
- p.expr_lev = -1;
-
- if p.tok != token.SEMICOLON {
- s1 = p.parseSimpleStmt(false);
- }
- if p.tok == token.SEMICOLON {
- p.next();
- if p.tok != token.LBRACE && p.tok != token.SEMICOLON {
- s2 = p.parseSimpleStmt(false);
- }
- if isForStmt {
- // for statements have a 3rd section
- p.expect(token.SEMICOLON);
- if p.tok != token.LBRACE {
- s3 = p.parseSimpleStmt(false);
- }
- }
- } else {
- s1, s2 = nil, s1;
- }
-
- p.expr_lev = prev_lev;
- }
-
- return s1, s2, s3;
-}
-
-
-func (p *parser) parseIfStmt() *ast.IfStmt {
- if p.trace {
- defer un(trace(p, "IfStmt"));
- }
-
- pos := p.expect(token.IF);
- s1, s2, dummy := p.parseControlClause(false);
- body := p.parseBlockStmt();
- var else_ ast.Stmt;
- if p.tok == token.ELSE {
- p.next();
- else_ = p.parseStatement();
- }
-
- return &ast.IfStmt{pos, s1, p.makeExpr(s2), body, else_};
-}
-
-
-func (p *parser) parseCaseClause() *ast.CaseClause {
- if p.trace {
- defer un(trace(p, "CaseClause"));
- }
-
- // SwitchCase
- pos := p.pos;
- var x []ast.Expr;
- if p.tok == token.CASE {
- p.next();
- x = p.parseExpressionList();
- } else {
- p.expect(token.DEFAULT);
- }
-
- colon := p.expect(token.COLON);
- body := p.parseStatementList();
-
- return &ast.CaseClause{pos, x, colon, body};
-}
-
-
-func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
- if p.trace {
- defer un(trace(p, "CaseClause"));
- }
-
- // TypeSwitchCase
- pos := p.pos;
- var typ ast.Expr;
- if p.tok == token.CASE {
- p.next();
- typ = p.parseType();
- } else {
- p.expect(token.DEFAULT);
- }
-
- colon := p.expect(token.COLON);
- body := p.parseStatementList();
-
- return &ast.TypeCaseClause{pos, typ, colon, body};
-}
-
-
-func (p *parser) parseSwitchStmt() ast.Stmt {
- if p.trace {
- defer un(trace(p, "SwitchStmt"));
- }
-
- pos := p.expect(token.SWITCH);
- s1, s2, dummy := p.parseControlClause(false);
-
- 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());
- }
- rbrace := p.expect(token.RBRACE);
- p.opt_semi = true;
- body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace};
- return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body};
- }
-
- // 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.BlockStmt{lbrace, makeStmtList(cases), rbrace};
- return &ast.TypeSwitchStmt{pos, s1, s2, body};
-}
-
-
-func (p *parser) parseCommClause() *ast.CommClause {
- if p.trace {
- defer un(trace(p, "CommClause"));
- }
-
- // CommCase
- pos := p.pos;
- var tok token.Token;
- var lhs, rhs ast.Expr;
- if p.tok == token.CASE {
- p.next();
- if p.tok == token.ARROW {
- // RecvExpr without assignment
- rhs = p.parseExpression();
- } else {
- // SendExpr or RecvExpr
- rhs = p.parseExpression();
- if p.tok == token.ASSIGN || p.tok == token.DEFINE {
- // RecvExpr with assignment
- tok = p.tok;
- p.next();
- lhs = rhs;
- if p.tok == token.ARROW {
- rhs = p.parseExpression();
- } else {
- p.expect(token.ARROW); // use expect() error handling
- }
- }
- // else SendExpr
- }
- } else {
- p.expect(token.DEFAULT);
- }
-
- colon := p.expect(token.COLON);
- body := p.parseStatementList();
-
- return &ast.CommClause{pos, tok, lhs, rhs, colon, body};
-}
-
-
-func (p *parser) parseSelectStmt() *ast.SelectStmt {
- if p.trace {
- defer un(trace(p, "SelectStmt"));
- }
-
- 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());
- }
- rbrace := p.expect(token.RBRACE);
- p.opt_semi = true;
- body := &ast.BlockStmt{lbrace, makeStmtList(cases), rbrace};
-
- return &ast.SelectStmt{pos, body};
-}
-
-
-func (p *parser) parseForStmt() ast.Stmt {
- if p.trace {
- defer un(trace(p, "ForStmt"));
- }
-
- pos := p.expect(token.FOR);
- s1, s2, s3 := p.parseControlClause(true);
- body := p.parseBlockStmt();
-
- if as, is_as := s2.(*ast.AssignStmt); is_as {
- // possibly a for statement with a range clause; check assignment operator
- if as.Tok != token.ASSIGN && as.Tok != token.DEFINE {
- p.error_expected(as.TokPos, "'=' or ':='");
- return &ast.BadStmt{pos};
- }
- // check lhs
- var key, value ast.Expr;
- switch len(as.Lhs) {
- case 2:
- value = as.Lhs[1];
- fallthrough;
- case 1:
- key = as.Lhs[0];
- default:
- p.error_expected(as.Lhs[0].Pos(), "1 or 2 expressions");
- return &ast.BadStmt{pos};
- }
- // check rhs
- if len(as.Rhs) != 1 {
- p.error_expected(as.Rhs[0].Pos(), "1 expressions");
- return &ast.BadStmt{pos};
- }
- if rhs, is_unary := as.Rhs[0].(*ast.UnaryExpr); is_unary && rhs.Op == token.RANGE {
- // rhs is range expression; check lhs
- return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body}
- } else {
- p.error_expected(s2.Pos(), "range clause");
- return &ast.BadStmt{pos};
- }
- } else {
- // regular for statement
- return &ast.ForStmt{pos, s1, p.makeExpr(s2), s3, body};
- }
-
- panic(); // unreachable
- return nil;
-}
-
-
-func (p *parser) parseStatement() ast.Stmt {
- if p.trace {
- defer un(trace(p, "Statement"));
- }
-
- switch p.tok {
- case token.CONST, token.TYPE, token.VAR:
- return &ast.DeclStmt{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.parseSimpleStmt(true);
- case token.GO:
- return p.parseGoStmt();
- case token.DEFER:
- return p.parseDeferStmt();
- case token.RETURN:
- return p.parseReturnStmt();
- case token.BREAK, token.CONTINUE, token.GOTO, token.FALLTHROUGH:
- return p.parseBranchStmt(p.tok);
- case token.LBRACE:
- return p.parseBlockStmt();
- case token.IF:
- return p.parseIfStmt();
- case token.SWITCH:
- return p.parseSwitchStmt();
- case token.SELECT:
- return p.parseSelectStmt();
- case token.FOR:
- return p.parseForStmt();
- case token.SEMICOLON, token.RBRACE:
- // don't consume the ";", it is the separator following the empty statement
- return &ast.EmptyStmt{p.pos};
- }
-
- // no statement found
- p.error_expected(p.pos, "statement");
- return &ast.BadStmt{p.pos};
-}
-
-
-// ----------------------------------------------------------------------------
-// Declarations
-
-func (p *parser) parseImportSpec(pos token.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.pos, `"import ." not yet handled properly`);
- p.next();
- } else if p.tok == token.IDENT {
- ident = p.parseIdent();
- }
-
- var path []*ast.StringLit;
- if p.tok == token.STRING {
- path = p.parseStringList(nil);
- } else {
- p.expect(token.STRING); // use expect() error handling
- }
-
- return &ast.ImportDecl{doc, pos, ident, path};
-}
-
-
-func (p *parser) parseConstSpec(pos token.Position, doc ast.Comments) *ast.ConstDecl {
- if p.trace {
- defer un(trace(p, "ConstSpec"));
- }
-
- idents := p.parseIdentList(nil);
- typ := p.tryType();
- var values []ast.Expr;
- if typ != nil || p.tok == token.ASSIGN {
- p.expect(token.ASSIGN);
- values = p.parseExpressionList();
- }
-
- return &ast.ConstDecl{doc, pos, idents, typ, values};
-}
-
-
-func (p *parser) parseTypeSpec(pos token.Position, doc ast.Comments) *ast.TypeDecl {
- if p.trace {
- defer un(trace(p, "TypeSpec"));
- }
-
- ident := p.parseIdent();
- typ := p.parseType();
-
- return &ast.TypeDecl{doc, pos, ident, typ};
-}
-
-
-func (p *parser) parseVarSpec(pos token.Position, doc ast.Comments) *ast.VarDecl {
- if p.trace {
- defer un(trace(p, "VarSpec"));
- }
-
- idents := p.parseIdentList(nil);
- typ := p.tryType();
- var values []ast.Expr;
- if typ == nil || p.tok == token.ASSIGN {
- p.expect(token.ASSIGN);
- values = p.parseExpressionList();
- }
-
- return &ast.VarDecl{doc, pos, idents, typ, values};
-}
-
-
-func (p *parser) parseSpec(pos token.Position, doc ast.Comments, keyword int) ast.Decl {
- switch keyword {
- 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);
- }
-
- panic(); // unreachable
- return nil;
-}
-
-
-func (p *parser) parseDecl(keyword int) ast.Decl {
- if p.trace {
- defer un(trace(p, "Decl"));
- }
-
- 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(noPos, nil, keyword));
- if p.tok == token.SEMICOLON {
- p.next();
- } else {
- break;
- }
- }
- rparen := p.expect(token.RPAREN);
- p.opt_semi = true;
-
- // convert vector
- decls := make([]ast.Decl, list.Len());
- for i := 0; i < list.Len(); i++ {
- decls[i] = list.At(i).(ast.Decl);
- }
-
- return &ast.DeclList{doc, pos, keyword, lparen, decls, rparen};
- }
-
- return p.parseSpec(pos, doc, keyword);
-}
-
-
-func (p *parser) parseReceiver() *ast.Field {
- if p.trace {
- defer un(trace(p, "Receiver"));
- }
-
- pos := p.pos;
- par := p.parseParameters(false);
-
- // must have exactly one receiver
- if len(par) != 1 || len(par) == 1 && len(par[0].Names) > 1 {
- p.error_expected(pos, "exactly one receiver");
- return &ast.Field{nil, nil, &ast.BadExpr{noPos}, nil};
- }
-
- recv := par[0];
-
- // recv type must be TypeName or *TypeName
- base := recv.Type;
- if ptr, is_ptr := base.(*ast.StarExpr); is_ptr {
- base = ptr.X;
- }
- p.checkTypeName(base);
-
- return recv;
-}
-
-
-func (p *parser) parseFunctionDecl() *ast.FuncDecl {
- if p.trace {
- defer un(trace(p, "FunctionDecl"));
- }
-
- doc := p.getDoc();
- pos := p.expect(token.FUNC);
-
- var recv *ast.Field;
- if p.tok == token.LPAREN {
- recv = p.parseReceiver();
- }
-
- ident := p.parseIdent();
- params, results := p.parseSignature();
-
- var body *ast.BlockStmt;
- if p.tok == token.LBRACE {
- body = p.parseBlockStmt();
- }
-
- return &ast.FuncDecl{doc, recv, ident, &ast.FunctionType{pos, params, results}, body};
-}
-
-
-func (p *parser) parseDeclaration() ast.Decl {
- if p.trace {
- defer un(trace(p, "Declaration"));
- }
-
- switch p.tok {
- case token.CONST, token.TYPE, token.VAR:
- return p.parseDecl(p.tok);
- case token.FUNC:
- return p.parseFunctionDecl();
- }
-
- pos := p.pos;
- p.error_expected(pos, "declaration");
- p.next(); // make progress
- return &ast.BadDecl{pos};
-}
-
-
-// ----------------------------------------------------------------------------
-// Packages
-
-// The mode parameter to the Parse function is a set of flags (or 0).
-// They control the amount of source code parsed and other optional
-// parser functionality.
-//
-const (
- PackageClauseOnly uint = 1 << iota; // parsing stops after package clause
- ImportsOnly; // parsing stops after import declarations
- ParseComments; // parse comments and add them to AST
- Trace; // print a trace of parsed productions
-)
-
-
-func (p *parser) parsePackage() *ast.Package {
- if p.trace {
- defer un(trace(p, "Program"));
- }
-
- // package clause
- comment := p.getDoc();
- pos := p.expect(token.PACKAGE);
- ident := p.parseIdent();
- if p.tok == token.SEMICOLON {
- // common error
- p.error(p.pos, "extra semicolon");
- p.next();
- }
-
- var decls []ast.Decl;
- if p.mode & PackageClauseOnly == 0 {
- // import decls
- list := vector.New(0);
- for p.tok == token.IMPORT {
- list.Push(p.parseDecl(token.IMPORT));
- if p.tok == token.SEMICOLON {
- p.next();
- }
- }
-
- if p.mode & ImportsOnly == 0 {
- // rest of package body
- for p.tok != token.EOF {
- list.Push(p.parseDeclaration());
- if p.tok == token.SEMICOLON {
- p.next();
- }
- }
- }
-
- // convert declaration list
- decls = make([]ast.Decl, list.Len());
- for i := 0; i < list.Len(); i++ {
- decls[i] = list.At(i).(ast.Decl);
- }
- }
-
- // convert comments list
- comments := make([]*ast.Comment, p.comments.Len());
- for i := 0; i < p.comments.Len(); i++ {
- comments[i] = p.comments.At(i).(*ast.Comment);
- }
-
- return &ast.Package{comment, pos, ident, decls, comments};
-}
-
-
-// ----------------------------------------------------------------------------
-// Parsing of entire programs.
-
-func readSource(src interface{}, err ErrorHandler) []byte {
- errmsg := "could not read input src";
-
- switch s := src.(type) {
- case string:
- return io.StringBytes(s);
- case []byte:
- return s;
- case *io.ByteBuffer:
- // is io.Read, but src is already available in []byte form
- if s != nil {
- return s.Data();
- }
- case io.Read:
- var buf io.ByteBuffer;
- n, os_err := io.Copy(s, &buf);
- if os_err == nil {
- return buf.Data();
- }
- errmsg = os_err.String();
- }
-
- if err != nil {
- err.Error(noPos, errmsg);
- }
- return nil;
-}
-
-
-// Parse parses a Go program.
-//
-// The program source src may be provided in a variety of formats. At the
-// moment the following types are supported: string, []byte, and io.Read.
-//
-// The ErrorHandler err, if not nil, is invoked if src cannot be read and
-// for each syntax error found. The mode parameter controls the amount of
-// source text parsed and other optional parser functionality.
-//
-// Parse returns an AST and the boolean value true if no errors occured;
-// it returns a partial AST (or nil if the source couldn't be read) and
-// the boolean value false to indicate failure.
-//
-// If syntax errors were found, the AST may only be constructed partially,
-// with ast.BadX nodes representing the fragments of erroneous source code.
-//
-func Parse(src interface{}, err ErrorHandler, mode uint) (*ast.Package, bool) {
- data := readSource(src, err);
-
- // initialize parser state
- var p parser;
- p.scanner.Init(data, err, mode & ParseComments != 0);
- p.err = err;
- p.mode = mode;
- p.trace = mode & Trace != 0; // for convenience (p.trace is used frequently)
- p.comments.Init(0);
- p.next();
-
- // parse program
- prog := p.parsePackage();
- return prog, p.scanner.ErrorCount == 0 && p.errorCount == 0;
-}
diff --git a/usr/gri/pretty/pretty.go b/usr/gri/pretty/pretty.go
index 1f802126777..fe2a03ecb60 100644
--- a/usr/gri/pretty/pretty.go
+++ b/usr/gri/pretty/pretty.go
@@ -7,18 +7,25 @@ package main
import (
"os";
"flag";
- Platform "platform";
- Printer "printer";
- Compilation "compilation";
+ "platform";
+ "compilation";
+ "tabwriter";
+ "ast";
+ "astprinter";
)
var (
flags Compilation.Flags;
silent = flag.Bool("s", false, "silent mode: no pretty print output");
+
+ // layout control
html = flag.Bool("html", false, "generate html");
+ tabwidth = flag.Int("pretty_tabwidth", 4, "tab width");
+ usetabs = flag.Bool("pretty_usetabs", false, "align with tabs instead of blanks");
)
+
func init() {
flag.BoolVar(&flags.Verbose, "v", false, "verbose mode: trace parsing");
flag.BoolVar(&flags.Deps, "d", false, "print dependency information only");
@@ -33,6 +40,25 @@ func usage() {
}
+func print(prog *ast.Program) {
+ // initialize tabwriter for nicely aligned output
+ padchar := byte(' ');
+ if *usetabs {
+ padchar = '\t';
+ }
+ writer := tabwriter.NewWriter(os.Stdout, *tabwidth, 1, padchar, tabwriter.FilterHTML);
+
+ // initialize printer
+ var printer astPrinter.Printer;
+ printer.Init(writer, prog.Comments, *html);
+
+ printer.DoProgram(prog);
+
+ // flush any pending output
+ writer.Flush();
+}
+
+
func main() {
flag.Parse();
@@ -53,7 +79,7 @@ func main() {
sys.Exit(1);
}
if !*silent {
- Printer.Print(os.Stdout, prog, *html);
+ print(prog);
}
}
}
diff --git a/usr/gri/pretty/printer.go b/usr/gri/pretty/printer.go
deleted file mode 100644
index 5595a2b837f..00000000000
--- a/usr/gri/pretty/printer.go
+++ /dev/null
@@ -1,1413 +0,0 @@
-// 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 Printer
-
-import (
- "os";
- "io";
- "vector";
- "tabwriter";
- "flag";
- "fmt";
- "strings";
- "utils";
- "token";
- "scanner";
- "ast";
- "template";
- "utf8";
- "unicode";
- "symboltable";
-)
-
-var (
- debug = flag.Bool("debug", false, "print debugging information");
-
- // layout control
- tabwidth = flag.Int("tabwidth", 8, "tab width");
- usetabs = flag.Bool("usetabs", true, "align with tabs instead of blanks");
- newlines = flag.Bool("newlines", false, "respect newlines in source");
- maxnewlines = flag.Int("maxnewlines", 3, "max. number of consecutive newlines");
-
- // formatting control
- comments = flag.Bool("comments", true, "print comments");
- optsemicolons = flag.Bool("optsemicolons", false, "print optional semicolons");
-)
-
-
-// When we don't have a position use nopos.
-// TODO make sure we always have a position.
-var nopos token.Position;
-
-
-// ----------------------------------------------------------------------------
-// Elementary support
-
-func unimplemented() {
- panic("unimplemented");
-}
-
-
-func unreachable() {
- panic("unreachable");
-}
-
-
-func assert(pred bool) {
- if !pred {
- panic("assertion failed");
- }
-}
-
-
-// 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;
-}
-
-
-// ----------------------------------------------------------------------------
-// Printer
-
-// Separators - printed in a delayed fashion, depending on context.
-const (
- none = iota;
- blank;
- tab;
- comma;
- semicolon;
-)
-
-
-// Semantic states - control formatting.
-const (
- normal = iota;
- opening_scope; // controls indentation, scope level
- closing_scope; // controls indentation, scope level
- inside_list; // controls extra line breaks
-)
-
-
-type Printer struct {
- // output
- text io.Write;
-
- // formatting control
- html bool;
- full bool; // if false, print interface only; print all otherwise
-
- // comments
- comments []*ast.Comment; // the list of unassociated comments
- cindex int; // the current comment group index
- cpos token.Position; // the position of the next comment group
-
- // current state
- lastpos token.Position; // position after last string
- level int; // scope level
- indentation int; // indentation level (may be different from scope level)
-
- // formatting parameters
- opt_semi bool; // // true if semicolon separator is optional in statement list
- separator int; // pending separator
- newlines int; // pending newlines
-
- // semantic state
- state int; // current semantic state
- laststate int; // state for last string
-
- // expression precedence
- prec int;
-}
-
-
-func (P *Printer) hasComment(pos token.Position) bool {
- return *comments && P.cpos.Offset < pos.Offset;
-}
-
-
-func (P *Printer) nextComments() {
- P.cindex++;
- if P.comments != nil && P.cindex < len(P.comments) && P.comments[P.cindex] != nil {
- P.cpos = P.comments[P.cindex].Pos();
- } else {
- P.cpos = token.Position{1<<30, 1<<30, 1}; // infinite
- }
-}
-
-
-func (P *Printer) Init(text io.Write, comments []*ast.Comment, html bool) {
- // writers
- P.text = text;
-
- // formatting control
- P.html = html;
-
- // comments
- P.comments = comments;
- P.cindex = -1;
- P.nextComments();
-
- // formatting parameters & semantic state initialized correctly by default
-
- // expression precedence
- P.prec = token.LowestPrec;
-}
-
-
-// ----------------------------------------------------------------------------
-// Printing support
-
-func (P *Printer) htmlEscape(s string) string {
- if P.html {
- var esc string;
- for i := 0; i < len(s); i++ {
- switch s[i] {
- case '<': esc = "<";
- case '&': esc = "&";
- default: continue;
- }
- return s[0 : i] + esc + P.htmlEscape(s[i+1 : len(s)]);
- }
- }
- return s;
-}
-
-
-// Reduce contiguous sequences of '\t' in a string to a single '\t'.
-func untabify(s string) string {
- for i := 0; i < len(s); i++ {
- if s[i] == '\t' {
- j := i;
- for j < len(s) && s[j] == '\t' {
- j++;
- }
- if j-i > 1 { // more then one tab
- return s[0 : i+1] + untabify(s[j : len(s)]);
- }
- }
- }
- return s;
-}
-
-
-func (P *Printer) Printf(format string, s ...) {
- n, err := fmt.Fprintf(P.text, format, s);
- if err != nil {
- panic("print error - exiting");
- }
-}
-
-
-func (P *Printer) newline(n int) {
- if n > 0 {
- m := int(*maxnewlines);
- if n > m {
- n = m;
- }
- for n > 0 {
- P.Printf("\n");
- n--;
- }
- for i := P.indentation; i > 0; i-- {
- P.Printf("\t");
- }
- }
-}
-
-
-func (P *Printer) TaggedString(pos token.Position, tag, s, endtag string) {
- // use estimate for pos if we don't have one
- offs := pos.Offset;
- if offs == 0 {
- offs = P.lastpos.Offset;
- }
-
- // --------------------------------
- // print pending separator, if any
- // - keep track of white space printed for better comment formatting
- // TODO print white space separators after potential comments and newlines
- // (currently, we may get trailing white space before a newline)
- trailing_char := 0;
- switch P.separator {
- case none: // nothing to do
- case blank:
- P.Printf(" ");
- trailing_char = ' ';
- case tab:
- P.Printf("\t");
- trailing_char = '\t';
- case comma:
- P.Printf(",");
- if P.newlines == 0 {
- P.Printf(" ");
- trailing_char = ' ';
- }
- case semicolon:
- if P.level > 0 { // no semicolons at level 0
- P.Printf(";");
- if P.newlines == 0 {
- P.Printf(" ");
- trailing_char = ' ';
- }
- }
- default: panic("UNREACHABLE");
- }
- P.separator = none;
-
- // --------------------------------
- // interleave comments, if any
- nlcount := 0;
- if P.full {
- for ; P.hasComment(pos); P.nextComments() {
- // we have a comment group that comes before the string
- comment := P.comments[P.cindex];
- ctext := string(comment.Text); // TODO get rid of string conversion here
-
- // classify comment (len(ctext) >= 2)
- //-style comment
- if nlcount > 0 || P.cpos.Offset == 0 {
- // only white space before comment on this line
- // or file starts with comment
- // - indent
- if !*newlines && P.cpos.Offset != 0 {
- nlcount = 1;
- }
- P.newline(nlcount);
- nlcount = 0;
-
- } else {
- // black space before comment on this line
- if ctext[1] == '/' {
- //-style comment
- // - put in next cell unless a scope was just opened
- // in which case we print 2 blanks (otherwise the
- // entire scope gets indented like the next cell)
- if P.laststate == opening_scope {
- switch trailing_char {
- case ' ': P.Printf(" "); // one space already printed
- case '\t': // do nothing
- default: P.Printf(" ");
- }
- } else {
- if trailing_char != '\t' {
- P.Printf("\t");
- }
- }
- } else {
- /*-style comment */
- // - print surrounded by blanks
- if trailing_char == 0 {
- P.Printf(" ");
- }
- ctext += " ";
- }
- }
-
- // print comment
- if *debug {
- P.Printf("[%d]", P.cpos.Offset);
- }
- // calling untabify increases the change for idempotent output
- // since tabs in comments are also interpreted by tabwriter
- P.Printf("%s", P.htmlEscape(untabify(ctext)));
- }
- // 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
- // printing newlines below.
- }
-
- // --------------------------------
- // interpret state
- // (any pending separator or comment must be printed in previous state)
- switch P.state {
- case normal:
- case opening_scope:
- case closing_scope:
- P.indentation--;
- case inside_list:
- default:
- panic("UNREACHABLE");
- }
-
- // --------------------------------
- // print pending newlines
- if *newlines && (P.newlines > 0 || P.state == inside_list) && nlcount > P.newlines {
- // Respect additional newlines in the source, but only if we
- // enabled this feature (newlines.BVal()) and we are expecting
- // newlines (P.newlines > 0 || P.state == inside_list).
- // Otherwise - because we don't have all token positions - we
- // get funny formatting.
- P.newlines = nlcount;
- }
- nlcount = 0;
- P.newline(P.newlines);
- P.newlines = 0;
-
- // --------------------------------
- // print string
- if *debug {
- P.Printf("[%d]", pos);
- }
- P.Printf("%s%s%s", tag, P.htmlEscape(s), endtag);
-
- // --------------------------------
- // interpret state
- switch P.state {
- case normal:
- case opening_scope:
- P.level++;
- P.indentation++;
- case closing_scope:
- P.level--;
- case inside_list:
- default:
- panic("UNREACHABLE");
- }
- P.laststate = P.state;
- P.state = none;
-
- // --------------------------------
- // done
- P.opt_semi = false;
- pos.Offset += len(s); // rough estimate
- pos.Column += len(s); // rough estimate
- P.lastpos = pos;
-}
-
-
-func (P *Printer) String(pos token.Position, s string) {
- P.TaggedString(pos, "", s, "");
-}
-
-
-func (P *Printer) Token(pos token.Position, tok token.Token) {
- P.String(pos, tok.String());
- //P.TaggedString(pos, "", tok.String(), "");
-}
-
-
-func (P *Printer) Error(pos token.Position, tok token.Token, msg string) {
- fmt.Printf("\ninternal printing error: pos = %d, tok = %s, %s\n", pos.Offset, tok.String(), msg);
- panic();
-}
-
-
-// ----------------------------------------------------------------------------
-// HTML support
-
-func (P *Printer) HtmlIdentifier(x *ast.Ident) {
- P.String(x.Pos(), string(x.Lit));
- /*
- obj := x.Obj;
- if P.html && obj.Kind != symbolTable.NONE {
- // depending on whether we have a declaration or use, generate different html
- // - no need to htmlEscape ident
- id := utils.IntToString(obj.Id, 10);
- if x.Loc_ == obj.Pos {
- // probably the declaration of x
- P.TaggedString(x.Loc_, ``, obj.Ident, ``);
- } else {
- // probably not the declaration of x
- P.TaggedString(x.Loc_, ``, obj.Ident, ``);
- }
- } else {
- P.String(x.Loc_, obj.Ident);
- }
- */
-}
-
-
-func (P *Printer) HtmlPackageName(pos token.Position, name string) {
- if P.html {
- sname := name[1 : len(name)-1]; // strip quotes TODO do this elsewhere eventually
- // TODO CAPITAL HACK BELOW FIX THIS
- P.TaggedString(pos, `"`, sname, `"`);
- } else {
- P.String(pos, name);
- }
-}
-
-
-// ----------------------------------------------------------------------------
-// Support
-
-func (P *Printer) Expr(x ast.Expr)
-
-func (P *Printer) Idents(list []*ast.Ident, full bool) int {
- n := 0;
- for i, x := range list {
- if n > 0 {
- P.Token(nopos, token.COMMA);
- P.separator = blank;
- P.state = inside_list;
- }
- if full || isExported(x) {
- P.Expr(x);
- n++;
- }
- }
- return n;
-}
-
-
-func (P *Printer) Exprs(list []ast.Expr) {
- for i, x := range list {
- if i > 0 {
- P.Token(nopos, token.COMMA);
- P.separator = blank;
- P.state = inside_list;
- }
- P.Expr(x);
- }
-}
-
-
-func (P *Printer) Parameters(list []*ast.Field) {
- P.Token(nopos, token.LPAREN);
- if len(list) > 0 {
- for i, par := range list {
- if i > 0 {
- P.separator = comma;
- }
- n := P.Idents(par.Names, true);
- if n > 0 {
- P.separator = blank
- };
- P.Expr(par.Type);
- }
- }
- P.Token(nopos, token.RPAREN);
-}
-
-
-// Returns the separator (semicolon or none) required if
-// the type is terminating a declaration or statement.
-func (P *Printer) Signature(params, result []*ast.Field) {
- P.Parameters(params);
- if result != nil {
- P.separator = blank;
-
- if len(result) == 1 && result[0].Names == nil {
- // single anonymous result
- // => no parentheses needed unless it's a function type
- fld := result[0];
- if dummy, is_ftyp := fld.Type.(*ast.FunctionType); !is_ftyp {
- P.Expr(fld.Type);
- return;
- }
- }
-
- P.Parameters(result);
- }
-}
-
-
-func (P *Printer) Fields(lbrace token.Position, list []*ast.Field, rbrace token.Position, is_interface bool) {
- P.state = opening_scope;
- P.separator = blank;
- P.Token(lbrace, token.LBRACE);
-
- if len(list) > 0 {
- P.newlines = 1;
- for i, fld := range list {
- if i > 0 {
- P.separator = semicolon;
- P.newlines = 1;
- }
- n := P.Idents(fld.Names, P.full);
- if n > 0 {
- // at least one identifier
- P.separator = tab
- };
- if n > 0 || len(fld.Names) == 0 {
- // at least one identifier or anonymous field
- if is_interface {
- if ftyp, is_ftyp := fld.Type.(*ast.FunctionType); is_ftyp {
- P.Signature(ftyp.Params, ftyp.Results);
- } else {
- P.Expr(fld.Type);
- }
- } else {
- P.Expr(fld.Type);
- if fld.Tag != nil {
- P.separator = tab;
- P.Expr(&ast.StringList{fld.Tag});
- }
- }
- }
- }
- P.newlines = 1;
- }
-
- P.state = closing_scope;
- P.Token(rbrace, token.RBRACE);
- P.opt_semi = true;
-}
-
-
-// ----------------------------------------------------------------------------
-// Expressions
-
-func (P *Printer) Expr1(x ast.Expr, prec1 int)
-func (P *Printer) Stmt(s ast.Stmt)
-
-
-func (P *Printer) DoBadExpr(x *ast.BadExpr) {
- P.String(nopos, "BadExpr");
-}
-
-
-func (P *Printer) DoIdent(x *ast.Ident) {
- P.HtmlIdentifier(x);
-}
-
-
-func (P *Printer) DoBinaryExpr(x *ast.BinaryExpr) {
- prec := x.Op.Precedence();
- if prec < P.prec {
- P.Token(nopos, token.LPAREN);
- }
- P.Expr1(x.X, prec);
- P.separator = blank;
- P.Token(x.OpPos, x.Op);
- P.separator = blank;
- P.Expr1(x.Y, prec);
- if prec < P.prec {
- P.Token(nopos, token.RPAREN);
- }
-}
-
-
-func (P *Printer) DoKeyValueExpr(x *ast.KeyValueExpr) {
- P.Expr(x.Key);
- P.separator = blank;
- P.Token(x.Colon, token.COLON);
- P.separator = blank;
- P.Expr(x.Value);
-}
-
-
-func (P *Printer) DoStarExpr(x *ast.StarExpr) {
- P.Token(x.Pos(), token.MUL);
- P.Expr(x.X);
-}
-
-
-func (P *Printer) DoUnaryExpr(x *ast.UnaryExpr) {
- prec := token.UnaryPrec;
- if prec < P.prec {
- P.Token(nopos, token.LPAREN);
- }
- P.Token(x.Pos(), x.Op);
- if x.Op == token.RANGE {
- P.separator = blank;
- }
- P.Expr1(x.X, prec);
- if prec < P.prec {
- P.Token(nopos, token.RPAREN);
- }
-}
-
-
-func (P *Printer) DoIntLit(x *ast.IntLit) {
- // TODO get rid of string conversion here
- P.String(x.Pos(), string(x.Lit));
-}
-
-
-func (P *Printer) DoFloatLit(x *ast.FloatLit) {
- // TODO get rid of string conversion here
- P.String(x.Pos(), string(x.Lit));
-}
-
-
-func (P *Printer) DoCharLit(x *ast.CharLit) {
- // TODO get rid of string conversion here
- P.String(x.Pos(), string(x.Lit));
-}
-
-
-func (P *Printer) DoStringLit(x *ast.StringLit) {
- // TODO get rid of string conversion here
- P.String(x.Pos(), string(x.Lit));
-}
-
-
-func (P *Printer) DoStringList(x *ast.StringList) {
- for i, x := range x.Strings {
- if i > 0 {
- P.separator = blank;
- }
- P.DoStringLit(x);
- }
-}
-
-
-func (P *Printer) DoFunctionType(x *ast.FunctionType)
-
-func (P *Printer) DoFunctionLit(x *ast.FunctionLit) {
- P.DoFunctionType(x.Type);
- P.separator = blank;
- P.Stmt(x.Body);
- P.newlines = 0;
-}
-
-
-func (P *Printer) DoParenExpr(x *ast.ParenExpr) {
- P.Token(x.Pos(), token.LPAREN);
- P.Expr(x.X);
- P.Token(x.Rparen, token.RPAREN);
-}
-
-
-func (P *Printer) DoSelectorExpr(x *ast.SelectorExpr) {
- P.Expr1(x.X, token.HighestPrec);
- P.Token(nopos, token.PERIOD);
- P.Expr1(x.Sel, token.HighestPrec);
-}
-
-
-func (P *Printer) DoTypeAssertExpr(x *ast.TypeAssertExpr) {
- P.Expr1(x.X, token.HighestPrec);
- P.Token(nopos, token.PERIOD);
- P.Token(nopos, token.LPAREN);
- P.Expr(x.Type);
- P.Token(nopos, token.RPAREN);
-}
-
-
-func (P *Printer) DoIndexExpr(x *ast.IndexExpr) {
- P.Expr1(x.X, token.HighestPrec);
- P.Token(nopos, token.LBRACK);
- P.Expr(x.Index);
- P.Token(nopos, token.RBRACK);
-}
-
-
-func (P *Printer) DoSliceExpr(x *ast.SliceExpr) {
- P.Expr1(x.X, token.HighestPrec);
- P.Token(nopos, token.LBRACK);
- P.Expr(x.Begin);
- P.Token(nopos, token.COLON);
- P.Expr(x.End);
- P.Token(nopos, token.RBRACK);
-}
-
-
-func (P *Printer) DoCallExpr(x *ast.CallExpr) {
- P.Expr1(x.Fun, token.HighestPrec);
- P.Token(x.Lparen, token.LPAREN);
- P.Exprs(x.Args);
- P.Token(x.Rparen, token.RPAREN);
-}
-
-
-func (P *Printer) DoCompositeLit(x *ast.CompositeLit) {
- P.Expr1(x.Type, token.HighestPrec);
- P.Token(x.Lbrace, token.LBRACE);
- P.Exprs(x.Elts);
- P.Token(x.Rbrace, token.RBRACE);
-}
-
-
-func (P *Printer) DoEllipsis(x *ast.Ellipsis) {
- P.Token(x.Pos(), token.ELLIPSIS);
-}
-
-
-func (P *Printer) DoArrayType(x *ast.ArrayType) {
- P.Token(x.Pos(), token.LBRACK);
- P.Expr(x.Len);
- P.Token(nopos, token.RBRACK);
- P.Expr(x.Elt);
-}
-
-
-func (P *Printer) DoSliceType(x *ast.SliceType) {
- P.Token(x.Pos(), token.LBRACK);
- P.Token(nopos, token.RBRACK);
- P.Expr(x.Elt);
-}
-
-
-func (P *Printer) DoStructType(x *ast.StructType) {
- P.Token(x.Pos(), token.STRUCT);
- if x.Fields != nil {
- P.Fields(x.Lbrace, x.Fields, x.Rbrace, false);
- }
-}
-
-
-func (P *Printer) DoFunctionType(x *ast.FunctionType) {
- P.Token(x.Pos(), token.FUNC);
- P.Signature(x.Params, x.Results);
-}
-
-
-func (P *Printer) DoInterfaceType(x *ast.InterfaceType) {
- P.Token(x.Pos(), token.INTERFACE);
- if x.Methods != nil {
- P.Fields(x.Lbrace, x.Methods, x.Rbrace, true);
- }
-}
-
-
-func (P *Printer) DoMapType(x *ast.MapType) {
- P.Token(x.Pos(), token.MAP);
- P.separator = blank;
- P.Token(nopos, token.LBRACK);
- P.Expr(x.Key);
- P.Token(nopos, token.RBRACK);
- P.Expr(x.Value);
-}
-
-
-func (P *Printer) DoChannelType(x *ast.ChannelType) {
- switch x.Dir {
- case ast.SEND | ast.RECV:
- P.Token(x.Pos(), token.CHAN);
- case ast.RECV:
- P.Token(x.Pos(), token.ARROW);
- P.Token(nopos, token.CHAN);
- case ast.SEND:
- P.Token(x.Pos(), token.CHAN);
- P.separator = blank;
- P.Token(nopos, token.ARROW);
- }
- P.separator = blank;
- P.Expr(x.Value);
-}
-
-
-func (P *Printer) Expr1(x ast.Expr, prec1 int) {
- if x == nil {
- return; // empty expression list
- }
-
- saved_prec := P.prec;
- P.prec = prec1;
- x.Visit(P);
- P.prec = saved_prec;
-}
-
-
-func (P *Printer) Expr(x ast.Expr) {
- P.Expr1(x, token.LowestPrec);
-}
-
-
-// ----------------------------------------------------------------------------
-// Statements
-
-func (P *Printer) Stmt(s ast.Stmt) {
- s.Visit(P);
-}
-
-
-func (P *Printer) DoBadStmt(s *ast.BadStmt) {
- panic();
-}
-
-
-func (P *Printer) Decl(d ast.Decl);
-
-func (P *Printer) DoDeclStmt(s *ast.DeclStmt) {
- P.Decl(s.Decl);
-}
-
-
-func (P *Printer) DoEmptyStmt(s *ast.EmptyStmt) {
- P.String(s.Pos(), "");
-}
-
-
-func (P *Printer) DoLabeledStmt(s *ast.LabeledStmt) {
- P.indentation--;
- P.Expr(s.Label);
- P.Token(nopos, token.COLON);
- P.indentation++;
- // TODO be more clever if s.Stmt is a labeled stat as well
- P.separator = tab;
- P.Stmt(s.Stmt);
-}
-
-
-func (P *Printer) DoExprStmt(s *ast.ExprStmt) {
- P.Expr(s.X);
-}
-
-
-func (P *Printer) DoIncDecStmt(s *ast.IncDecStmt) {
- P.Expr(s.X);
- P.Token(nopos, s.Tok);
-}
-
-
-func (P *Printer) DoAssignStmt(s *ast.AssignStmt) {
- P.Exprs(s.Lhs);
- P.separator = blank;
- P.Token(s.TokPos, s.Tok);
- P.separator = blank;
- P.Exprs(s.Rhs);
-}
-
-
-func (P *Printer) DoGoStmt(s *ast.GoStmt) {
- P.Token(s.Pos(), token.GO);
- P.separator = blank;
- P.Expr(s.Call);
-}
-
-
-func (P *Printer) DoDeferStmt(s *ast.DeferStmt) {
- P.Token(s.Pos(), token.DEFER);
- P.separator = blank;
- P.Expr(s.Call);
-}
-
-
-func (P *Printer) DoReturnStmt(s *ast.ReturnStmt) {
- P.Token(s.Pos(), token.RETURN);
- P.separator = blank;
- P.Exprs(s.Results);
-}
-
-
-func (P *Printer) DoBranchStmt(s *ast.BranchStmt) {
- P.Token(s.Pos(), s.Tok);
- if s.Label != nil {
- P.separator = blank;
- P.Expr(s.Label);
- }
-}
-
-
-func (P *Printer) StatementList(list []ast.Stmt) {
- if list != nil {
- for i, s := range list {
- if i == 0 {
- P.newlines = 1;
- } else { // i > 0
- if !P.opt_semi || *optsemicolons {
- // semicolon is required
- P.separator = semicolon;
- }
- }
- P.Stmt(s);
- P.newlines = 1;
- P.state = inside_list;
- }
- }
-}
-
-
-/*
-func (P *Printer) Block(list []ast.Stmt, indent bool) {
- P.state = opening_scope;
- P.Token(b.Pos_, b.Tok);
- if !indent {
- P.indentation--;
- }
- P.StatementList(b.List);
- if !indent {
- P.indentation++;
- }
- if !*optsemicolons {
- P.separator = none;
- }
- P.state = closing_scope;
- if b.Tok == token.LBRACE {
- P.Token(b.Rbrace, token.RBRACE);
- P.opt_semi = true;
- } else {
- P.String(nopos, ""); // process closing_scope state transition!
- }
-}
-*/
-
-
-func (P *Printer) DoBlockStmt(s *ast.BlockStmt) {
- P.state = opening_scope;
- P.Token(s.Pos(), token.LBRACE);
- P.StatementList(s.List);
- if !*optsemicolons {
- P.separator = none;
- }
- P.state = closing_scope;
- P.Token(s.Rbrace, token.RBRACE);
- P.opt_semi = true;
-}
-
-
-func (P *Printer) ControlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, post ast.Stmt) {
- P.separator = blank;
- if init == nil && post == nil {
- // no semicolons required
- if expr != nil {
- P.Expr(expr);
- }
- } else {
- // all semicolons required
- // (they are not separators, print them explicitly)
- if init != nil {
- P.Stmt(init);
- P.separator = none;
- }
- P.Token(nopos, token.SEMICOLON);
- P.separator = blank;
- if expr != nil {
- P.Expr(expr);
- P.separator = none;
- }
- if isForStmt {
- P.Token(nopos, token.SEMICOLON);
- P.separator = blank;
- if post != nil {
- P.Stmt(post);
- }
- }
- }
- P.separator = blank;
-}
-
-
-func (P *Printer) DoIfStmt(s *ast.IfStmt) {
- P.Token(s.Pos(), token.IF);
- P.ControlClause(false, s.Init, s.Cond, nil);
- P.Stmt(s.Body);
- if s.Else != nil {
- P.separator = blank;
- P.Token(nopos, token.ELSE);
- P.separator = blank;
- P.Stmt(s.Else);
- }
-}
-
-
-func (P *Printer) DoCaseClause(s *ast.CaseClause) {
- if s.Values != nil {
- P.Token(s.Pos(), token.CASE);
- P.separator = blank;
- P.Exprs(s.Values);
- } else {
- P.Token(s.Pos(), token.DEFAULT);
- }
- P.Token(s.Colon, token.COLON);
- P.indentation++;
- P.StatementList(s.Body);
- P.indentation--;
- P.newlines = 1;
-}
-
-
-func (P *Printer) DoSwitchStmt(s *ast.SwitchStmt) {
- P.Token(s.Pos(), token.SWITCH);
- P.ControlClause(false, s.Init, s.Tag, nil);
- P.Stmt(s.Body);
-}
-
-
-func (P *Printer) DoTypeCaseClause(s *ast.TypeCaseClause) {
- if s.Type != nil {
- P.Token(s.Pos(), token.CASE);
- P.separator = blank;
- P.Expr(s.Type);
- } else {
- P.Token(s.Pos(), token.DEFAULT);
- }
- P.Token(s.Colon, token.COLON);
- P.indentation++;
- P.StatementList(s.Body);
- P.indentation--;
- P.newlines = 1;
-}
-
-
-func (P *Printer) DoTypeSwitchStmt(s *ast.TypeSwitchStmt) {
- P.Token(s.Pos(), token.SWITCH);
- P.separator = blank;
- if s.Init != nil {
- P.Stmt(s.Init);
- P.separator = none;
- P.Token(nopos, token.SEMICOLON);
- }
- P.separator = blank;
- P.Stmt(s.Assign);
- P.separator = blank;
- P.Stmt(s.Body);
-}
-
-
-func (P *Printer) DoCommClause(s *ast.CommClause) {
- if s.Rhs != nil {
- P.Token(s.Pos(), token.CASE);
- P.separator = blank;
- if s.Lhs != nil {
- P.Expr(s.Lhs);
- P.separator = blank;
- P.Token(nopos, s.Tok);
- P.separator = blank;
- }
- P.Expr(s.Rhs);
- } else {
- P.Token(s.Pos(), token.DEFAULT);
- }
- P.Token(s.Colon, token.COLON);
- P.indentation++;
- P.StatementList(s.Body);
- P.indentation--;
- P.newlines = 1;
-}
-
-
-func (P *Printer) DoSelectStmt(s *ast.SelectStmt) {
- P.Token(s.Pos(), token.SELECT);
- P.separator = blank;
- P.Stmt(s.Body);
-}
-
-
-func (P *Printer) DoForStmt(s *ast.ForStmt) {
- P.Token(s.Pos(), token.FOR);
- P.ControlClause(true, s.Init, s.Cond, s.Post);
- P.Stmt(s.Body);
-}
-
-
-func (P *Printer) DoRangeStmt(s *ast.RangeStmt) {
- P.Token(s.Pos(), token.FOR);
- P.separator = blank;
- P.Expr(s.Key);
- if s.Value != nil {
- P.Token(nopos, token.COMMA);
- P.separator = blank;
- P.state = inside_list;
- P.Expr(s.Value);
- }
- P.separator = blank;
- P.Token(s.TokPos, s.Tok);
- P.separator = blank;
- P.Token(nopos, token.RANGE);
- P.separator = blank;
- P.Expr(s.X);
- P.separator = blank;
- P.Stmt(s.Body);
-}
-
-
-// ----------------------------------------------------------------------------
-// Declarations
-
-func (P *Printer) DoBadDecl(d *ast.BadDecl) {
- P.String(d.Pos(), "");
-}
-
-
-func (P *Printer) DoImportDecl(d *ast.ImportDecl) {
- if d.Pos().Offset > 0 {
- P.Token(d.Pos(), token.IMPORT);
- P.separator = blank;
- }
- if d.Name != nil {
- P.Expr(d.Name);
- } else {
- P.String(d.Path[0].Pos(), ""); // flush pending ';' separator/newlines
- }
- P.separator = tab;
- // TODO fix for longer package names
- if len(d.Path) > 1 {
- panic();
- }
- P.HtmlPackageName(d.Path[0].Pos(), string(d.Path[0].Lit));
- P.newlines = 2;
-}
-
-
-func (P *Printer) DoConstDecl(d *ast.ConstDecl) {
- if d.Pos().Offset > 0 {
- P.Token(d.Pos(), token.CONST);
- P.separator = blank;
- }
- P.Idents(d.Names, P.full);
- if d.Type != nil {
- P.separator = blank; // TODO switch to tab? (indentation problem with structs)
- P.Expr(d.Type);
- }
- if d.Values != nil {
- P.separator = tab;
- P.Token(nopos, token.ASSIGN);
- P.separator = blank;
- P.Exprs(d.Values);
- }
- P.newlines = 2;
-}
-
-
-func (P *Printer) DoTypeDecl(d *ast.TypeDecl) {
- if d.Pos().Offset > 0 {
- P.Token(d.Pos(), token.TYPE);
- P.separator = blank;
- }
- P.Expr(d.Name);
- P.separator = blank; // TODO switch to tab? (but indentation problem with structs)
- P.Expr(d.Type);
- P.newlines = 2;
-}
-
-
-func (P *Printer) DoVarDecl(d *ast.VarDecl) {
- if d.Pos().Offset > 0 {
- P.Token(d.Pos(), token.VAR);
- P.separator = blank;
- }
- P.Idents(d.Names, P.full);
- if d.Type != nil {
- P.separator = blank; // TODO switch to tab? (indentation problem with structs)
- P.Expr(d.Type);
- //P.separator = P.Type(d.Type);
- }
- if d.Values != nil {
- P.separator = tab;
- P.Token(nopos, token.ASSIGN);
- P.separator = blank;
- P.Exprs(d.Values);
- }
- P.newlines = 2;
-}
-
-
-func (P *Printer) DoFuncDecl(d *ast.FuncDecl) {
- P.Token(d.Pos(), token.FUNC);
- P.separator = blank;
- if recv := d.Recv; recv != nil {
- // method: print receiver
- P.Token(nopos, token.LPAREN);
- if len(recv.Names) > 0 {
- P.Expr(recv.Names[0]);
- P.separator = blank;
- }
- P.Expr(recv.Type);
- P.Token(nopos, token.RPAREN);
- P.separator = blank;
- }
- P.Expr(d.Name);
- P.Signature(d.Type.Params, d.Type.Results);
- if P.full && d.Body != nil {
- P.separator = blank;
- P.Stmt(d.Body);
- }
- P.newlines = 3;
-}
-
-
-func (P *Printer) DoDeclList(d *ast.DeclList) {
- P.Token(d.Pos(), d.Tok);
- P.separator = blank;
-
- // group of parenthesized declarations
- P.state = opening_scope;
- P.Token(nopos, token.LPAREN);
- if len(d.List) > 0 {
- P.newlines = 1;
- for i := 0; i < len(d.List); i++ {
- if i > 0 {
- P.separator = semicolon;
- }
- P.Decl(d.List[i]);
- P.newlines = 1;
- }
- }
- P.state = closing_scope;
- P.Token(d.Rparen, token.RPAREN);
- P.opt_semi = true;
- P.newlines = 2;
-}
-
-
-func (P *Printer) Decl(d ast.Decl) {
- d.Visit(P);
-}
-
-
-// ----------------------------------------------------------------------------
-// Package interface
-
-func stripWhiteSpace(s []byte) []byte {
- i, j := 0, len(s);
- for i < len(s) && s[i] <= ' ' {
- 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.Comments) {
- in_paragraph := false;
- for i, c := range comment {
- s := cleanComment(c.Text);
- if len(s) > 0 {
- if !in_paragraph {
- P.Printf("\n");
- in_paragraph = true;
- }
- P.Printf("%s\n", P.htmlEscape(untabify(string(s))));
- } else {
- if in_paragraph {
- P.Printf("
\n");
- in_paragraph = false;
- }
- }
- }
- if in_paragraph {
- P.Printf("\n");
- }
-}
-
-
-func (P *Printer) Interface(p *ast.Package) {
- P.full = false;
- for i := 0; i < len(p.Decls); i++ {
- switch d := p.Decls[i].(type) {
- case *ast.ConstDecl:
- if hasExportedNames(d.Names) {
- P.Printf("Constants
\n");
- P.Printf("");
- P.DoConstDecl(d);
- P.String(nopos, "");
- P.Printf("
\n");
- if d.Doc != nil {
- P.printComment(d.Doc);
- }
- }
-
- case *ast.TypeDecl:
- if isExported(d.Name) {
- P.Printf("type %s
\n", d.Name.Lit);
- P.Printf("");
- P.DoTypeDecl(d);
- P.String(nopos, "");
- P.Printf("
\n");
- if d.Doc != nil {
- P.printComment(d.Doc);
- }
- }
-
- case *ast.VarDecl:
- if hasExportedNames(d.Names) {
- P.Printf("Variables
\n");
- P.Printf("");
- P.DoVarDecl(d);
- P.String(nopos, "");
- P.Printf("
\n");
- if d.Doc != nil {
- P.printComment(d.Doc);
- }
- }
-
- case *ast.FuncDecl:
- if isExported(d.Name) {
- if d.Recv != nil {
- P.Printf("func (");
- P.Expr(d.Recv.Type);
- P.Printf(") %s
\n", d.Name.Lit);
- } else {
- P.Printf("func %s
\n", d.Name.Lit);
- }
- P.Printf("");
- P.DoFuncDecl(d);
- P.String(nopos, "");
- P.Printf("
\n");
- if d.Doc != nil {
- P.printComment(d.Doc);
- }
- }
-
- case *ast.DeclList:
-
- }
- }
-}
-
-
-// ----------------------------------------------------------------------------
-// Program
-
-func (P *Printer) Program(p *ast.Package) {
- P.full = true;
- P.Token(p.Pos(), token.PACKAGE);
- P.separator = blank;
- P.Expr(p.Name);
- P.newlines = 1;
- for i := 0; i < len(p.Decls); i++ {
- P.Decl(p.Decls[i]);
- }
- P.newlines = 1;
-}
-
-
-// ----------------------------------------------------------------------------
-// External interface
-
-var templ = template.NewTemplateOrDie("template.html");
-
-
-func Print(writer io.Write, prog *ast.Package, html bool) {
- // setup
- var P Printer;
- padchar := byte(' ');
- if *usetabs {
- padchar = '\t';
- }
- flags := uint(0);
- if html {
- flags |= tabwriter.FilterHTML;
- }
- text := tabwriter.NewWriter(writer, *tabwidth, 1, padchar, flags);
- P.Init(text, prog.Comments, html);
-
- if P.html {
- err := templ.Apply(text, "" : func() { P.Printf("%s", prog.Name.Lit); },
- "PACKAGE_COMMENT-->": func() { P.printComment(prog.Doc); },
- "PACKAGE_INTERFACE-->" : func() { P.Interface(prog); },
- "PACKAGE_BODY-->" : func() { P.Program(prog); },
- });
- if err != nil {
- panic("print error - exiting");
- }
- } else {
- P.Program(prog);
- }
-
- P.String(nopos, ""); // flush pending separator/newlines
- err := text.Flush();
- if err != nil {
- panic("print error - exiting");
- }
-}
diff --git a/usr/gri/pretty/template.html b/usr/gri/pretty/template.html
index 617b4562bef..e4a7550dd75 100644
--- a/usr/gri/pretty/template.html
+++ b/usr/gri/pretty/template.html
@@ -2,8 +2,16 @@
THIS SECTION IS CURRENTLY UNDER CONSTRUCTION
package
-
-
+
+
+
+
+
+
+
+
+
+
Implementation
diff --git a/usr/gri/pretty/typechecker.go b/usr/gri/pretty/typechecker.go
index 2582f61a5bb..b2dc4c9d395 100644
--- a/usr/gri/pretty/typechecker.go
+++ b/usr/gri/pretty/typechecker.go
@@ -77,7 +77,7 @@ func (s *state) CheckDeclaration(d *AST.Decl) {
*/
-func (s *state) CheckProgram(p *ast.Package) {
+func (s *state) CheckProgram(p *ast.Program) {
for i := 0; i < len(p.Decls); i++ {
//s.CheckDeclaration(p.Decls[i].(*AST.Decl));
}
@@ -86,7 +86,7 @@ func (s *state) CheckProgram(p *ast.Package) {
// ----------------------------------------------------------------------------
-func CheckProgram(err scanner.ErrorHandler, p *ast.Package) {
+func CheckProgram(err scanner.ErrorHandler, p *ast.Program) {
var s state;
s.Init(err);
s.CheckProgram(p);