1
0
mirror of https://github.com/golang/go synced 2024-09-24 23:10:12 -06:00

- factored out tabwriter a separate writer filter

(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
This commit is contained in:
Robert Griesemer 2008-11-17 19:58:52 -08:00
parent 337af31781
commit 654bc2badc
5 changed files with 326 additions and 195 deletions

View 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) $<

View 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 {

View 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;

View 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;

285
usr/gri/pretty/tabwriter.go Normal file
View File

@ -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;
}