platform.6: utils.6
-printer.6: scanner.6 ast.6
+printer.6: scanner.6 ast.6 tabwriter.6
+
%.6: %.go
$(G) $(F) $<
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();
}
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 {
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");
}
-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
}
+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");
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");
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;
}
}
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;
func (P *Printer) Tab() {
- P.String(0, "");
- P.buf.Tab();
+ P.String(0, "\t");
}
P.Expr(d.ident);
if d.typ != nil {
- P.Blank();
+ if d.tok != Scanner.FUNC {
+ P.Blank();
+ }
P.Type(d.typ);
}
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;
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;
--- /dev/null
+// 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;
+}