Commit a3b4a3c2 authored by Robert Griesemer's avatar Robert Griesemer

- steps towards "flexible tab stops" simulation in pretty

  printing output
- not yet enabled

R=r
OCL=18842
CL=18842
parent 4328d442
......@@ -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;
}
}
}
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
}
......@@ -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();
......
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