// Disabled formatting - enable eventually and remove the flag.
const (
- oneLineFuncDecls = false;
- compositeLitBlank = false;
- stringListMode = exprListMode(0); // previously: noIndent
+ oneLineFuncDecls = false;
+ compositeLitBlank = false;
+ stringListMode = exprListMode(0); // previously: noIndent
)
func (p *printer) linebreak(line, min, max int, ws whiteSpace, newSection bool) (printedBreak bool) {
n := line - p.pos.Line;
switch {
- case n < min: n = min;
- case n > max: n = max;
+ case n < min:
+ n = min;
+ case n > max:
+ n = max;
}
if n > 0 {
p.print(ws);
}
-type exprListMode uint;
+type exprListMode uint
+
const (
- blankStart exprListMode = 1 << iota; // print a blank before the list
- commaSep; // elements are separated by commas
- commaTerm; // elements are terminated by comma
- noIndent; // no extra indentation in multi-line lists
+ blankStart exprListMode = 1<<iota; // print a blank before the list
+ commaSep; // elements are separated by commas
+ commaTerm; // elements are terminated by comma
+ noIndent; // no extra indentation in multi-line lists
)
// all list entries on a single line
for i, x := range list {
if i > 0 {
- if mode & commaSep != 0 {
+ if mode&commaSep != 0 {
p.print(token.COMMA);
}
p.print(blank);
prev := line;
line = x.Pos().Line;
if i > 0 {
- if mode & commaSep != 0 {
+ if mode&commaSep != 0 {
p.print(token.COMMA);
}
if prev < line {
// expression list - be conservative and check anyway
p.print(unindent);
}
- p.print(formfeed); // terminating comma needs a line break to look good
+ p.print(formfeed); // terminating comma needs a line break to look good
} else if ws == ignore && mode&noIndent == 0 {
p.print(unindent);
}
p.print("// contains unexported fields");
}
- } else { // interface
+ } else { // interface
var ml bool;
for i, f := range list {
return false;
case *ast.IndexExpr:
// index expressions don't need blanks if the indexed expressions are simple
- return needsBlanks(x.X)
+ return needsBlanks(x.X);
case *ast.CallExpr:
// call expressions need blanks if they have more than one
// argument or if the function expression needs blanks
p.print(blank);
}
p.print(x.Lbrace, token.LBRACE);
- p.exprList(x.Lbrace, x.Elts, commaSep|commaTerm, multiLine);
+ p.exprList(x.Lbrace, x.Elts, commaSep | commaTerm, multiLine);
p.print(x.Rbrace, token.RBRACE);
case *ast.Ellipsis:
// ----------------------------------------------------------------------------
// Statements
-const maxStmtNewlines = 2 // maximum number of newlines between statements
+const maxStmtNewlines = 2 // maximum number of newlines between statements
// Print the statement list indented, but without a newline after the last statement.
// Extra line breaks between statements in the source are respected but at most one
case *ast.DeclStmt:
p.decl(s.Decl, inStmtList, multiLine);
- optSemi = true; // decl prints terminating semicolon if necessary
+ optSemi = true; // decl prints terminating semicolon if necessary
case *ast.EmptyStmt:
// nothing to do
}
p.print(s.Colon, token.COLON);
p.stmtList(s.Body, 1);
- optSemi = true; // "block" without {}'s
+ optSemi = true; // "block" without {}'s
case *ast.SwitchStmt:
p.print(token.SWITCH);
}
p.print(s.Colon, token.COLON);
p.stmtList(s.Body, 1);
- optSemi = true; // "block" without {}'s
+ optSemi = true; // "block" without {}'s
case *ast.TypeSwitchStmt:
p.print(token.SWITCH);
}
p.print(s.Colon, token.COLON);
p.stmtList(s.Body, 1);
- optSemi = true; // "block" without {}'s
+ optSemi = true; // "block" without {}'s
case *ast.SelectStmt:
p.print(token.SELECT, blank);
// ----------------------------------------------------------------------------
// Declarations
-type declContext uint;
+type declContext uint
+
const (
- atTop declContext = iota;
+ atTop declContext = iota;
inGroup;
inStmtList;
)
//
func (p *printer) spec(spec ast.Spec, n int, context declContext, multiLine *bool) {
var (
- optSemi bool; // true if a semicolon is optional
- comment *ast.CommentGroup; // a line comment, if any
- extraTabs int; // number of extra tabs before comment, if any
+ optSemi bool; // true if a semicolon is optional
+ comment *ast.CommentGroup; // a line comment, if any
+ extraTabs int; // number of extra tabs before comment, if any
)
switch s := spec.(type) {
case *ast.ValueSpec:
p.leadComment(s.Doc);
- p.identList(s.Names, multiLine); // always present
+ p.identList(s.Names, multiLine); // always present
if n == 1 {
if s.Type != nil {
p.print(blank);
func (p *printer) isOneLiner(b *ast.BlockStmt) bool {
switch {
case len(b.List) > 1 || p.commentBefore(b.Rbrace):
- return false; // too many statements or there is a comment - all bets are off
+ return false; // too many statements or there is a comment - all bets are off
case len(b.List) == 0:
- return true; // empty block and no comments
+ return true; // empty block and no comments
}
// test-print the statement and see if it would fit
var buf bytes.Buffer;
_, err := p.Config.Fprint(&buf, b.List[0]);
if err != nil {
- return false; // don't try
+ return false; // don't try
}
if buf.Len() > 40 {
- return false; // too long
+ return false; // too long
}
for _, ch := range buf.Bytes() {
if ch < ' ' {
- return false; // contains control chars (tabs, newlines)
+ return false; // contains control chars (tabs, newlines)
}
}
// ----------------------------------------------------------------------------
// Files
-const maxDeclNewlines = 3 // maximum number of newlines between declarations
+const maxDeclNewlines = 3 // maximum number of newlines between declarations
func declToken(decl ast.Decl) (tok token.Token) {
tok = token.ILLEGAL;
const (
- debug = false; // enable for debugging
- maxNewlines = 3; // maximum vertical white space
+ debug = false; // enable for debugging
+ maxNewlines = 3; // maximum vertical white space
)
type whiteSpace int
const (
- ignore = whiteSpace(0);
- blank = whiteSpace(' ');
- vtab = whiteSpace('\v');
- newline = whiteSpace('\n');
- formfeed = whiteSpace('\f');
- indent = whiteSpace('>');
- unindent = whiteSpace('<');
+ ignore = whiteSpace(0);
+ blank = whiteSpace(' ');
+ vtab = whiteSpace('\v');
+ newline = whiteSpace('\n');
+ formfeed = whiteSpace('\f');
+ indent = whiteSpace('>');
+ unindent = whiteSpace('<');
)
var (
- esc = []byte{tabwriter.Escape};
- htab = []byte{'\t'};
- htabs = [...]byte{'\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t'};
- newlines = [...]byte{'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'}; // more than maxNewlines
-
- esc_quot = strings.Bytes("""); // shorter than """
- esc_apos = strings.Bytes("'"); // shorter than "'"
- esc_amp = strings.Bytes("&");
- esc_lt = strings.Bytes("<");
- esc_gt = strings.Bytes(">");
+ esc = []byte{tabwriter.Escape};
+ htab = []byte{'\t'};
+ htabs = [...]byte{'\t', '\t', '\t', '\t', '\t', '\t', '\t', '\t'};
+ newlines = [...]byte{'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'}; // more than maxNewlines
+
+ esc_quot = strings.Bytes("""); // shorter than """
+ esc_apos = strings.Bytes("'"); // shorter than "'"
+ esc_amp = strings.Bytes("&");
+ esc_lt = strings.Bytes("<");
+ esc_gt = strings.Bytes(">");
)
// Use ignoreMultiLine if the multiLine information is not important.
-var ignoreMultiLine = new(bool);
+var ignoreMultiLine = new(bool)
type printer struct {
// Configuration (does not change after initialization)
- output io.Writer;
+ output io.Writer;
Config;
- errors chan os.Error;
+ errors chan os.Error;
// Current state
- written int; // number of bytes written
- indent int; // current indentation
- escape bool; // true if in escape sequence
+ written int; // number of bytes written
+ indent int; // current indentation
+ escape bool; // true if in escape sequence
// Buffered whitespace
- buffer []whiteSpace;
+ buffer []whiteSpace;
// The (possibly estimated) position in the generated output;
// in AST space (i.e., pos is set whenever a token position is
// known accurately, and updated dependending on what has been
// written)
- pos token.Position;
+ pos token.Position;
// The value of pos immediately after the last item has been
// written using writeItem.
- last token.Position;
+ last token.Position;
// HTML support
- lastTaggedLine int; // last line for which a line tag was written
+ lastTaggedLine int; // last line for which a line tag was written
// The list of comments; or nil.
- comment *ast.CommentGroup;
+ comment *ast.CommentGroup;
}
p.output = output;
p.Config = *cfg;
p.errors = make(chan os.Error);
- p.buffer = make([]whiteSpace, 0, 16); // whitespace sequences are short
+ p.buffer = make([]whiteSpace, 0, 16); // whitespace sequences are short
}
p.write0(data[i0 : i+1]);
// update p.pos
- p.pos.Offset += i+1 - i0;
+ p.pos.Offset += i+1-i0;
p.pos.Line++;
p.pos.Column = 1;
case '"', '\'', '&', '<', '>':
if p.Mode & GenHTML != 0 {
// write segment ending in b
- p.write0(data[i0 : i]);
+ p.write0(data[i0:i]);
// write HTML-escaped b
var esc []byte;
switch b {
- case '"': esc = esc_quot;
- case '\'': esc = esc_apos;
- case '&': esc = esc_amp;
- case '<': esc = esc_lt;
- case '>': esc = esc_gt;
+ case '"':
+ esc = esc_quot;
+ case '\'':
+ esc = esc_apos;
+ case '&':
+ esc = esc_amp;
+ case '<':
+ esc = esc_lt;
+ case '>':
+ esc = esc_gt;
}
p.write0(esc);
// update p.pos
- d := i+1 - i0;
+ d := i+1-i0;
p.pos.Offset += d;
p.pos.Column += d;
}
// write remaining segment
- p.write0(data[i0 : len(data)]);
+ p.write0(data[i0:len(data)]);
// update p.pos
- d := len(data) - i0;
+ d := len(data)-i0;
p.pos.Offset += d;
p.pos.Column += d;
}
if n > maxNewlines {
n = maxNewlines;
}
- p.write(newlines[0 : n]);
+ p.write(newlines[0:n]);
}
}
i := 0;
for j, c := range text {
if c == '\n' {
- lines[n] = text[i:j]; // exclude newline
- i = j+1; // discard newline
+ lines[n] = text[i:j]; // exclude newline
+ i = j+1; // discard newline
n++;
}
}
for i < len(a) && i < len(b) && a[i] == b[i] && (a[i] <= ' ' || a[i] == '*') {
i++;
}
- return a[0 : i];
+ return a[0:i];
}
func stripCommonPrefix(lines [][]byte) {
if len(lines) < 2 {
- return; // at most one line - nothing to do
+ return; // at most one line - nothing to do
}
-
+
// The heuristic in this function tries to handle a few
// common patterns of /*-style comments: Comments where
// the opening /* and closing */ are aligned and the
if i := bytes.Index(prefix, []byte{'*'}); i >= 0 {
// Line of stars present.
if i > 0 && prefix[i-1] == ' ' {
- i--; // remove trailing blank from prefix so stars remain aligned
+ i--; // remove trailing blank from prefix so stars remain aligned
}
prefix = prefix[0:i];
lineOfStars = true;
// for the opening /*, assume up to 3 blanks or a tab. This
// whitespace may be found as suffix in the common prefix.
first := lines[0];
- if isBlank(first[2 : len(first)]) {
+ if isBlank(first[2:len(first)]) {
// no comment text on the first line:
// reduce prefix by up to 3 blanks or a tab
// if present - this keeps comment text indented
// Shorten the computed common prefix by the length of
// suffix, if it is found as suffix of the prefix.
if bytes.HasSuffix(prefix, suffix) {
- prefix = prefix[0 : len(prefix) - len(suffix)];
+ prefix = prefix[0 : len(prefix)-len(suffix)];
}
}
}
// Remove the common prefix from all but the first and empty lines.
for i, line := range lines {
if i > 0 && len(line) != 0 {
- lines[i] = line[len(prefix) : len(line)];
+ lines[i] = line[len(prefix):len(line)];
}
}
}
// of lines before the label; effectively leading to wrong
// indentation.
p.buffer[i], p.buffer[i+1] = unindent, formfeed;
- i--; // do it again
+ i--; // do it again
continue;
}
fallthrough;
for i := 0; i < v.NumField(); i++ {
f := v.Field(i);
- next := p.pos; // estimated position of next item
+ next := p.pos; // estimated position of next item
var data []byte;
var tag HtmlTag;
isKeyword := false;
// (note that valid Go programs cannot contain esc ('\xff')
// bytes since they do not appear in legal UTF-8 sequences)
// TODO(gri): this this more efficiently.
- data = strings.Bytes("\xff" + string(data) + "\xff");
+ data = strings.Bytes("\xff"+string(data)+"\xff");
case token.Token:
if p.Styler != nil {
data, tag = p.Styler.Token(x);
isKeyword = x.IsKeyword();
case token.Position:
if x.IsValid() {
- next = x; // accurate position of next item
+ next = x; // accurate position of next item
}
default:
panicln("print: unsupported argument type", f.Type().String());
// is used).
//
type trimmer struct {
- output io.Writer;
- buf bytes.Buffer;
+ output io.Writer;
+ buf bytes.Buffer;
}
}
case '\v':
- b = '\t'; // convert to htab
+ b = '\t'; // convert to htab
fallthrough;
case '\t', ' ', tabwriter.Escape:
}
// collect whitespace but discard tabrwiter.Escapes.
if b != tabwriter.Escape {
- p.buf.WriteByte(b); // WriteByte returns no errors
+ p.buf.WriteByte(b); // WriteByte returns no errors
}
case '\f', '\n':
// General printing is controlled with these Config.Mode flags.
const (
- GenHTML uint = 1 << iota; // generate HTML
- RawFormat; // do not use a tabwriter; if set, UseSpaces is ignored
- UseSpaces; // use spaces instead of tabs for indentation and alignment
+ GenHTML uint = 1<<iota; // generate HTML
+ RawFormat; // do not use a tabwriter; if set, UseSpaces is ignored
+ UseSpaces; // use spaces instead of tabs for indentation and alignment
)
// An HtmlTag specifies a start and end tag.
type HtmlTag struct {
- Start, End string; // empty if tags are absent
+ Start, End string; // empty if tags are absent
}
//
type Styler interface {
LineTag(line int) ([]byte, HtmlTag);
- Comment(c *ast.Comment, line []byte) ([]byte, HtmlTag);
- BasicLit(x *ast.BasicLit) ([]byte, HtmlTag);
- Ident(id *ast.Ident) ([]byte, HtmlTag);
- Token(tok token.Token) ([]byte, HtmlTag);
+ Comment(c *ast.Comment, line []byte) ([]byte, HtmlTag);
+ BasicLit(x *ast.BasicLit) ([]byte, HtmlTag);
+ Ident(id *ast.Ident) ([]byte, HtmlTag);
+ Token(tok token.Token) ([]byte, HtmlTag);
}
// A Config node controls the output of Fprint.
type Config struct {
- Mode uint; // default: 0
- Tabwidth int; // default: 8
- Styler Styler; // default: nil
+ Mode uint; // default: 0
+ Tabwidth int; // default: 8
+ Styler Styler; // default: nil
}
p.errors <- os.NewError(fmt.Sprintf("printer.Fprint: unsupported node type %T", n));
runtime.Goexit();
}
- p.flush(token.Position{Offset: 1<<30, Line: 1<<30}, false); // flush to "infinity"
- p.errors <- nil; // no errors
+ p.flush(token.Position{Offset: 1<<30, Line: 1<<30}, false); // flush to "infinity"
+ p.errors <- nil; // no errors
}();
- err := <-p.errors; // wait for completion of goroutine
+ err := <-p.errors; // wait for completion of goroutine
// flush tabwriter, if any
if tw != nil {
- tw.Flush(); // ignore errors
+ tw.Flush(); // ignore errors
}
return p.written, err;
// It calls Config.Fprint with default settings.
//
func Fprint(output io.Writer, node interface{}) os.Error {
- _, err := (&Config{Tabwidth: 8}).Fprint(output, node); // don't care about number of bytes written
+ _, err := (&Config{Tabwidth: 8}).Fprint(output, node); // don't care about number of bytes written
return err;
}
const (
- dataDir = "testdata";
- tabwidth = 8;
+ dataDir = "testdata";
+ tabwidth = 8;
)
-var update = flag.Bool("update", false, "update golden files");
+var update = flag.Bool("update", false, "update golden files")
func lineString(text []byte, i int) string {
for i < len(text) && text[i] != '\n' {
i++;
}
- return string(text[i0 : i]);
+ return string(text[i0:i]);
}
-type checkMode uint;
+type checkMode uint
+
const (
- export checkMode = 1<<iota;
+ export checkMode = 1<<iota;
rawFormat;
)
// filter exports if necessary
if mode&export != 0 {
- ast.FileExports(prog); // ignore result
- prog.Comments = nil; // don't print comments that are not in AST
+ ast.FileExports(prog); // ignore result
+ prog.Comments = nil; // don't print comments that are not in AST
}
// determine printer configuration
cfg := Config{Tabwidth: tabwidth};
- if mode&rawFormat != 0 {
+ if mode & rawFormat != 0 {
cfg.Mode |= RawFormat;
}
type entry struct {
- source, golden string;
- mode checkMode;
+ source, golden string;
+ mode checkMode;
}
// Use gotest -update to create/update the respective golden files.
var data = []entry{
- entry{ "empty.input", "empty.golden", 0 },
- entry{ "comments.input", "comments.golden", 0 },
- entry{ "comments.input", "comments.x", export },
- entry{ "linebreaks.input", "linebreaks.golden", 0 },
- entry{ "expressions.input", "expressions.golden", 0 },
- entry{ "expressions.input", "expressions.raw", rawFormat },
- entry{ "declarations.input", "declarations.golden", 0 },
- entry{ "statements.input", "statements.golden", 0 },
+ entry{"empty.input", "empty.golden", 0},
+ entry{"comments.input", "comments.golden", 0},
+ entry{"comments.input", "comments.x", export},
+ entry{"linebreaks.input", "linebreaks.golden", 0},
+ entry{"expressions.input", "expressions.golden", 0},
+ entry{"expressions.input", "expressions.raw", rawFormat},
+ entry{"declarations.input", "declarations.golden", 0},
+ entry{"statements.input", "statements.golden", 0},
}