summaryrefslogtreecommitdiff
path: root/usr
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2008-11-07 18:30:58 -0800
committerRobert Griesemer <gri@golang.org>2008-11-07 18:30:58 -0800
commit31af41abde3f455cd8a79f9bed6944a0fd52799e (patch)
tree1f44e7b493eec775ca1de63063ed04f21adfa4b7 /usr
parentdc89385174339cf91a5d5b1a8b24de2af3711cf1 (diff)
downloadgolang-31af41abde3f455cd8a79f9bed6944a0fd52799e.tar.gz
- steps towards "flexible tab stops" simulation in pretty
printing output - not yet enabled R=r OCL=18842 CL=18842
Diffstat (limited to 'usr')
-rw-r--r--usr/gri/pretty/ast.go12
-rw-r--r--usr/gri/pretty/parser.go9
-rw-r--r--usr/gri/pretty/printer.go164
-rw-r--r--usr/gri/pretty/scanner.go20
4 files changed, 179 insertions, 26 deletions
diff --git a/usr/gri/pretty/ast.go b/usr/gri/pretty/ast.go
index 91c61ec76..d566361bf 100644
--- a/usr/gri/pretty/ast.go
+++ b/usr/gri/pretty/ast.go
@@ -27,6 +27,11 @@ export type List struct {
}
+func (p *List) Init() {
+ p.a = new([] Any, 10) [0 : 0];
+}
+
+
func (p *List) len() int {
if p == nil { return 0; }
return len(p.a);
@@ -78,9 +83,14 @@ func (p *List) Pop() Any {
}
+func (p *List) Clear() {
+ p.a = p.a[0 : 0];
+}
+
+
export func NewList() *List {
p := new(List);
- p.a = new([] Any, 10) [0 : 0];
+ p.Init();
return p;
}
diff --git a/usr/gri/pretty/parser.go b/usr/gri/pretty/parser.go
index d9e7c921e..d091529c0 100644
--- a/usr/gri/pretty/parser.go
+++ b/usr/gri/pretty/parser.go
@@ -77,8 +77,13 @@ func (P *Parser) Next0() {
func (P *Parser) Next() {
- for P.Next0(); P.tok == Scanner.COMMENT; P.Next0() {
- P.comments.Add(AST.NewComment(P.pos, P.val));
+ P.Next0();
+ if P.tok == Scanner.COMMENT {
+ pos, s := P.pos, P.val;
+ for P.Next0(); P.tok == Scanner.COMMENT; P.Next0() {
+ s += P.val;
+ }
+ P.comments.Add(AST.NewComment(pos, s));
}
}
diff --git a/usr/gri/pretty/printer.go b/usr/gri/pretty/printer.go
index cd20adb89..4c886ad56 100644
--- a/usr/gri/pretty/printer.go
+++ b/usr/gri/pretty/printer.go
@@ -7,11 +7,128 @@ package Printer
import Strings "strings"
import Scanner "scanner"
import AST "ast"
+import Flag "flag"
+import Fmt "fmt"
+var tabwith = Flag.Int("tabwidth", 4, nil, "tab width");
+
+
+// ----------------------------------------------------------------------------
+// Support
+
+func assert(p bool) {
+ if !p {
+ panic("assert failed");
+ }
+}
+
+
+func PrintBlanks(n int) {
+ // TODO make this faster
+ for ; n > 0; n-- {
+ print(" ");
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// Implemententation of flexible tab stops.
+// (http://nickgravgaard.com/elastictabstops/index.html)
+
+type Buffer struct {
+ lines AST.List; // a list of lines; and each line is a list of strings
+ widths AST.List;
+}
+
+
+func (b *Buffer) Newline() {
+ b.lines.Add(AST.NewList());
+}
+
+
+func (b *Buffer) Init() {
+ b.lines.Init();
+ b.widths.Init();
+ b.Newline();
+}
+
+
+func (b *Buffer) ComputeWidths() {
+ // iterate through all columns j
+ for j := 0; ; j++ {
+ width := -1; // initial column width
+
+ // iterate through all lines i
+ for i := 0; i < b.lines.len(); i++ {
+ line := b.lines.at(i).(*AST.List);
+ if j < line.len() {
+ // the j.th column exists in this line
+ w := len(line.at(j).(string));
+ if w > width {
+ width = w;
+ }
+ }
+ }
+
+ if width >= 0 {
+ assert(b.widths.len() == j);
+ b.widths.Add(width);
+ } else {
+ // no column j - we are done
+ return;
+ }
+ }
+}
-export type Printer struct {
- pos int; // actual output position
+func (b *Buffer) Flush() {
+ b.ComputeWidths();
+
+ // print the lines
+ for i := 0; i < b.lines.len(); i++ {
+ line := b.lines.at(i).(*AST.List);
+ for j := 0; j < line.len(); j++ {
+ s := line.at(j).(string);
+ d := b.widths.at(j).(int) - len(s);
+ assert(d >= 0);
+ if d < int(tabwith.IVal()) {
+ d = int(tabwith.IVal());
+ }
+ PrintBlanks(d); // +1 padding
+ print(s);
+ }
+ println();
+ }
+
+ b.lines.Clear();
+ b.widths.Clear();
+ b.Newline();
+}
+
+
+func (b *Buffer) Indent(n int) {
+ line := b.lines.at(b.lines.len() - 1).(*AST.List);
+ for ; n > 0; n-- {
+ line.Add("");
+ }
+}
+
+
+func (b *Buffer) Print(s string) {
+ i := b.lines.len() - 1;
+ line := b.lines.at(i).(*AST.List);
+ j := line.len() - 1;
+ if j < 0 {
+ line.Add(s);
+ } else {
+ line.set(j, line.at(j).(string) + s);
+ }
+}
+
+
+export type Printer struct {
+ buf Buffer;
+
// formatting control
level int; // true scope level
indent int; // indentation level
@@ -25,24 +142,22 @@ export type Printer struct {
}
-// Bottleneck interface - all output goes through here.
-func (P *Printer) print(s string) {
- print(s);
- // TODO do we need the code below?
- // P.pos += Strings.utflen(s);
-}
-
+const NEW_CODE = false;
func (P *Printer) String(pos int, s string) {
if P.semi && P.level > 0 { // no semicolons at level 0
- print(";");
+ if NEW_CODE {
+ P.buf.Print(";");
+ } else {
+ print(";");
+ }
}
/*
for pos > P.cpos {
// we have a comment
c := P.clist.at(P.cindex).(*AST.Comment);
- if c.text[1] == '/' {
+ if len(c.text) > 1 && c.text[1] == '/' {
print(" " + c.text);
if P.newl <= 0 {
P.newl = 1; // line comments must have a newline
@@ -60,15 +175,30 @@ func (P *Printer) String(pos int, s string) {
*/
if P.newl > 0 {
+ if NEW_CODE {
+ P.buf.Flush();
+ }
for i := P.newl; i > 0; i-- {
- print("\n");
+ if NEW_CODE {
+ P.buf.Newline();
+ } else {
+ print("\n");
+ }
}
- for i := P.indent; i > 0; i-- {
- print("\t");
+ if NEW_CODE {
+ P.buf.Indent(P.indent);
+ } else {
+ for i := P.indent; i > 0; i-- {
+ print("\t");
+ }
}
}
- print(s);
+ if NEW_CODE {
+ P.buf.Print(s);
+ } else {
+ print(s);
+ }
P.semi, P.newl = false, 0;
}
@@ -519,6 +649,8 @@ 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.clist = p.comments;
P.cindex = 0;
if p.comments.len() > 0 {
@@ -527,6 +659,7 @@ func (P *Printer) Program(p *AST.Program) {
P.cpos = 1000000000; // infinite
}
+ // Print package
P.String(p.pos, "package ");
P.Expr(p.ident);
P.newl = 2;
@@ -534,5 +667,6 @@ func (P *Printer) Program(p *AST.Program) {
P.Declaration(p.decls.at(i), false);
}
P.newl = 1;
+
P.String(0, ""); // flush
}
diff --git a/usr/gri/pretty/scanner.go b/usr/gri/pretty/scanner.go
index 4b331b562..06428e9b6 100644
--- a/usr/gri/pretty/scanner.go
+++ b/usr/gri/pretty/scanner.go
@@ -109,7 +109,7 @@ export const (
export func TokenString(tok int) string {
- switch (tok) {
+ switch tok {
case ILLEGAL: return "ILLEGAL";
case IDENT: return "IDENT";
@@ -249,11 +249,6 @@ func init() {
}
-func is_whitespace(ch int) bool {
- return ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t';
-}
-
-
func is_letter(ch int) bool {
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 128 ;
}
@@ -524,12 +519,20 @@ func (S *Scanner) Expect(ch int) {
func (S *Scanner) SkipWhitespace() {
- for is_whitespace(S.ch) {
+ for S.ch == ' ' || S.ch == '\r' {
S.Next();
}
}
+func (S *Scanner) ScanWhitespace() string {
+ // first char ('\n' or '\t', 1 byte) already consumed
+ pos := S.chpos - 1;
+ S.SkipWhitespace();
+ return S.src[pos : S.chpos];
+}
+
+
func (S *Scanner) ScanComment() string {
// first '/' already consumed
pos := S.chpos - 1;
@@ -686,7 +689,7 @@ func (S *Scanner) ScanEscape(quote int) string {
ch := S.ch;
pos := S.chpos;
S.Next();
- switch (ch) {
+ switch ch {
case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\':
return string(ch);
@@ -825,6 +828,7 @@ func (S *Scanner) Scan() (pos, tok int, val string) {
S.Next(); // always make progress
switch ch {
case -1: tok = EOF;
+ case '\n', '\t': tok, val = COMMENT, S.ScanWhitespace();
case '"': tok, val = STRING, S.ScanString();
case '\'': tok, val = INT, S.ScanChar();
case '`': tok, val = STRING, S.ScanRawString();