Commit 654bc2ba authored by Robert Griesemer's avatar Robert Griesemer

- 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
parent 337af317
...@@ -32,7 +32,8 @@ parser.6: scanner.6 ast.6 ...@@ -32,7 +32,8 @@ parser.6: scanner.6 ast.6
platform.6: utils.6 platform.6: utils.6
printer.6: scanner.6 ast.6 printer.6: scanner.6 ast.6 tabwriter.6
%.6: %.go %.6: %.go
$(G) $(F) $< $(G) $(F) $<
...@@ -469,8 +469,14 @@ func (P *Parser) ParseFunctionType() *AST.Type { ...@@ -469,8 +469,14 @@ func (P *Parser) ParseFunctionType() *AST.Type {
func (P *Parser) ParseMethodSpec(list *AST.List) { func (P *Parser) ParseMethodSpec(list *AST.List) {
P.Trace("MethodDecl"); P.Trace("MethodDecl");
list.Add(P.ParseIdent()); list.Add(P.ParseIdentList());
list.Add(AST.NewTypeExpr(P.ParseFunctionType())); t := AST.BadType;
if P.sixg {
t = P.ParseType();
} else {
t = P.ParseFunctionType();
}
list.Add(AST.NewTypeExpr(t));
P.Ecart(); P.Ecart();
} }
...@@ -1485,7 +1491,8 @@ func (P *Parser) ParseDeclaration() *AST.Decl { ...@@ -1485,7 +1491,8 @@ func (P *Parser) ParseDeclaration() *AST.Decl {
d := AST.BadDecl; d := AST.BadDecl;
exported := false; 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 { if P.scope_lev == 0 {
exported = true; exported = true;
} else { } else {
......
...@@ -9,6 +9,9 @@ import Scanner "scanner" ...@@ -9,6 +9,9 @@ import Scanner "scanner"
import AST "ast" import AST "ast"
import Flag "flag" import Flag "flag"
import Fmt "fmt" import Fmt "fmt"
import IO "io"
import OS "os"
import TabWriter "tabwriter"
var tabwith = Flag.Int("tabwidth", 4, nil, "tab width"); var tabwith = Flag.Int("tabwidth", 4, nil, "tab width");
var comments = Flag.Bool("comments", false, nil, "enable printing of comments"); var comments = Flag.Bool("comments", false, nil, "enable printing of comments");
...@@ -24,180 +27,11 @@ func assert(p bool) { ...@@ -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 // Printer
export type Printer struct { export type Printer struct {
buf Buffer; writer IO.Write;
// formatting control // formatting control
lastpos int; // pos after last string lastpos int; // pos after last string
...@@ -213,13 +47,18 @@ export type Printer struct { ...@@ -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) { func (P *Printer) String(pos int, s string) {
if pos == 0 { if pos == 0 {
pos = P.lastpos; // estimate pos = P.lastpos; // estimate
} }
if P.semi && P.level > 0 { // no semicolons at level 0 if P.semi && P.level > 0 { // no semicolons at level 0
P.buf.Print(";"); P.Printf(";");
} }
//print("--", pos, "[", s, "]\n"); //print("--", pos, "[", s, "]\n");
...@@ -238,26 +77,25 @@ func (P *Printer) String(pos int, s string) { ...@@ -238,26 +77,25 @@ func (P *Printer) String(pos int, s string) {
case Scanner.COMMENT_BB: case Scanner.COMMENT_BB:
// black space before and after comment on the same line // black space before and after comment on the same line
// - print surrounded by blanks // - print surrounded by blanks
P.buf.Print(" "); P.Printf(" %s ", text);
P.buf.Print(text);
P.buf.Print(" ");
case Scanner.COMMENT_BW: case Scanner.COMMENT_BW:
// only white space after comment on the same line // only white space after comment on the same line
// - put into next cell // - put into next cell
P.buf.Tab(); P.Printf("\t%s", text);
P.buf.Print(text);
case Scanner.COMMENT_WW, Scanner.COMMENT_WB: case Scanner.COMMENT_WW, Scanner.COMMENT_WB:
// only white space before comment on the same line // only white space before comment on the same line
// - indent // - indent
/*
if !P.buf.EmptyLine() { if !P.buf.EmptyLine() {
P.buf.Newline(); P.buf.Newline();
} }
*/
for i := P.indent; i > 0; i-- { for i := P.indent; i > 0; i-- {
P.buf.Tab(); P.Printf("\t");
} }
P.buf.Print(text); P.Printf("%s", text);
default: default:
panic("UNREACHABLE"); panic("UNREACHABLE");
...@@ -266,9 +104,9 @@ func (P *Printer) String(pos int, s string) { ...@@ -266,9 +104,9 @@ func (P *Printer) String(pos int, s string) {
if text[1] == '/' { if text[1] == '/' {
// line comments must end in newline // line comments must end in newline
// TODO should we set P.newl instead? // TODO should we set P.newl instead?
P.buf.Newline(); P.Printf("\n");
for i := P.indent; i > 0; i-- { for i := P.indent; i > 0; i-- {
P.buf.Tab(); P.Printf("\t");
} }
at_line_begin = true; at_line_begin = true;
} }
...@@ -286,19 +124,18 @@ func (P *Printer) String(pos int, s string) { ...@@ -286,19 +124,18 @@ func (P *Printer) String(pos int, s string) {
} }
if P.newl > 0 { if P.newl > 0 {
P.buf.Newline(); P.Printf("\n");
if P.newl > 1 { if P.newl > 1 {
for i := P.newl; i > 1; i-- { for i := P.newl; i > 1; i-- {
//P.buf.Flush(); P.Printf("\n");
P.buf.Newline();
} }
} }
for i := P.indent; i > 0; i-- { 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.lastpos = pos + len(s);
P.semi, P.newl = false, 0; P.semi, P.newl = false, 0;
...@@ -311,8 +148,7 @@ func (P *Printer) Blank() { ...@@ -311,8 +148,7 @@ func (P *Printer) Blank() {
func (P *Printer) Tab() { func (P *Printer) Tab() {
P.String(0, ""); P.String(0, "\t");
P.buf.Tab();
} }
...@@ -712,7 +548,9 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) { ...@@ -712,7 +548,9 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) {
P.Expr(d.ident); P.Expr(d.ident);
if d.typ != nil { if d.typ != nil {
P.Blank(); if d.tok != Scanner.FUNC {
P.Blank();
}
P.Type(d.typ); P.Type(d.typ);
} }
...@@ -756,7 +594,7 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) { ...@@ -756,7 +594,7 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) {
func (P *Printer) Program(p *AST.Program) { func (P *Printer) Program(p *AST.Program) {
// TODO should initialize all fields? // TODO should initialize all fields?
P.buf.Init(); P.writer = TabWriter.MakeTabWriter(OS.Stdout, 4);
P.clist = p.comments; P.clist = p.comments;
P.cindex = 0; P.cindex = 0;
......
...@@ -22,14 +22,14 @@ var ( ...@@ -22,14 +22,14 @@ var (
func main() { func main() {
// the prolog // the prologue
for i := 0; i <= 10 /* limit */; i++ { for i := 0; i <= 10 /* limit */; i++ {
println(i); // the index println(i); // the index
println(i + 1); // the index + 1 println(i + 1); // the index + 1
println(i + 1000); // the index + 1000 println(i + 1000); // the index + 1000
println(); println();
} }
// the epilog // the epilogue
println("foo"); // foo println("foo"); // foo
println("foobar"); // foobar println("foobar"); // foobar
var x int; var x int;
......
// 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;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment