Commit 8083467d authored by Robert Griesemer's avatar Robert Griesemer

- renamed format -> datafmt

- factored out datafmt-specifics from pretty to ast

R=rsc
DELTA=3580  (1810 added, 1763 deleted, 7 changed)
OCL=29770
CL=29774
parent da0a5825
...@@ -6,12 +6,12 @@ crypto/block.install: fmt.install io.install os.install ...@@ -6,12 +6,12 @@ crypto/block.install: fmt.install io.install os.install
crypto/hmac.install: crypto/md5.install crypto/sha1.install hash.install os.install crypto/hmac.install: crypto/md5.install crypto/sha1.install hash.install os.install
crypto/md5.install: hash.install os.install crypto/md5.install: hash.install os.install
crypto/sha1.install: hash.install os.install crypto/sha1.install: hash.install os.install
datafmt.install: container/vector.install fmt.install go/scanner.install go/token.install io.install os.install reflect.install runtime.install strconv.install strings.install
exec.install: os.install strings.install 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
format.install: container/vector.install flag.install fmt.install go/scanner.install go/token.install io.install os.install reflect.install runtime.install strconv.install strings.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/scanner.install: go/token.install strconv.install unicode.install utf8.install go/scanner.install: go/token.install strconv.install unicode.install utf8.install
......
...@@ -22,11 +22,11 @@ DIRS=\ ...@@ -22,11 +22,11 @@ DIRS=\
crypto/hmac\ crypto/hmac\
crypto/md5\ crypto/md5\
crypto/sha1\ crypto/sha1\
datafmt\
exec\ exec\
exvar\ exvar\
flag\ flag\
fmt\ fmt\
format\
go/ast\ go/ast\
go/doc\ go/doc\
go/parser\ go/parser\
...@@ -70,11 +70,11 @@ TEST=\ ...@@ -70,11 +70,11 @@ TEST=\
crypto/block\ crypto/block\
crypto/md5\ crypto/md5\
crypto/sha1\ crypto/sha1\
datafmt\
exec\ exec\
exvar\ exvar\
flag\ flag\
fmt\ fmt\
format\
go/parser\ go/parser\
go/scanner\ go/scanner\
hash/adler32\ hash/adler32\
......
...@@ -40,37 +40,37 @@ coverage: packages ...@@ -40,37 +40,37 @@ coverage: packages
$(AS) $*.s $(AS) $*.s
O1=\ O1=\
format.$O\ datafmt.$O\
O2=\ O2=\
parser.$O\ parser.$O\
phases: a1 a2 phases: a1 a2
_obj$D/format.a: phases _obj$D/datafmt.a: phases
a1: $(O1) a1: $(O1)
$(AR) grc _obj$D/format.a format.$O $(AR) grc _obj$D/datafmt.a datafmt.$O
rm -f $(O1) rm -f $(O1)
a2: $(O2) a2: $(O2)
$(AR) grc _obj$D/format.a parser.$O $(AR) grc _obj$D/datafmt.a parser.$O
rm -f $(O2) rm -f $(O2)
newpkg: clean newpkg: clean
mkdir -p _obj$D mkdir -p _obj$D
$(AR) grc _obj$D/format.a $(AR) grc _obj$D/datafmt.a
$(O1): newpkg $(O1): newpkg
$(O2): a1 $(O2): a1
$(O3): a2 $(O3): a2
nuke: clean nuke: clean
rm -f $(GOROOT)/pkg$D/format.a rm -f $(GOROOT)/pkg$D/datafmt.a
packages: _obj$D/format.a packages: _obj$D/datafmt.a
install: packages install: packages
test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg$D test -d $(GOROOT)/pkg && mkdir -p $(GOROOT)/pkg$D
cp _obj$D/format.a $(GOROOT)/pkg$D/format.a cp _obj$D/datafmt.a $(GOROOT)/pkg$D/datafmt.a
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
/* The format package implements syntax-directed, type-driven formatting /* The datafmt package implements syntax-directed, type-driven formatting
of arbitrary data structures. Formatting a data structure consists of of arbitrary data structures. Formatting a data structure consists of
two phases: first, a parser reads a format specification and builds a two phases: first, a parser reads a format specification and builds a
"compiled" format. Then, the format can be applied repeatedly to "compiled" format. Then, the format can be applied repeatedly to
...@@ -200,7 +200,7 @@ ...@@ -200,7 +200,7 @@
will format an argument list by printing each one in its default format, will format an argument list by printing each one in its default format,
separated by a comma and a space. separated by a comma and a space.
*/ */
package format package datafmt
import ( import (
"container/vector"; "container/vector";
......
...@@ -2,28 +2,28 @@ ...@@ -2,28 +2,28 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package format package datafmt
import ( import (
"fmt"; "fmt";
"format"; "datafmt";
"io"; "io";
"os"; "os";
"testing"; "testing";
) )
func parse(t *testing.T, form string, fmap format.FormatterMap) format.Format { func parse(t *testing.T, form string, fmap FormatterMap) Format {
f, err := format.Parse(io.StringBytes(form), fmap); f, err := Parse(io.StringBytes(form), fmap);
if err != nil { if err != nil {
t.Errorf("Parse(%s): %v", err); t.Errorf("Parse(%s): %v", form, err);
return nil; return nil;
} }
return f; return f;
} }
func verify(t *testing.T, f format.Format, expected string, args ...) { func verify(t *testing.T, f Format, expected string, args ...) {
if f == nil { if f == nil {
return; // allow other tests to run return; // allow other tests to run
} }
...@@ -37,7 +37,7 @@ func verify(t *testing.T, f format.Format, expected string, args ...) { ...@@ -37,7 +37,7 @@ func verify(t *testing.T, f format.Format, expected string, args ...) {
} }
func formatter(s *format.State, value interface{}, rule_name string) bool { func formatter(s *State, value interface{}, rule_name string) bool {
switch rule_name { switch rule_name {
case "/": case "/":
fmt.Fprintf(s, "%d %d %d", s.Pos().Line, s.LinePos().Column, s.Pos().Column); fmt.Fprintf(s, "%d %d %d", s.Pos().Line, s.LinePos().Column, s.Pos().Column);
...@@ -61,8 +61,8 @@ func formatter(s *format.State, value interface{}, rule_name string) bool { ...@@ -61,8 +61,8 @@ func formatter(s *format.State, value interface{}, rule_name string) bool {
func TestCustomFormatters(t *testing.T) { func TestCustomFormatters(t *testing.T) {
fmap0 := format.FormatterMap{ "/": formatter }; fmap0 := FormatterMap{ "/": formatter };
fmap1 := format.FormatterMap{ "int": formatter, "blank": formatter, "nil": formatter }; fmap1 := FormatterMap{ "int": formatter, "blank": formatter, "nil": formatter };
f := parse(t, `int=`, fmap0); f := parse(t, `int=`, fmap0);
verify(t, f, ``, 1, 2, 3); verify(t, f, ``, 1, 2, 3);
...@@ -91,6 +91,9 @@ func TestCustomFormatters(t *testing.T) { ...@@ -91,6 +91,9 @@ func TestCustomFormatters(t *testing.T) {
func check(t *testing.T, form, expected string, args ...) { func check(t *testing.T, form, expected string, args ...) {
f := parse(t, form, nil); f := parse(t, form, nil);
if f == nil {
return; // allow other tests to run
}
result := f.Sprint(args); result := f.Sprint(args);
if result != expected { if result != expected {
t.Errorf( t.Errorf(
...@@ -227,9 +230,9 @@ type T1 struct { ...@@ -227,9 +230,9 @@ type T1 struct {
} }
const F1 = const F1 =
`format "format";` `datafmt "datafmt";`
`int = "%d";` `int = "%d";`
`format.T1 = "<" a ">";` `datafmt.T1 = "<" a ">";`
func TestStruct1(t *testing.T) { func TestStruct1(t *testing.T) {
check(t, F1, "<42>", T1{42}); check(t, F1, "<42>", T1{42});
...@@ -248,13 +251,13 @@ const F2a = ...@@ -248,13 +251,13 @@ const F2a =
F1 + F1 +
`string = "%s";` `string = "%s";`
`ptr = *;` `ptr = *;`
`format.T2 = s ["-" p "-"];` `datafmt.T2 = s ["-" p "-"];`
const F2b = const F2b =
F1 + F1 +
`string = "%s";` `string = "%s";`
`ptr = *;` `ptr = *;`
`format.T2 = s ("-" p "-" | "empty");`; `datafmt.T2 = s ("-" p "-" | "empty");`;
func TestStruct2(t *testing.T) { func TestStruct2(t *testing.T) {
check(t, F2a, "foo", T2{"foo", nil}); check(t, F2a, "foo", T2{"foo", nil});
...@@ -272,19 +275,19 @@ type T3 struct { ...@@ -272,19 +275,19 @@ type T3 struct {
} }
const F3a = const F3a =
`format "format";` `datafmt "datafmt";`
`default = "%v";` `default = "%v";`
`array = *;` `array = *;`
`format.T3 = s {" " a a / ","};` `datafmt.T3 = s {" " a a / ","};`
const F3b = const F3b =
`format "format";` `datafmt "datafmt";`
`int = "%d";` `int = "%d";`
`string = "%s";` `string = "%s";`
`array = *;` `array = *;`
`nil = ;` `nil = ;`
`empty = *:nil;` `empty = *:nil;`
`format.T3 = s [a:empty ": " {a / "-"}]` `datafmt.T3 = s [a:empty ": " {a / "-"}]`
func TestStruct3(t *testing.T) { func TestStruct3(t *testing.T) {
check(t, F3a, "foo", T3{"foo", nil}); check(t, F3a, "foo", T3{"foo", nil});
...@@ -303,22 +306,22 @@ type T4 struct { ...@@ -303,22 +306,22 @@ type T4 struct {
} }
const F4a = const F4a =
`format "format";` `datafmt "datafmt";`
`int = "%d";` `int = "%d";`
`ptr = *;` `ptr = *;`
`array = *;` `array = *;`
`nil = ;` `nil = ;`
`empty = *:nil;` `empty = *:nil;`
`format.T4 = "<" (x:empty x | "-") ">" ` `datafmt.T4 = "<" (x:empty x | "-") ">" `
const F4b = const F4b =
`format "format";` `datafmt "datafmt";`
`int = "%d";` `int = "%d";`
`ptr = *;` `ptr = *;`
`array = *;` `array = *;`
`nil = ;` `nil = ;`
`empty = *:nil;` `empty = *:nil;`
`format.T4 = "<" (a:empty {a / ", "} | "-") ">" ` `datafmt.T4 = "<" (a:empty {a / ", "} | "-") ">" `
func TestStruct4(t *testing.T) { func TestStruct4(t *testing.T) {
x := 7; x := 7;
...@@ -338,11 +341,11 @@ type Point struct { ...@@ -338,11 +341,11 @@ type Point struct {
} }
const FPoint = const FPoint =
`format "format";` `datafmt "datafmt";`
`int = "%d";` `int = "%d";`
`hexInt = "0x%x";` `hexInt = "0x%x";`
`string = "---%s---";` `string = "---%s---";`
`format.Point = name "{" x ", " y:hexInt "}";` `datafmt.Point = name "{" x ", " y:hexInt "}";`
func TestStructPoint(t *testing.T) { func TestStructPoint(t *testing.T) {
p := Point{"foo", 3, 15}; p := Point{"foo", 3, 15};
......
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package format package datafmt
import ( import (
"container/vector"; "container/vector";
"datafmt";
"fmt"; "fmt";
"format";
"go/scanner"; "go/scanner";
"go/token"; "go/token";
"io"; "io";
......
...@@ -42,14 +42,21 @@ coverage: packages ...@@ -42,14 +42,21 @@ 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
...@@ -57,6 +64,7 @@ newpkg: clean ...@@ -57,6 +64,7 @@ newpkg: clean
$(O1): newpkg $(O1): newpkg
$(O2): a1 $(O2): a1
$(O3): a2
nuke: clean nuke: clean
rm -f $(GOROOT)/pkg$D/ast.a rm -f $(GOROOT)/pkg$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 {
optSemi := *s.optSemi;
return &state{&optSemi};
}
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) {
s := state{new(bool)};
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);
}
...@@ -5,10 +5,9 @@ ...@@ -5,10 +5,9 @@
package main package main
import ( import (
"astprinter"; "astprinter"; // TODO remove once go/printer is fully functional
"flag"; "flag";
"fmt"; "fmt";
"format";
"go/ast"; "go/ast";
"go/parser"; "go/parser";
"go/token"; "go/token";
...@@ -22,13 +21,14 @@ import ( ...@@ -22,13 +21,14 @@ import (
var ( var (
// operation modes // operation modes
columns bool; 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: no pretty print output");
verbose = flag.Bool("v", false, "verbose mode: trace parsing"); verbose = flag.Bool("v", false, "verbose mode: trace parsing");
// 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");
formatter = flag.Bool("formatter", false, "use formatter"); // TODO remove eventually
) )
...@@ -45,21 +45,6 @@ func usage() { ...@@ -45,21 +45,6 @@ func usage() {
} }
// TODO(gri) use library function for this once it exists
func readFile(filename string) ([]byte, os.Error) {
f, err := os.Open(filename, os.O_RDONLY, 0);
if err != nil {
return nil, err;
}
defer f.Close();
var b io.ByteBuffer;
if n, err := io.Copy(f, &b); err != nil {
return nil, err;
}
return b.Data(), nil;
}
// TODO(gri) move this function into tabwriter.go? (also used in godoc) // TODO(gri) move this function into tabwriter.go? (also used in godoc)
func makeTabwriter(writer io.Writer) *tabwriter.Writer { func makeTabwriter(writer io.Writer) *tabwriter.Writer {
padchar := byte(' '); padchar := byte(' ');
...@@ -70,70 +55,6 @@ func makeTabwriter(writer io.Writer) *tabwriter.Writer { ...@@ -70,70 +55,6 @@ func makeTabwriter(writer io.Writer) *tabwriter.Writer {
} }
func isValidPos(state *format.State, value interface{}, rule_name string) bool {
pos := value.(token.Position);
return pos.IsValid();
}
func isSend(state *format.State, value interface{}, rule_name string) bool {
return value.(ast.ChanDir) & ast.SEND != 0;
}
func isRecv(state *format.State, value interface{}, rule_name string) bool {
return value.(ast.ChanDir) & ast.RECV != 0;
}
func isMultiLineComment(state *format.State, value interface{}, rule_name string) bool {
return value.([]byte)[1] == '*';
}
type environment struct {
optSemi *bool;
}
func (e environment) Copy() format.Environment {
optSemi := *e.optSemi;
return environment{&optSemi};
}
func clearOptSemi(state *format.State, value interface{}, rule_name string) bool {
*state.Env().(environment).optSemi = false;
return true;
}
func setOptSemi(state *format.State, value interface{}, rule_name string) bool {
*state.Env().(environment).optSemi = true;
return true;
}
func optSemi(state *format.State, value interface{}, rule_name string) bool {
if !*state.Env().(environment).optSemi {
state.Write([]byte{';'});
}
return true;
}
var fmap = format.FormatterMap {
"isValidPos": isValidPos,
"isSend": isSend,
"isRecv": isRecv,
"isMultiLineComment": isMultiLineComment,
"/": clearOptSemi,
"clearOptSemi": clearOptSemi,
"setOptSemi": setOptSemi,
"optSemi": optSemi,
}
func main() { func main() {
// handle flags // handle flags
flag.Parse(); flag.Parse();
...@@ -141,31 +62,25 @@ func main() { ...@@ -141,31 +62,25 @@ func main() {
usage(); 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 // determine parsing mode
mode := parser.ParseComments; mode := parser.ParseComments;
if *verbose { if *verbose {
mode |= parser.Trace; mode |= parser.Trace;
} }
// get ast format
const ast_txt = "ast.txt";
src, err := readFile(ast_txt);
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %v\n", ast_txt, err);
os.Exit(1);
}
ast_format, err := format.Parse(src, fmap);
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %v\n", ast_txt, err);
os.Exit(1);
}
// process files // process files
exitcode := 0; exitcode := 0;
for i := 0; i < flag.NArg(); i++ { for i := 0; i < flag.NArg(); i++ {
filename := flag.Arg(i); filename := flag.Arg(i);
src, err := 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; exitcode = 1;
...@@ -188,9 +103,8 @@ func main() { ...@@ -188,9 +103,8 @@ func main() {
if !*silent { if !*silent {
tw := makeTabwriter(os.Stdout); tw := makeTabwriter(os.Stdout);
if *formatter { if *format != "" {
env := environment{new(bool)}; _, err := astFormat.Fprint(tw, prog);
_, err := ast_format.Fprint(tw, env, prog);
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "format error: %v\n", err); fmt.Fprintf(os.Stderr, "format error: %v\n", err);
exitcode = 1; exitcode = 1;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#!/bin/bash #!/bin/bash
CMD="./pretty -formatter" CMD="./pretty -format=ast.txt"
TMP1=test_tmp1.go TMP1=test_tmp1.go
TMP2=test_tmp2.go TMP2=test_tmp2.go
TMP3=test_tmp3.go TMP3=test_tmp3.go
......
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