]> Cypherpunks repositories - gostls13.git/commitdiff
- factored out tabwriter a separate writer filter
authorRobert Griesemer <gri@golang.org>
Tue, 18 Nov 2008 03:58:52 +0000 (19:58 -0800)
committerRobert Griesemer <gri@golang.org>
Tue, 18 Nov 2008 03:58:52 +0000 (19:58 -0800)
  (to be moved into std lib eventually)
- rewrote tabwriter to use byte buffers instead of strings
  (byte buffers to be moved into stdlib eventually)
- support for recent syntax changes
- no space printed after function name and before function parameters
- comments still disabled due to a known bug

R=r
OCL=19430
CL=19430

usr/gri/pretty/Makefile
usr/gri/pretty/parser.go
usr/gri/pretty/printer.go
usr/gri/pretty/selftest2.go
usr/gri/pretty/tabwriter.go [new file with mode: 0644]

index 000d88f1da8cc38ed408317e05ab6d71f8a45c34..462ab5f5565912d02258872a50d9dc4353986d45 100644 (file)
@@ -32,7 +32,8 @@ parser.6:      scanner.6 ast.6
 
 platform.6:     utils.6
 
-printer.6:      scanner.6 ast.6
+printer.6:      scanner.6 ast.6 tabwriter.6
+
 
 %.6:   %.go
        $(G) $(F) $<
index 5cd454918bada6271a1ec16fb603e3fafb5960c5..9e6bc10c06de19d8d40fe7c583dfbde7f191c093 100644 (file)
@@ -469,8 +469,14 @@ func (P *Parser) ParseFunctionType() *AST.Type {
 func (P *Parser) ParseMethodSpec(list *AST.List) {
        P.Trace("MethodDecl");
        
-       list.Add(P.ParseIdent());
-       list.Add(AST.NewTypeExpr(P.ParseFunctionType()));
+       list.Add(P.ParseIdentList());
+       t := AST.BadType;
+       if P.sixg {
+               t = P.ParseType();
+       } else {
+               t = P.ParseFunctionType();
+       }
+       list.Add(AST.NewTypeExpr(t));
        
        P.Ecart();
 }
@@ -1485,7 +1491,8 @@ func (P *Parser) ParseDeclaration() *AST.Decl {
        
        d := AST.BadDecl;
        exported := false;
-       if P.tok == Scanner.EXPORT {
+       // TODO don't use bool flag for export
+       if P.tok == Scanner.EXPORT || P.tok == Scanner.PACKAGE {
                if P.scope_lev == 0 {
                        exported = true;
                } else {
index 57b3124ba753fbf5a08a07b0822efc93d46a78e5..039199db463ff01ea85b50317d07f47297b1e69f 100644 (file)
@@ -9,6 +9,9 @@ import Scanner "scanner"
 import AST "ast"
 import Flag "flag"
 import Fmt "fmt"
+import IO "io"
+import OS "os"
+import TabWriter "tabwriter"
 
 var tabwith = Flag.Int("tabwidth", 4, nil, "tab width");
 var comments = Flag.Bool("comments", false, nil, "enable printing of comments");
@@ -24,180 +27,11 @@ func assert(p bool) {
 }
 
 
-func PrintBlanks(n int) {
-       // TODO make this faster
-       for ; n > 0; n-- {
-               print(" ");
-       }
-}
-
-
-// ----------------------------------------------------------------------------
-// Implemententation of flexible tab stops.
-
-// Buffer is a representation for a list of lines consisting of
-// cells. A new cell is added for each Tab() call, and a new line
-// is added for each Newline() call.
-//
-// The lines are formatted and printed such that all cells in a column
-// of adjacent cells have the same width (by adding padding). For more
-// details see: http://nickgravgaard.com/elastictabstops/index.html .
-
-type Buffer struct {
-       cell string;  // current cell (last cell in last line, not in lines yet)
-       lines AST.List;  // list of lines; each line is a list of cells (strings)
-       widths AST.List;  // list of column widths - (re-)used during formatting
-}
-
-
-// Implementation
-// (Do not use these functions outside the Buffer implementation).
-
-func (b *Buffer) AddLine() {
-       b.lines.Add(AST.NewList());
-}
-
-
-func (b *Buffer) Line(i int) *AST.List {
-       return b.lines.at(i).(*AST.List);
-}
-
-
-func (b *Buffer) LastLine() *AST.List {
-       return b.lines.last().(*AST.List);
-}
-
-
-// debugging support
-func (b *Buffer) Dump() {
-       for i := 0; i < b.lines.len(); i++ {
-               line := b.Line(i);
-               print("(", i, ") ");
-               for j := 0; j < line.len(); j++ {
-                       print("[", line.at(j).(string), "]");
-               }
-               print("\n");
-       }
-       print("\n");
-}
-
-
-func (b *Buffer) PrintLines(line0, line1 int) {
-       for i := line0; i < line1; i++ {
-               line := b.Line(i);
-               for j := 0; j < line.len(); j++ {
-                       s := line.at(j).(string);
-                       print(s);
-                       if j < b.widths.len() {
-                               nsep := b.widths.at(j).(int) - len(s);
-                               assert(nsep >= 0);
-                               PrintBlanks(nsep);
-                       } else {
-                               assert(j == b.widths.len());
-                       }
-               }
-               println();
-       }
-}
-
-
-func (b *Buffer) Format(line0, line1 int) {
-       column := b.widths.len();
-       
-       last := line0;
-       for this := line0; this < line1; this++ {
-               line := b.Line(this);
-               
-               if column < line.len() - 1 {
-                       // cell exists in this column
-                       // (note that the last cell per line is ignored)
-                       
-                       // print unprinted lines until beginning of block
-                       b.PrintLines(last, this);
-                       last = this;
-                       
-                       // column block begin
-                       width := int(tabwith.IVal());  // minimal width
-                       for ; this < line1; this++ {
-                               line := b.Line(this);
-                               if column < line.len() - 1 {
-                                       // cell exists in this column
-                                       // update width
-                                       w := len(line.at(column).(string)) + 1; // 1 = minimum space between cells
-                                       if w > width {
-                                               width = w;
-                                       }
-                               } else {
-                                       break
-                               }
-                       }
-                       // column block end
-
-                       // format and print all columns to the right of this column
-                       // (we know the widths of this column and all columns to the left)
-                       b.widths.Add(width);
-                       b.Format(last, this);
-                       b.widths.Pop();
-                       last = this;
-               }
-       }
-
-       // print unprinted lines until end
-       b.PrintLines(last, line1);
-}
-
-
-// Buffer interface
-// (Use these functions to interact with Buffers).
-
-func (b *Buffer) Init() {
-       b.lines.Init();
-       b.widths.Init();
-       b.AddLine();  // the very first line
-}
-
-
-func (b *Buffer) EmptyLine() bool {
-       return b.LastLine().len() == 0 && len(b.cell) == 0;
-}
-
-
-func (b *Buffer) Tab() {
-       b.LastLine().Add(b.cell);
-       b.cell = "";
-}
-
-
-func (b *Buffer) Newline() {
-       b.Tab();  // add last cell to current line
-       
-       if b.LastLine().len() == 1 {
-               // The current line has only one cell which does not have an impact
-               // on the formatting of the following lines (the last cell per line
-               // is ignored by Format), thus we can print the buffer contents.
-               assert(b.widths.len() == 0);
-               b.Format(0, b.lines.len());
-               assert(b.widths.len() == 0);
-               
-               // reset the buffer
-               b.lines.Clear();
-       }
-       
-       b.AddLine();
-       assert(len(b.cell) == 0);
-}
-
-
-func (b *Buffer) Print(s string) {
-       b.cell += s;
-}
-
-
 // ----------------------------------------------------------------------------
 // Printer
 
 export type Printer struct {
-       buf Buffer;
+       writer IO.Write;
        
        // formatting control
        lastpos int;  // pos after last string
@@ -213,13 +47,18 @@ export type Printer struct {
 }
 
 
+func (P *Printer) Printf(fmt string, s ...) {
+       Fmt.fprintf(P.writer, fmt, s);
+}
+
+
 func (P *Printer) String(pos int, s string) {
        if pos == 0 {
                pos = P.lastpos;  // estimate
        }
 
        if P.semi && P.level > 0 {  // no semicolons at level 0
-               P.buf.Print(";");
+               P.Printf(";");
        }
 
        //print("--", pos, "[", s, "]\n");
@@ -238,26 +77,25 @@ func (P *Printer) String(pos int, s string) {
                case Scanner.COMMENT_BB:
                        // black space before and after comment on the same line
                        // - print surrounded by blanks
-                       P.buf.Print(" ");
-                       P.buf.Print(text);
-                       P.buf.Print(" ");
+                       P.Printf(" %s ", text);
 
                case Scanner.COMMENT_BW:
                        // only white space after comment on the same line
                        // - put into next cell
-                       P.buf.Tab();
-                       P.buf.Print(text);
+                       P.Printf("\t%s", text);
                        
                case Scanner.COMMENT_WW, Scanner.COMMENT_WB:
                        // only white space before comment on the same line
                        // - indent
+                       /*
                        if !P.buf.EmptyLine() {
                                P.buf.Newline();
                        }
+                       */
                        for i := P.indent; i > 0; i-- {
-                               P.buf.Tab();
+                               P.Printf("\t");
                        }
-                       P.buf.Print(text);
+                       P.Printf("%s", text);
 
                default:
                        panic("UNREACHABLE");
@@ -266,9 +104,9 @@ func (P *Printer) String(pos int, s string) {
                if text[1] == '/' {
                        // line comments must end in newline
                        // TODO should we set P.newl instead?
-                       P.buf.Newline();
+                       P.Printf("\n");
                        for i := P.indent; i > 0; i-- {
-                               P.buf.Tab();
+                               P.Printf("\t");
                        }
                        at_line_begin = true;
                }
@@ -286,19 +124,18 @@ func (P *Printer) String(pos int, s string) {
        }
        
        if P.newl > 0 {
-               P.buf.Newline();
+               P.Printf("\n");
                if P.newl > 1 {
                        for i := P.newl; i > 1; i-- {
-                               //P.buf.Flush();
-                               P.buf.Newline();
+                               P.Printf("\n");
                        }
                }
                for i := P.indent; i > 0; i-- {
-                       P.buf.Tab();
+                       P.Printf("\t");
                }
        }
 
-       P.buf.Print(s);
+       P.Printf("%s", s);
 
        P.lastpos = pos + len(s);
        P.semi, P.newl = false, 0;
@@ -311,8 +148,7 @@ func (P *Printer) Blank() {
 
 
 func (P *Printer) Tab() {
-       P.String(0, "");
-       P.buf.Tab();
+       P.String(0, "\t");
 }
 
 
@@ -712,7 +548,9 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) {
                P.Expr(d.ident);
                
                if d.typ != nil {
-                       P.Blank();
+                       if d.tok != Scanner.FUNC {
+                               P.Blank();
+                       }
                        P.Type(d.typ);
                }
 
@@ -756,7 +594,7 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) {
 
 func (P *Printer) Program(p *AST.Program) {
        // TODO should initialize all fields?
-       P.buf.Init();
+       P.writer = TabWriter.MakeTabWriter(OS.Stdout, 4);
        
        P.clist = p.comments;
        P.cindex = 0;
index a6c49b675c732f23de118636d7f0abbad856cd4a..2b7b04be1bd55f28e82912955c020607a8919932 100644 (file)
@@ -22,14 +22,14 @@ var (
 
 
 func main() {
-// the prolog
+// the prologue
        for i := 0; i <= 10 /* limit */; i++ {
                println(i);  // the index
                println(i + 1);  // the index + 1
                println(i + 1000);  // the index + 1000
                println();
        }
-// the epilog
+// the epilogue
        println("foo");  // foo
        println("foobar");  // foobar
 var x int;
diff --git a/usr/gri/pretty/tabwriter.go b/usr/gri/pretty/tabwriter.go
new file mode 100644 (file)
index 0000000..fa3331d
--- /dev/null
@@ -0,0 +1,285 @@
+// 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 tabwriter
+
+import (
+       OS "os";
+       IO "io";
+       Vector "vector";
+)
+
+
+// ----------------------------------------------------------------------------
+// ByteArray
+
+type ByteArray struct {
+       a *[]byte;
+}
+
+
+func (b *ByteArray) Init(initial_size int) {
+       b.a = new([]byte, initial_size)[0 : 0];
+}
+
+
+func (b *ByteArray) Clear() {
+       b.a = b.a[0 : 0];
+}
+
+
+func (b *ByteArray) Len() int {
+       return len(b.a);
+}
+
+
+func (b *ByteArray) At(i int) byte {
+       return b.a[i];
+}
+
+
+func (b *ByteArray) Set(i int, x byte) {
+       b.a[i] = x;
+}
+
+
+func (b *ByteArray) Slice(i, j int) *[]byte {
+       return b.a[i : j];  // BUG should really be &b.a[i : j]
+}
+
+
+func (b *ByteArray) Append(s *[]byte) {
+       a := b.a;
+       n := len(a);
+       m := n + len(s);
+
+       if m > cap(a) {
+               n2 := 2*n;
+               if m > n2 {
+                       n2 = m;
+               }
+               b := new([]byte, n2);
+               for i := 0; i < n; i++ {
+                       b[i] = a[i];
+               }
+               a = b;
+       }
+
+       a = a[0 : m];
+       for i := len(s) - 1; i >= 0; i-- {
+               a[n + i] = s[i];
+       }
+       b.a = a;
+}
+
+
+// ----------------------------------------------------------------------------
+// Implemententation of flexible tab stops.
+
+// TabWriter is a representation for a list of lines consisting of
+// cells. A new cell is added for each Tab() call, and a new line
+// is added for each Newline() call.
+//
+// The lines are formatted and printed such that all cells in a column
+// of adjacent cells have the same width (by adding padding). For more
+// details see: http://nickgravgaard.com/elastictabstops/index.html .
+
+type TabWriter struct {
+       // configuration
+       writer IO.Write;
+       tabwidth int;
+
+       // current state
+       buf ByteArray;  // the collected text w/o tabs and newlines
+       width int;  // width of last incomplete cell
+       lines Vector.Vector;  // list of lines; each line is a list of cell widths
+       widths Vector.Vector;  // list of column widths - (re-)used during formatting
+}
+
+
+func (b *TabWriter) AddLine() {
+       b.lines.Append(Vector.New());
+}
+
+
+func (b *TabWriter) Init(writer IO.Write, tabwidth int) {
+       b.writer = writer;
+       b.tabwidth = tabwidth;
+       
+       b.buf.Init(1024);
+       b.lines.Init();
+       b.widths.Init();
+       b.AddLine();  // the very first line
+}
+
+
+func (b *TabWriter) Line(i int) *Vector.Vector {
+       return b.lines.At(i).(*Vector.Vector);
+}
+
+
+func (b *TabWriter) LastLine() *Vector.Vector {
+       return b.lines.At(b.lines.Len() - 1).(*Vector.Vector);
+}
+
+
+// debugging support
+func (b *TabWriter) Dump() {
+       pos := 0;
+       for i := 0; i < b.lines.Len(); i++ {
+               line := b.Line(i);
+               print("(", i, ") ");
+               for j := 0; j < line.Len(); j++ {
+                       w := line.At(j).(int);
+                       print("[", string(b.buf.a[pos : pos + w]), "]");
+                       pos += w;
+               }
+               print("\n");
+       }
+       print("\n");
+}
+
+
+var Blanks = &[]byte{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}
+var Newline = &[]byte{'\n'}
+
+func (b *TabWriter) WriteBlanks(n int) {
+       for n >= len(Blanks) {
+               m, err := b.writer.Write(Blanks);
+               n -= len(Blanks);
+       }
+       m, err := b.writer.Write(Blanks[0 : n]);
+}
+
+
+func (b *TabWriter) PrintLines(pos int, line0, line1 int) int {
+       for i := line0; i < line1; i++ {
+               line := b.Line(i);
+               for j := 0; j < line.Len(); j++ {
+                       w := line.At(j).(int);
+                       m, err := b.writer.Write(b.buf.a[pos : pos + w]);
+                       if m != w {
+                               panic();
+                       }
+                       pos += w;
+                       if j < b.widths.Len() {
+                               b.WriteBlanks(b.widths.At(j).(int) - w);
+                       }
+               }
+               m, err := b.writer.Write(Newline);
+       }
+       return pos;
+}
+
+
+func (b *TabWriter) Format(pos int, line0, line1 int) int {
+       column := b.widths.Len();
+       
+       last := line0;
+       for this := line0; this < line1; this++ {
+               line := b.Line(this);
+               
+               if column < line.Len() - 1 {
+                       // cell exists in this column
+                       // (note that the last cell per line is ignored)
+                       
+                       // print unprinted lines until beginning of block
+                       pos = b.PrintLines(pos, last, this);
+                       last = this;
+                       
+                       // column block begin
+                       width := b.tabwidth;  // minimal width
+                       for ; this < line1; this++ {
+                               line = b.Line(this);
+                               if column < line.Len() - 1 {
+                                       // cell exists in this column
+                                       // update width
+                                       w := line.At(column).(int) + 1; // 1 = minimum space between cells
+                                       if w > width {
+                                               width = w;
+                                       }
+                               } else {
+                                       break
+                               }
+                       }
+                       // column block end
+
+                       // format and print all columns to the right of this column
+                       // (we know the widths of this column and all columns to the left)
+                       b.widths.Append(width);
+                       pos = b.Format(pos, last, this);
+                       b.widths.Remove(b.widths.Len() - 1);
+                       last = this;
+               }
+       }
+
+       // print unprinted lines until end
+       return b.PrintLines(pos, last, line1);
+}
+
+
+func (b *TabWriter) EmptyLine() bool {
+       return b.LastLine().Len() == 0 && b.width == 0;
+}
+
+
+func (b *TabWriter) Tab() {
+       b.LastLine().Append(b.width);
+       b.width = 0;
+}
+
+
+func (b *TabWriter) Newline() {
+       b.Tab();  // add last cell to current line
+       
+       if b.LastLine().Len() == 1 {
+               // The current line has only one cell which does not have an impact
+               // on the formatting of the following lines (the last cell per line
+               // is ignored by Format), thus we can print the TabWriter contents.
+               if b.widths.Len() != 0 {
+                       panic();
+               }
+               //b.Dump();
+               b.Format(0, 0, b.lines.Len());
+               if b.widths.Len() != 0 {
+                       panic();
+               }
+               
+               // reset the TabWriter
+               b.width = 0;
+               b.buf.Clear();
+               b.lines.Reset();
+       }
+       
+       b.AddLine();
+}
+
+
+func (b *TabWriter) Write(buf *[]byte) (i int, err *OS.Error) {
+       i0, n := 0, len(buf);
+       for i = 0; i < n; i++ {
+               switch buf[i] {
+               case '\t':
+                       b.width += i - i0;
+                       b.buf.Append(buf[i0 : i]);
+                       i0 = i + 1;  // don't append '\t'
+                       b.Tab();
+               case '\n':
+                       b.width += i - i0;
+                       b.buf.Append(buf[i0 : i]);
+                       i0 = i + 1;  // don't append '\n'
+                       b.Newline();
+               }
+       }
+       b.width += n - i0;
+       b.buf.Append(buf[i0 : n]);
+       return i, nil;
+}
+
+
+export func MakeTabWriter(writer IO.Write, tabwidth int) IO.Write {
+       b := new(TabWriter);
+       b.Init(writer, tabwidth);
+       return b;
+}