Commit a893db87 authored by Robert Griesemer's avatar Robert Griesemer

gofmt (final resting place TBD):

- replacement for pretty; app to format a single .go file

printer.go (pkg/go/printer):
- replacement for astprinter.go; implements AST printing
- also replaces pkg/go/ast/format.go for now

cleanups:
- removed/saved away old code

R=r,rsc,iant
DELTA=2833  (1183 added, 1628 deleted, 22 changed)
OCL=30226
CL=30306
parent c2faeac8
...@@ -16,9 +16,10 @@ exec.install: os.install strings.install ...@@ -16,9 +16,10 @@ exec.install: os.install strings.install
exvar.install: fmt.install http.install io.install log.install strconv.install sync.install exvar.install: fmt.install http.install io.install log.install strconv.install sync.install
flag.install: fmt.install os.install strconv.install flag.install: fmt.install os.install strconv.install
fmt.install: io.install os.install reflect.install strconv.install utf8.install fmt.install: io.install os.install reflect.install strconv.install utf8.install
go/ast.install: datafmt.install go/token.install io.install os.install unicode.install utf8.install go/ast.install: go/token.install unicode.install utf8.install
go/doc.install: container/vector.install fmt.install go/ast.install go/token.install io.install once.install regexp.install sort.install strings.install template.install go/doc.install: container/vector.install fmt.install go/ast.install go/token.install io.install once.install regexp.install sort.install strings.install template.install
go/parser.install: container/vector.install fmt.install go/ast.install go/scanner.install go/token.install io.install os.install go/parser.install: container/vector.install fmt.install go/ast.install go/scanner.install go/token.install io.install os.install
go/printer.install: fmt.install go/ast.install go/token.install io.install os.install reflect.install
go/scanner.install: go/token.install strconv.install unicode.install utf8.install go/scanner.install: go/token.install strconv.install unicode.install utf8.install
go/token.install: strconv.install go/token.install: strconv.install
hash.install: io.install hash.install: io.install
......
...@@ -33,6 +33,7 @@ DIRS=\ ...@@ -33,6 +33,7 @@ DIRS=\
go/ast\ go/ast\
go/doc\ go/doc\
go/parser\ go/parser\
go/printer\
go/scanner\ go/scanner\
go/token\ go/token\
hash\ hash\
......
...@@ -34,21 +34,14 @@ coverage: packages ...@@ -34,21 +34,14 @@ coverage: packages
O1=\ O1=\
ast.$O\ ast.$O\
O2=\
format.$O\
phases: a1
phases: a1 a2
_obj$D/ast.a: phases _obj$D/ast.a: phases
a1: $(O1) a1: $(O1)
$(AR) grc _obj$D/ast.a ast.$O $(AR) grc _obj$D/ast.a ast.$O
rm -f $(O1) rm -f $(O1)
a2: $(O2)
$(AR) grc _obj$D/ast.a format.$O
rm -f $(O2)
newpkg: clean newpkg: clean
mkdir -p _obj$D mkdir -p _obj$D
...@@ -56,7 +49,6 @@ newpkg: clean ...@@ -56,7 +49,6 @@ newpkg: clean
$(O1): newpkg $(O1): newpkg
$(O2): a1 $(O2): a1
$(O3): a2
nuke: clean nuke: clean
rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/ast.a rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/ast.a
......
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ast
import (
"datafmt";
"go/ast";
"go/token";
"io";
"os";
)
// Format is a customized datafmt.Format for printing of ASTs.
type Format datafmt.Format;
// ----------------------------------------------------------------------------
// Custom formatters
// The AST-specific formatting state is maintained by a state variable.
type state struct {
// for now we have very little state
// TODO maintain list of unassociated comments
optSemi bool
}
func (s *state) Copy() datafmt.Environment {
copy := *s;
return ©
}
func isValidPos(s *datafmt.State, value interface{}, ruleName string) bool {
pos := value.(token.Position);
return pos.IsValid();
}
func isSend(s *datafmt.State, value interface{}, ruleName string) bool {
return value.(ast.ChanDir) & ast.SEND != 0;
}
func isRecv(s *datafmt.State, value interface{}, ruleName string) bool {
return value.(ast.ChanDir) & ast.RECV != 0;
}
func isMultiLineComment(s *datafmt.State, value interface{}, ruleName string) bool {
return value.([]byte)[1] == '*';
}
func clearOptSemi(s *datafmt.State, value interface{}, ruleName string) bool {
s.Env().(*state).optSemi = false;
return true;
}
func setOptSemi(s *datafmt.State, value interface{}, ruleName string) bool {
s.Env().(*state).optSemi = true;
return true;
}
func optSemi(s *datafmt.State, value interface{}, ruleName string) bool {
if !s.Env().(*state).optSemi {
s.Write([]byte{';'});
}
return true;
}
var fmap = datafmt.FormatterMap {
"isValidPos": isValidPos,
"isSend": isSend,
"isRecv": isRecv,
"isMultiLineComment": isMultiLineComment,
"/": clearOptSemi,
"clearOptSemi": clearOptSemi,
"setOptSemi": setOptSemi,
"optSemi": optSemi,
}
// ----------------------------------------------------------------------------
// Printing
// NewFormat parses a datafmt format specification from a file
// and adds AST-specific custom formatter rules. The result is
// the customized format or an os.Error, if any.
//
func NewFormat(filename string) (Format, os.Error) {
src, err := io.ReadFile(filename);
if err != nil {
return nil, err;
}
f, err := datafmt.Parse(src, fmap);
return Format(f), err;
}
// Fprint formats each AST node provided as argument according to the
// format f and writes to standard output. The result is the total number
// of bytes written and an os.Error, if any.
//
func (f Format) Fprint(w io.Writer, nodes ...) (int, os.Error) {
var s state;
return datafmt.Format(f).Fprint(w, &s, nodes);
}
// Fprint formats each AST node provided as argument according to the
// format f and writes to w. The result is the total number of bytes
// written and an os.Error, if any.
//
func (f Format) Print(nodes ...) (int, os.Error) {
return f.Fprint(os.Stdout, nodes);
}
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# DO NOT EDIT. Automatically generated by gobuild.
# gobuild -m >Makefile
D=/go/
include $(GOROOT)/src/Make.$(GOARCH)
AR=gopack
default: packages
clean:
rm -rf *.[$(OS)] *.a [$(OS)].out _obj
test: packages
gotest
coverage: packages
gotest
6cov -g `pwd` | grep -v '_test\.go:'
%.$O: %.go
$(GC) -I_obj $*.go
%.$O: %.c
$(CC) $*.c
%.$O: %.s
$(AS) $*.s
O1=\
printer.$O\
phases: a1
_obj$D/printer.a: phases
a1: $(O1)
$(AR) grc _obj$D/printer.a printer.$O
rm -f $(O1)
newpkg: clean
mkdir -p _obj$D
$(AR) grc _obj$D/printer.a
$(O1): newpkg
$(O2): a1
nuke: clean
rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/printer.a
packages: _obj$D/printer.a
install: packages
test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D
cp _obj$D/printer.a $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/printer.a
This diff is collapsed.
...@@ -4,34 +4,26 @@ ...@@ -4,34 +4,26 @@
include $(GOROOT)/src/Make.$(GOARCH) include $(GOROOT)/src/Make.$(GOARCH)
all: untab godoc pretty all: godoc gofmt
untab: untab.$O
$(LD) -o untab untab.$O
godoc: godoc.$O godoc: godoc.$O
$(LD) -o godoc godoc.$O $(LD) -o godoc godoc.$O
pretty: pretty.$O gofmt: gofmt.$O
$(LD) -o pretty pretty.$O $(LD) -o gofmt gofmt.$O
test: pretty test: gofmt
./test.sh ./test.sh
smoketest: pretty smoketest: gofmt
./test.sh astprinter.go ./test.sh $(GOROOT)/src/pkg/go/printer/printer.go
install: pretty godoc untab install: pretty godoc untab
cp godoc $(HOME)/bin/godoc cp godoc $(HOME)/bin/godoc
cp pretty $(HOME)/bin/pretty cp gofmt $(HOME)/bin/gofmt
cp untab $(HOME)/bin/untab
clean: clean:
rm -f pretty untab godoc *.$O *.a 6.out *~ rm -f godoc gofmt *.$O *.a 6.out *~
godoc.$O: astprinter.$O
pretty.$O: astprinter.$O
%.$O: %.go %.$O: %.go
$(GC) $(F) $< $(GC) $(F) $<
This diff is collapsed.
...@@ -33,6 +33,7 @@ import ( ...@@ -33,6 +33,7 @@ import (
"go/ast"; "go/ast";
"go/doc"; "go/doc";
"go/parser"; "go/parser";
"go/printer";
"go/token"; "go/token";
"http"; "http";
"io"; "io";
...@@ -47,8 +48,6 @@ import ( ...@@ -47,8 +48,6 @@ import (
"tabwriter"; "tabwriter";
"template"; "template";
"time"; "time";
"astprinter"; // TODO remove eventually in favor of ast.Fprint
) )
...@@ -90,7 +89,6 @@ var ( ...@@ -90,7 +89,6 @@ var (
// layout control // layout control
tabwidth = flag.Int("tabwidth", 4, "tab width"); tabwidth = flag.Int("tabwidth", 4, "tab width");
usetabs = flag.Bool("tabs", false, "align with tabs instead of spaces");
html = flag.Bool("html", false, "print HTML in command-line mode"); html = flag.Bool("html", false, "print HTML in command-line mode");
// server control // server control
...@@ -129,11 +127,7 @@ func isPkgDir(dir *os.Dir) bool { ...@@ -129,11 +127,7 @@ func isPkgDir(dir *os.Dir) bool {
func makeTabwriter(writer io.Writer) *tabwriter.Writer { func makeTabwriter(writer io.Writer) *tabwriter.Writer {
padchar := byte(' '); return tabwriter.NewWriter(writer, *tabwidth, 1, byte(' '), 0);
if *usetabs {
padchar = '\t';
}
return tabwriter.NewWriter(writer, *tabwidth, 1, padchar, tabwriter.FilterHTML);
} }
...@@ -203,22 +197,12 @@ func parse(path string, mode uint) (*ast.Program, *parseErrors) { ...@@ -203,22 +197,12 @@ func parse(path string, mode uint) (*ast.Program, *parseErrors) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Templates // Templates
// Return text for decl. // Return text for an AST node.
func DeclText(d ast.Decl) []byte { func nodeText(node interface{}, mode uint) []byte {
var buf io.ByteBuffer;
var p astPrinter.Printer;
p.Init(&buf, nil, nil, false);
d.Visit(&p);
return buf.Data();
}
// Return text for expr.
func ExprText(d ast.Expr) []byte {
var buf io.ByteBuffer; var buf io.ByteBuffer;
var p astPrinter.Printer; tw := makeTabwriter(&buf);
p.Init(&buf, nil, nil, false); printer.Fprint(tw, node, mode);
d.Visit(&p); tw.Flush();
return buf.Data(); return buf.Data();
} }
...@@ -235,9 +219,9 @@ func toText(x interface{}) []byte { ...@@ -235,9 +219,9 @@ func toText(x interface{}) []byte {
case String: case String:
return io.StringBytes(v.String()); return io.StringBytes(v.String());
case ast.Decl: case ast.Decl:
return DeclText(v); return nodeText(v, printer.ExportsOnly);
case ast.Expr: case ast.Expr:
return ExprText(v); return nodeText(v, printer.ExportsOnly);
} }
var buf io.ByteBuffer; var buf io.ByteBuffer;
fmt.Fprint(&buf, x); fmt.Fprint(&buf, x);
...@@ -247,23 +231,7 @@ func toText(x interface{}) []byte { ...@@ -247,23 +231,7 @@ func toText(x interface{}) []byte {
// Template formatter for "html" format. // Template formatter for "html" format.
func htmlFmt(w io.Writer, x interface{}, format string) { func htmlFmt(w io.Writer, x interface{}, format string) {
// Can do better than text in some cases.
switch v := x.(type) {
case ast.Decl:
var p astPrinter.Printer;
tw := makeTabwriter(w);
p.Init(tw, nil, nil, true);
v.Visit(&p);
tw.Flush();
case ast.Expr:
var p astPrinter.Printer;
tw := makeTabwriter(w);
p.Init(tw, nil, nil, true);
v.Visit(&p);
tw.Flush();
default:
template.HtmlEscape(w, toText(x)); template.HtmlEscape(w, toText(x));
}
} }
...@@ -363,11 +331,7 @@ func serveGoSource(c *http.Conn, name string) { ...@@ -363,11 +331,7 @@ func serveGoSource(c *http.Conn, name string) {
var buf io.ByteBuffer; var buf io.ByteBuffer;
fmt.Fprintln(&buf, "<pre>"); fmt.Fprintln(&buf, "<pre>");
var p astPrinter.Printer; template.HtmlEscape(&buf, nodeText(prog, printer.DocComments));
writer := makeTabwriter(&buf); // for nicely formatted output
p.Init(writer, nil, nil, true);
p.DoProgram(prog);
writer.Flush(); // ignore errors
fmt.Fprintln(&buf, "</pre>"); fmt.Fprintln(&buf, "</pre>");
servePage(c, name + " - Go source", buf.Data()); servePage(c, name + " - Go source", buf.Data());
......
...@@ -5,12 +5,10 @@ ...@@ -5,12 +5,10 @@
package main package main
import ( import (
"astprinter"; // TODO remove once go/printer is fully functional
"flag"; "flag";
"fmt"; "fmt";
"go/ast";
"go/parser"; "go/parser";
"go/token"; "go/printer";
"io"; "io";
"os"; "os";
"sort"; "sort";
...@@ -20,32 +18,49 @@ import ( ...@@ -20,32 +18,49 @@ import (
var ( var (
// operation modes // operation modes
columns bool; silent = flag.Bool("s", false, "silent mode: parsing only");
// TODO remove silent flag eventually, can achieve same by proving no format file
silent = flag.Bool("s", false, "silent mode: no pretty print output");
verbose = flag.Bool("v", false, "verbose mode: trace parsing"); verbose = flag.Bool("v", false, "verbose mode: trace parsing");
exports = flag.Bool("x", false, "show exports only");
// layout control // layout control
format = flag.String("format", "", "format file");
tabwidth = flag.Int("tabwidth", 4, "tab width"); tabwidth = flag.Int("tabwidth", 4, "tab width");
usetabs = flag.Bool("tabs", false, "align with tabs instead of blanks"); usetabs = flag.Bool("tabs", false, "align with tabs instead of blanks");
optcommas = flag.Bool("optcommas", false, "print optional commas");
optsemis = flag.Bool("optsemis", false, "print optional semicolons");
) )
func init() {
user, err := os.Getenv("USER");
flag.BoolVar(&columns, "columns", user == "gri", "print column no. in error messages");
}
func usage() { func usage() {
fmt.Fprintf(os.Stderr, "usage: pretty { flags } { files }\n"); fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [file.go]\n");
flag.PrintDefaults(); flag.PrintDefaults();
os.Exit(1); os.Exit(1);
} }
// TODO(gri) move this function into tabwriter.go? (also used in godoc) func parserMode() uint {
mode := parser.ParseComments;
if *verbose {
mode |= parser.Trace;
}
return mode;
}
func printerMode() uint {
mode := uint(0);
if *exports {
mode |= printer.ExportsOnly;
}
if *optcommas {
mode |= printer.OptCommas;
}
if *optsemis {
mode |= printer.OptSemis;
}
return mode;
}
func makeTabwriter(writer io.Writer) *tabwriter.Writer { func makeTabwriter(writer io.Writer) *tabwriter.Writer {
padchar := byte(' '); padchar := byte(' ');
if *usetabs { if *usetabs {
...@@ -56,38 +71,22 @@ func makeTabwriter(writer io.Writer) *tabwriter.Writer { ...@@ -56,38 +71,22 @@ func makeTabwriter(writer io.Writer) *tabwriter.Writer {
func main() { func main() {
// handle flags
flag.Parse(); flag.Parse();
if flag.NFlag() == 0 && flag.NArg() == 0 {
usage();
}
// initialize astFormat
astFormat, err := ast.NewFormat(*format);
if *format != "" && err != nil { // ignore error if no format file given
fmt.Fprintf(os.Stderr, "ast.NewFormat(%s): %v\n", *format, err);
os.Exit(1);
}
// determine parsing mode var filename string;
mode := parser.ParseComments; switch flag.NArg() {
if *verbose { case 0: filename = "/dev/stdin";
mode |= parser.Trace; case 1: filename = flag.Arg(0);
default: usage();
} }
// process files
exitcode := 0;
for i := 0; i < flag.NArg(); i++ {
filename := flag.Arg(i);
src, err := io.ReadFile(filename); src, err := io.ReadFile(filename);
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "%s: %v\n", filename, err); fmt.Fprintf(os.Stderr, "%s: %v\n", filename, err);
exitcode = 1; os.Exit(1);
continue; // proceed with next file
} }
prog, err := parser.Parse(src, mode); prog, err := parser.Parse(src, parserMode());
if err != nil { if err != nil {
if errors, ok := err.(parser.ErrorList); ok { if errors, ok := err.(parser.ErrorList); ok {
sort.Sort(errors); sort.Sort(errors);
...@@ -97,27 +96,12 @@ func main() { ...@@ -97,27 +96,12 @@ func main() {
} else { } else {
fmt.Fprintf(os.Stderr, "%s: %v\n", filename, err); fmt.Fprintf(os.Stderr, "%s: %v\n", filename, err);
} }
exitcode = 1; os.Exit(1);
continue; // proceed with next file
} }
if !*silent { if !*silent {
tw := makeTabwriter(os.Stdout); w := makeTabwriter(os.Stdout);
if *format != "" { printer.Fprint(w, prog, printerMode());
_, err := astFormat.Fprint(tw, prog); w.Flush();
if err != nil {
fmt.Fprintf(os.Stderr, "format error: %v\n", err);
exitcode = 1;
continue; // proceed with next file
}
} else {
var p astPrinter.Printer;
p.Init(tw, nil, nil /*prog.Comments*/, false);
p.DoProgram(prog);
}
tw.Flush();
} }
}
os.Exit(exitcode);
} }
...@@ -10,7 +10,7 @@ if [ -z "$O" ]; then ...@@ -10,7 +10,7 @@ if [ -z "$O" ]; then
exit 1 exit 1
fi fi
CMD="./pretty -format=ast.txt" CMD="./gofmt"
TMP1=test_tmp1.go TMP1=test_tmp1.go
TMP2=test_tmp2.go TMP2=test_tmp2.go
TMP3=test_tmp3.go TMP3=test_tmp3.go
...@@ -34,7 +34,7 @@ apply1() { ...@@ -34,7 +34,7 @@ apply1() {
# the following have semantic errors: bug039.go | bug040.go # the following have semantic errors: bug039.go | bug040.go
test_errors.go | calc.go | method1.go | selftest1.go | func3.go | const2.go | \ test_errors.go | calc.go | method1.go | selftest1.go | func3.go | const2.go | \
bug014.go | bug025.go | bug029.go | bug032.go | bug039.go | bug040.go | bug050.go | bug068.go | \ bug014.go | bug025.go | bug029.go | bug032.go | bug039.go | bug040.go | bug050.go | bug068.go | \
bug088.go | bug083.go | bug106.go | bug121.go | bug125.go | bug126.go | bug132.go | bug133.go | bug134.go ) ;; bug088.go | bug083.go | bug106.go | bug121.go | bug125.go | bug126.go | bug132.go | bug133.go | bug134.go | bug160.go ) ;;
* ) $1 $2; count $F;; * ) $1 $2; count $F;;
esac esac
} }
......
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"flag";
"fmt";
"io";
"os";
"tabwriter";
)
var (
tabwidth = flag.Int("tabwidth", 4, "tab width");
usetabs = flag.Bool("usetabs", false, "align with tabs instead of blanks");
)
func error(format string, params ...) {
fmt.Printf(format, params);
os.Exit(1);
}
func untab(name string, src *os.File, dst *tabwriter.Writer) {
n, err := io.Copy(src, dst);
if err != nil {
error("error while processing %s (%v)", name, err);
}
//dst.Flush();
}
func main() {
flag.Parse();
padchar := byte(' ');
if *usetabs {
padchar = '\t';
}
dst := tabwriter.NewWriter(os.Stdout, *tabwidth, 1, padchar, 0);
if flag.NArg() > 0 {
for i := 0; i < flag.NArg(); i++ {
name := flag.Arg(i);
src, err := os.Open(name, os.O_RDONLY, 0);
if err != nil {
error("could not open %s (%v)\n", name, err);
}
untab(name, src, dst);
src.Close(); // ignore errors
}
} else {
// no files => use stdin
untab("/dev/stdin", os.Stdin, dst);
}
}
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