Commit cb67a832 authored by Robert Griesemer's avatar Robert Griesemer

- fine-tuning of white space

- by default consider extra newlines in src for better formatting
- additional flags for control (-newlines, -maxnewlines, -optsemicolons)
- don't print ()'s around single anonymous result types

Status: Comparing the output of pretty with the input for larger files
shows mostly whitespace/formatting differences, which is what is desired.

TODO:
- Handling of overlong lines
- some esoteric cases which look funny

R=r
OCL=20293
CL=20293
parent 1e1a3c50
...@@ -16,16 +16,23 @@ import ( ...@@ -16,16 +16,23 @@ import (
var ( var (
debug = flag.Bool("debug", false, nil, "print debugging information"); debug = flag.Bool("debug", false, nil, "print debugging information");
// layout control
tabwidth = flag.Int("tabwidth", 8, nil, "tab width"); tabwidth = flag.Int("tabwidth", 8, nil, "tab width");
usetabs = flag.Bool("usetabs", true, nil, "align with tabs instead of blanks"); usetabs = flag.Bool("usetabs", true, nil, "align with tabs instead of blanks");
comments = flag.Bool("comments", true, nil, "enable printing of comments"); newlines = flag.Bool("newlines", true, nil, "respect newlines in source");
maxnewlines = flag.Int("maxnewlines", 3, nil, "max. number of consecutive newlines");
// formatting control
comments = flag.Bool("comments", true, nil, "print comments");
optsemicolons = flag.Bool("optsemicolons", false, nil, "print optional semicolons");
) )
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Printer // Printer
// Separators are printed in a delayed fashion, depending on the next token. // Separators - printed in a delayed fashion, depending on context.
const ( const (
none = iota; none = iota;
blank; blank;
...@@ -35,11 +42,12 @@ const ( ...@@ -35,11 +42,12 @@ const (
) )
// Formatting actions control formatting parameters during printing. // Semantic states - control formatting.
const ( const (
no_action = iota; normal = iota;
open_scope; opening_scope; // controls indentation, scope level
close_scope; closing_scope; // controls indentation, scope level
inside_list; // controls extra line breaks
) )
...@@ -61,9 +69,14 @@ type Printer struct { ...@@ -61,9 +69,14 @@ type Printer struct {
separator int; // pending separator separator int; // pending separator
newlines int; // pending newlines newlines int; // pending newlines
// formatting action // semantic state
action int; // action executed on formatting parameters state int; // current semantic state
lastaction int; // action for last string laststate int; // state for last string
}
func (P *Printer) HasComment(pos int) bool {
return comments.BVal() && P.cpos < pos;
} }
...@@ -90,7 +103,7 @@ func (P *Printer) Init(writer *tabwriter.Writer, comments *array.Array) { ...@@ -90,7 +103,7 @@ func (P *Printer) Init(writer *tabwriter.Writer, comments *array.Array) {
P.cindex = -1; P.cindex = -1;
P.NextComment(); P.NextComment();
// formatting parameters & action initialized correctly by default // formatting parameters & semantic state initialized correctly by default
} }
...@@ -106,10 +119,10 @@ func (P *Printer) Printf(format string, s ...) { ...@@ -106,10 +119,10 @@ func (P *Printer) Printf(format string, s ...) {
func (P *Printer) Newline(n int) { func (P *Printer) Newline(n int) {
const maxnl = 2;
if n > 0 { if n > 0 {
if n > maxnl { m := int(maxnewlines.IVal());
n = maxnl; if n > m {
n = m;
} }
for ; n > 0; n-- { for ; n > 0; n-- {
P.Printf("\n"); P.Printf("\n");
...@@ -122,14 +135,16 @@ func (P *Printer) Newline(n int) { ...@@ -122,14 +135,16 @@ func (P *Printer) Newline(n int) {
func (P *Printer) String(pos int, s string) { func (P *Printer) String(pos int, s string) {
// correct pos if necessary // use estimate for pos if we don't have one
if pos == 0 { if pos == 0 {
pos = P.lastpos; // estimate pos = P.lastpos;
} }
// -------------------------------- // --------------------------------
// print pending separator, if any // print pending separator, if any
// - keep track of white space printed for better comment formatting // - keep track of white space printed for better comment formatting
// TODO print white space separators after potential comments and newlines
// (currently, we may get trailing white space before a newline)
trailing_char := 0; trailing_char := 0;
switch P.separator { switch P.separator {
case none: // nothing to do case none: // nothing to do
...@@ -160,7 +175,7 @@ func (P *Printer) String(pos int, s string) { ...@@ -160,7 +175,7 @@ func (P *Printer) String(pos int, s string) {
// -------------------------------- // --------------------------------
// interleave comments, if any // interleave comments, if any
nlcount := 0; nlcount := 0;
for comments.BVal() && P.cpos < pos { for ; P.HasComment(pos); P.NextComment() {
// we have a comment/newline that comes before the string // we have a comment/newline that comes before the string
comment := P.comments.At(P.cindex).(*AST.Comment); comment := P.comments.At(P.cindex).(*AST.Comment);
ctext := comment.text; ctext := comment.text;
...@@ -176,7 +191,12 @@ func (P *Printer) String(pos int, s string) { ...@@ -176,7 +191,12 @@ func (P *Printer) String(pos int, s string) {
// only white space before comment on this line // only white space before comment on this line
// or file starts with comment // or file starts with comment
// - indent // - indent
if !newlines.BVal() && P.cpos != 0 {
nlcount = 1;
}
P.Newline(nlcount); P.Newline(nlcount);
nlcount = 0;
} else { } else {
// black space before comment on this line // black space before comment on this line
if ctext[1] == '/' { if ctext[1] == '/' {
...@@ -184,7 +204,7 @@ func (P *Printer) String(pos int, s string) { ...@@ -184,7 +204,7 @@ func (P *Printer) String(pos int, s string) {
// - put in next cell unless a scope was just opened // - put in next cell unless a scope was just opened
// in which case we print 2 blanks (otherwise the // in which case we print 2 blanks (otherwise the
// entire scope gets indented like the next cell) // entire scope gets indented like the next cell)
if P.lastaction == open_scope { if P.laststate == opening_scope {
switch trailing_char { switch trailing_char {
case ' ': P.Printf(" "); // one space already printed case ' ': P.Printf(" "); // one space already printed
case '\t': // do nothing case '\t': // do nothing
...@@ -205,6 +225,7 @@ func (P *Printer) String(pos int, s string) { ...@@ -205,6 +225,7 @@ func (P *Printer) String(pos int, s string) {
} }
} }
// print comment
if debug.BVal() { if debug.BVal() {
P.Printf("[%d]", P.cpos); P.Printf("[%d]", P.cpos);
} }
...@@ -216,33 +237,36 @@ func (P *Printer) String(pos int, s string) { ...@@ -216,33 +237,36 @@ func (P *Printer) String(pos int, s string) {
P.newlines = 1; P.newlines = 1;
} }
} }
nlcount = 0;
} }
P.NextComment();
} }
// At this point we may have nlcount > 0: In this case we found newlines
// that were not followed by a comment. They are recognized (or not) when
// printing newlines below.
// -------------------------------- // --------------------------------
// handle extra newlines // interpret state
if nlcount > 0 {
P.newlines += nlcount - 1;
}
// --------------------------------
// interpret control
// (any pending separator or comment must be printed in previous state) // (any pending separator or comment must be printed in previous state)
switch P.action { switch P.state {
case none: case normal:
case open_scope: case opening_scope:
case close_scope: case closing_scope:
P.indentation--; P.indentation--;
case inside_list:
default: default:
panic("UNREACHABLE"); panic("UNREACHABLE");
} }
// -------------------------------- // --------------------------------
// adjust formatting depending on state // print pending newlines
if newlines.BVal() && (P.newlines > 0 || P.state == inside_list) && nlcount > P.newlines {
// Respect additional newlines in the source, but only if we
// enabled this feature (newlines.BVal()) and we are expecting
// newlines (P.newlines > 0 || P.state == inside_list).
// Otherwise - because we don't have all token positions - we
// get funny formatting.
P.newlines = nlcount;
}
nlcount = 0;
P.Newline(P.newlines); P.Newline(P.newlines);
P.newlines = 0; P.newlines = 0;
...@@ -254,20 +278,20 @@ func (P *Printer) String(pos int, s string) { ...@@ -254,20 +278,20 @@ func (P *Printer) String(pos int, s string) {
P.Printf("%s", s); P.Printf("%s", s);
// -------------------------------- // --------------------------------
// interpret control // interpret state
switch P.action { switch P.state {
case none: case normal:
case open_scope: case opening_scope:
P.level++; P.level++;
P.indentation++; P.indentation++;
//P.newlines = 1; case closing_scope:
case close_scope:
P.level--; P.level--;
case inside_list:
default: default:
panic("UNREACHABLE"); panic("UNREACHABLE");
} }
P.lastaction = P.action; P.laststate = P.state;
P.action = none; P.state = none;
// -------------------------------- // --------------------------------
// done // done
...@@ -321,7 +345,7 @@ func (P *Printer) Parameters(pos int, list *array.Array) { ...@@ -321,7 +345,7 @@ func (P *Printer) Parameters(pos int, list *array.Array) {
func (P *Printer) Fields(list *array.Array, end int) { func (P *Printer) Fields(list *array.Array, end int) {
P.action = open_scope; P.state = opening_scope;
P.String(0, "{"); P.String(0, "{");
if list != nil { if list != nil {
...@@ -345,7 +369,7 @@ func (P *Printer) Fields(list *array.Array, end int) { ...@@ -345,7 +369,7 @@ func (P *Printer) Fields(list *array.Array, end int) {
P.newlines = 1; P.newlines = 1;
} }
P.action = close_scope; P.state = closing_scope;
P.String(end, "}"); P.String(end, "}");
} }
...@@ -394,7 +418,13 @@ func (P *Printer) Type(t *AST.Type) { ...@@ -394,7 +418,13 @@ func (P *Printer) Type(t *AST.Type) {
P.Parameters(t.pos, t.list); P.Parameters(t.pos, t.list);
if t.elt != nil { if t.elt != nil {
P.separator = blank; P.separator = blank;
P.Parameters(0, t.elt.list); list := t.elt.list;
if list.Len() > 1 {
P.Parameters(0, list);
} else {
// single, anonymous result type
P.Expr(list.At(0).(*AST.Expr));
}
} }
case Scanner.ELLIPSIS: case Scanner.ELLIPSIS:
...@@ -438,6 +468,7 @@ func (P *Printer) Expr1(x *AST.Expr, prec1 int) { ...@@ -438,6 +468,7 @@ func (P *Printer) Expr1(x *AST.Expr, prec1 int) {
P.Expr(x.x); P.Expr(x.x);
P.String(x.pos, ","); P.String(x.pos, ",");
P.separator = blank; P.separator = blank;
P.state = inside_list;
P.Expr(x.y); P.Expr(x.y);
case Scanner.PERIOD: case Scanner.PERIOD:
...@@ -522,7 +553,7 @@ func (P *Printer) StatementList(list *array.Array) { ...@@ -522,7 +553,7 @@ func (P *Printer) StatementList(list *array.Array) {
func (P *Printer) Block(pos int, list *array.Array, end int, indent bool) { func (P *Printer) Block(pos int, list *array.Array, end int, indent bool) {
P.action = open_scope; P.state = opening_scope;
P.String(pos, "{"); P.String(pos, "{");
if !indent { if !indent {
P.indentation--; P.indentation--;
...@@ -531,8 +562,10 @@ func (P *Printer) Block(pos int, list *array.Array, end int, indent bool) { ...@@ -531,8 +562,10 @@ func (P *Printer) Block(pos int, list *array.Array, end int, indent bool) {
if !indent { if !indent {
P.indentation++; P.indentation++;
} }
P.separator = none; if !optsemicolons.BVal() {
P.action = close_scope; P.separator = none;
}
P.state = closing_scope;
P.String(end, "}"); P.String(end, "}");
} }
...@@ -651,6 +684,8 @@ func (P *Printer) Stat(s *AST.Stat) { ...@@ -651,6 +684,8 @@ func (P *Printer) Stat(s *AST.Stat) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Declarations // Declarations
// TODO This code is unreadable! Clean up AST and rewrite this.
func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) { func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) {
if !parenthesized { if !parenthesized {
if d.exported { if d.exported {
...@@ -662,7 +697,7 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) { ...@@ -662,7 +697,7 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) {
} }
if d.tok != Scanner.FUNC && d.list != nil { if d.tok != Scanner.FUNC && d.list != nil {
P.action = open_scope; P.state = opening_scope;
P.String(0, "("); P.String(0, "(");
if d.list.Len() > 0 { if d.list.Len() > 0 {
P.newlines = 1; P.newlines = 1;
...@@ -672,7 +707,7 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) { ...@@ -672,7 +707,7 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) {
P.newlines = 1; P.newlines = 1;
} }
} }
P.action = close_scope; P.state = closing_scope;
P.String(d.end, ")"); P.String(d.end, ")");
} else { } else {
...@@ -691,11 +726,12 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) { ...@@ -691,11 +726,12 @@ func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) {
P.separator = blank; P.separator = blank;
} }
P.Type(d.typ); P.Type(d.typ);
P.separator = tab;
} }
if d.val != nil { if d.val != nil {
P.String(0, "\t");
if d.tok != Scanner.IMPORT { if d.tok != Scanner.IMPORT {
P.separator = tab;
P.String(0, "="); P.String(0, "=");
P.separator = blank; P.separator = blank;
} }
......
...@@ -4,7 +4,25 @@ ...@@ -4,7 +4,25 @@
package main package main
import Fmt "fmt" import (
"array"; // not needed
"utf8"; // not needed
Fmt "fmt"
)
const /* enum */ (
EnumTag0 = iota;
EnumTag1;
EnumTag2;
EnumTag3;
EnumTag4;
EnumTag5;
EnumTag6;
EnumTag7;
EnumTag8;
EnumTag9;
)
type T struct { type T struct {
...@@ -29,6 +47,16 @@ func f0(a, b int) int { ...@@ -29,6 +47,16 @@ func f0(a, b int) int {
} }
func f1(tag int) {
switch tag {
case
EnumTag0, EnumTag1, EnumTag2, EnumTag3, EnumTag4,
EnumTag5, EnumTag6, EnumTag7, EnumTag8, EnumTag9: break;
default:
}
}
func main() { func main() {
// the prologue // the prologue
for i := 0; i <= 10 /* limit */; i++ { for i := 0; i <= 10 /* limit */; i++ {
......
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