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
exvar.install: fmt.install http.install io.install log.install strconv.install sync.install
flag.install: fmt.install os.install strconv.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/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/token.install: strconv.install
hash.install: io.install
......
......@@ -33,6 +33,7 @@ DIRS=\
go/ast\
go/doc\
go/parser\
go/printer\
go/scanner\
go/token\
hash\
......
......@@ -34,21 +34,14 @@ coverage: packages
O1=\
ast.$O\
O2=\
format.$O\
phases: a1 a2
phases: a1
_obj$D/ast.a: phases
a1: $(O1)
$(AR) grc _obj$D/ast.a ast.$O
rm -f $(O1)
a2: $(O2)
$(AR) grc _obj$D/ast.a format.$O
rm -f $(O2)
newpkg: clean
mkdir -p _obj$D
......@@ -56,7 +49,6 @@ newpkg: clean
$(O1): newpkg
$(O2): a1
$(O3): a2
nuke: clean
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 @@
include $(GOROOT)/src/Make.$(GOARCH)
all: untab godoc pretty
untab: untab.$O
$(LD) -o untab untab.$O
all: godoc gofmt
godoc: godoc.$O
$(LD) -o godoc godoc.$O
pretty: pretty.$O
$(LD) -o pretty pretty.$O
gofmt: gofmt.$O
$(LD) -o gofmt gofmt.$O
test: pretty
test: gofmt
./test.sh
smoketest: pretty
./test.sh astprinter.go
smoketest: gofmt
./test.sh $(GOROOT)/src/pkg/go/printer/printer.go
install: pretty godoc untab
cp godoc $(HOME)/bin/godoc
cp pretty $(HOME)/bin/pretty
cp untab $(HOME)/bin/untab
cp gofmt $(HOME)/bin/gofmt
clean:
rm -f pretty untab godoc *.$O *.a 6.out *~
godoc.$O: astprinter.$O
pretty.$O: astprinter.$O
rm -f godoc gofmt *.$O *.a 6.out *~
%.$O: %.go
$(GC) $(F) $<
This diff is collapsed.
......@@ -33,6 +33,7 @@ import (
"go/ast";
"go/doc";
"go/parser";
"go/printer";
"go/token";
"http";
"io";
......@@ -47,8 +48,6 @@ import (
"tabwriter";
"template";
"time";
"astprinter"; // TODO remove eventually in favor of ast.Fprint
)
......@@ -90,7 +89,6 @@ var (
// layout control
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");
// server control
......@@ -129,11 +127,7 @@ func isPkgDir(dir *os.Dir) bool {
func makeTabwriter(writer io.Writer) *tabwriter.Writer {
padchar := byte(' ');
if *usetabs {
padchar = '\t';
}
return tabwriter.NewWriter(writer, *tabwidth, 1, padchar, tabwriter.FilterHTML);
return tabwriter.NewWriter(writer, *tabwidth, 1, byte(' '), 0);
}
......@@ -203,22 +197,12 @@ func parse(path string, mode uint) (*ast.Program, *parseErrors) {
// ----------------------------------------------------------------------------
// Templates
// Return text for decl.
func DeclText(d ast.Decl) []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 {
// Return text for an AST node.
func nodeText(node interface{}, mode uint) []byte {
var buf io.ByteBuffer;
var p astPrinter.Printer;
p.Init(&buf, nil, nil, false);
d.Visit(&p);
tw := makeTabwriter(&buf);
printer.Fprint(tw, node, mode);
tw.Flush();
return buf.Data();
}
......@@ -235,9 +219,9 @@ func toText(x interface{}) []byte {
case String:
return io.StringBytes(v.String());
case ast.Decl:
return DeclText(v);
return nodeText(v, printer.ExportsOnly);
case ast.Expr:
return ExprText(v);
return nodeText(v, printer.ExportsOnly);
}
var buf io.ByteBuffer;
fmt.Fprint(&buf, x);
......@@ -247,23 +231,7 @@ func toText(x interface{}) []byte {
// Template formatter for "html" format.
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) {
var buf io.ByteBuffer;
fmt.Fprintln(&buf, "<pre>");
var p astPrinter.Printer;
writer := makeTabwriter(&buf); // for nicely formatted output
p.Init(writer, nil, nil, true);
p.DoProgram(prog);
writer.Flush(); // ignore errors
template.HtmlEscape(&buf, nodeText(prog, printer.DocComments));
fmt.Fprintln(&buf, "</pre>");
servePage(c, name + " - Go source", buf.Data());
......
......@@ -5,12 +5,10 @@
package main
import (
"astprinter"; // TODO remove once go/printer is fully functional
"flag";
"fmt";
"go/ast";
"go/parser";
"go/token";
"go/printer";
"io";
"os";
"sort";
......@@ -20,32 +18,49 @@ import (
var (
// operation modes
columns bool;
// TODO remove silent flag eventually, can achieve same by proving no format file
silent = flag.Bool("s", false, "silent mode: no pretty print output");
silent = flag.Bool("s", false, "silent mode: parsing only");
verbose = flag.Bool("v", false, "verbose mode: trace parsing");
exports = flag.Bool("x", false, "show exports only");
// layout control
format = flag.String("format", "", "format file");
tabwidth = flag.Int("tabwidth", 4, "tab width");
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() {
fmt.Fprintf(os.Stderr, "usage: pretty { flags } { files }\n");
fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [file.go]\n");
flag.PrintDefaults();
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 {
padchar := byte(' ');
if *usetabs {
......@@ -56,68 +71,37 @@ func makeTabwriter(writer io.Writer) *tabwriter.Writer {
func main() {
// handle flags
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);
var filename string;
switch flag.NArg() {
case 0: filename = "/dev/stdin";
case 1: filename = flag.Arg(0);
default: usage();
}
// determine parsing mode
mode := parser.ParseComments;
if *verbose {
mode |= parser.Trace;
src, err := io.ReadFile(filename);
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %v\n", filename, err);
os.Exit(1);
}
// process files
exitcode := 0;
for i := 0; i < flag.NArg(); i++ {
filename := flag.Arg(i);
src, err := io.ReadFile(filename);
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %v\n", filename, err);
exitcode = 1;
continue; // proceed with next file
}
prog, err := parser.Parse(src, mode);
if err != nil {
if errors, ok := err.(parser.ErrorList); ok {
sort.Sort(errors);
for _, e := range errors {
fmt.Fprintf(os.Stderr, "%s:%v\n", filename, e);
}
} else {
fmt.Fprintf(os.Stderr, "%s: %v\n", filename, err);
}
exitcode = 1;
continue; // proceed with next file
}
if !*silent {
tw := makeTabwriter(os.Stdout);
if *format != "" {
_, err := astFormat.Fprint(tw, prog);
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);
prog, err := parser.Parse(src, parserMode());
if err != nil {
if errors, ok := err.(parser.ErrorList); ok {
sort.Sort(errors);
for _, e := range errors {
fmt.Fprintf(os.Stderr, "%s:%v\n", filename, e);
}
tw.Flush();
} else {
fmt.Fprintf(os.Stderr, "%s: %v\n", filename, err);
}
os.Exit(1);
}
os.Exit(exitcode);
if !*silent {
w := makeTabwriter(os.Stdout);
printer.Fprint(w, prog, printerMode());
w.Flush();
}
}
......@@ -10,7 +10,7 @@ if [ -z "$O" ]; then
exit 1
fi
CMD="./pretty -format=ast.txt"
CMD="./gofmt"
TMP1=test_tmp1.go
TMP2=test_tmp2.go
TMP3=test_tmp3.go
......@@ -34,7 +34,7 @@ apply1() {
# the following have semantic errors: bug039.go | bug040.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 | \
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;;
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