mirror of https://github.com/golang/go.git
- steps towards "flexible tab stops" simulation in pretty
printing output - not yet enabled R=r OCL=18842 CL=18842
This commit is contained in:
parent
4328d44254
commit
a3b4a3c29d
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
pos int; // actual output position
|
||||
|
||||
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 {
|
||||
for i := P.newl; i > 0; i-- {
|
||||
print("\n");
|
||||
if NEW_CODE {
|
||||
P.buf.Flush();
|
||||
}
|
||||
for i := P.indent; i > 0; i-- {
|
||||
print("\t");
|
||||
for i := P.newl; i > 0; i-- {
|
||||
if NEW_CODE {
|
||||
P.buf.Newline();
|
||||
} else {
|
||||
print("\n");
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
Loading…
Reference in New Issue