mirror of
https://github.com/golang/go
synced 2024-11-12 06:30:21 -07: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:
parent
337af31781
commit
654bc2badc
@ -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) $<
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
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;
|
||||
|
@ -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
285
usr/gri/pretty/tabwriter.go
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user