Commit b7585a31 authored by Robert Griesemer's avatar Robert Griesemer

weekly snapshot:

format.go:
- better error handling, indentation, support for defaults,
  environments for custom formatters, cleanups (more functionality, less code)

pretty.go:
- better comment printing using format.go

made test script more robust

TBR=r
DELTA=622  (175 added, 305 deleted, 142 changed)
OCL=28956
CL=28956
parent a343e5ce
...@@ -49,7 +49,7 @@ ast.Decl = ...@@ -49,7 +49,7 @@ ast.Decl =
// Comments // Comments
ast.Comment = ast.Comment =
Text:string "\n"; Text:string [Text:isMultiLineComment "\n"];
ast.Comments = ast.Comments =
{*}; {*};
...@@ -305,9 +305,13 @@ ast.BadDecl = ...@@ -305,9 +305,13 @@ ast.BadDecl =
ast.GenDecl = ast.GenDecl =
Doc Doc
Tok " " Tok " "
[Lparen:isValidPos "(" >> "\t" "\n"] ( Lparen:isValidPos
{Specs / ";\n"} >> "\t" "(\n"
[Rparen:isValidPos << "\n" ")"]; {Specs / ";\n"}
<<
"\n)"
| {Specs / ";\n"}
);
ast.FuncDecl = ast.FuncDecl =
"func " ["(" Recv ") "] Name Type:funcSignature "func " ["(" Recv ") "] Name Type:funcSignature
......
...@@ -28,23 +28,17 @@ import ( ...@@ -28,23 +28,17 @@ import (
"io"; "io";
"os"; "os";
"reflect"; "reflect";
"runtime";
"strconv"; "strconv";
"strings"; "strings";
) )
// TODO should probably do this in a different way
var (
debug = flag.Bool("d", false, "debug mode");
trace = flag.Bool("t", false, "trace mode");
)
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Format representation // Format representation
type ( type (
Formatter func(w io.Writer, value interface{}, name string) bool; Formatter func(w io.Writer, env, value interface{}, name string) bool;
FormatterMap map[string]Formatter; FormatterMap map[string]Formatter;
) )
...@@ -52,43 +46,35 @@ type ( ...@@ -52,43 +46,35 @@ type (
// A production expression is built from the following nodes. // A production expression is built from the following nodes.
// //
type ( type (
expr interface { expr interface {};
String() string;
};
alternative struct { alternative struct {
x, y expr; x, y expr; // x | y
}; };
sequence struct { sequence struct {
x, y expr; x, y expr; // x y
}; };
literal struct { literal struct {
// TODO should there be other types or should it all be string literals?
value []byte; value []byte;
}; };
indentation struct {
iexpr expr; // outdent if nil
};
field struct { field struct {
fname string; // including "^", "*" fname string; // including "^", "*"
tname string; // "" if no tname specified tname string; // "" if no tname specified
}; };
negation struct { indentation struct {
neg expr; indent, body expr; // >> indent body <<
}; };
option struct { option struct {
opt expr; body expr; // [body]
}; };
repetition struct { repetition struct {
rep expr; body, div expr; // {body / div}
div expr;
}; };
custom struct { custom struct {
...@@ -98,60 +84,6 @@ type ( ...@@ -98,60 +84,6 @@ type (
) )
func (x *alternative) String() string {
return fmt.Sprintf("(%v | %v)", x.x, x.y);
}
func (x *sequence) String() string {
return fmt.Sprintf("%v %v", x.x, x.y);
}
func (x *literal) String() string {
return strconv.Quote(string(x.value));
}
func (x *indentation) String() string {
if x.iexpr != nil {
fmt.Sprintf(">> %s", x.iexpr);
}
return "<<";
}
func (x *field) String() string {
if x.tname == "" {
return x.fname;
}
return x.fname + " : " + x.tname;
}
func (x *negation) String() string {
return fmt.Sprintf("!%v", x.neg);
}
func (x *option) String() string {
return fmt.Sprintf("[%v]", x.opt);
}
func (x *repetition) String() string {
if x.div == nil {
return fmt.Sprintf("{%v}", x.rep);
}
return fmt.Sprintf("{%v / %v}", x.rep, x.div);
}
func (x *custom) String() string {
return "<" + x.name + ">";
}
/* A Format is a set of production expressions. A new format is /* A Format is a set of production expressions. A new format is
created explicitly by calling Parse, or implicitly by one of created explicitly by calling Parse, or implicitly by one of
the Xprintf functions. the Xprintf functions.
...@@ -159,17 +91,16 @@ func (x *custom) String() string { ...@@ -159,17 +91,16 @@ func (x *custom) String() string {
Formatting rules are specified in the following syntax: Formatting rules are specified in the following syntax:
Format = Production { ";" Production } [ ";" ] . Format = Production { ";" Production } [ ";" ] .
Production = Name "=" Expression . Production = ( Name | "default" | "/" ) "=" Expression .
Name = identifier { "." identifier } . Name = identifier { "." identifier } .
Expression = [ Term ] { "|" [ Term ] } . Expression = [ Term ] { "|" [ Term ] } .
Term = Factor { Factor } . Term = Factor { Factor } .
Factor = string_literal | Indent | Field | Negation | Group | Option | Repetition . Factor = string_literal | Indent | Field | Group | Option | Repetition .
Indent = ">>" Factor | "<<" .
Field = ( "^" | "*" | Name ) [ ":" Name ] . Field = ( "^" | "*" | Name ) [ ":" Name ] .
Negation = "!" Factor . Indent = ">>" Factor Expression "<<" .
Group = "(" Expression ")" . Group = "(" Expression ")" .
Option = "[" Expression "]" . Option = "[" Expression "]" .
Repetition = "{" Expression "}" . Repetition = "{" Expression [ "/" Expression ] "}" .
The syntax of white space, comments, identifiers, and string literals is The syntax of white space, comments, identifiers, and string literals is
the same as in Go. the same as in Go.
...@@ -198,17 +129,46 @@ func (x *custom) String() string { ...@@ -198,17 +129,46 @@ func (x *custom) String() string {
A field may contain a format specifier of the form A field may contain a format specifier of the form
: Expression : Name
which specifies the field format irrespective of the field type.
Default formats are used for types without specific formating rules: which specifies the field format rule irrespective of the field type.
The "%v" format is used for values of all types expect pointer, array,
map, and interface types. They are using the "^" designator.
TODO complete this description TODO complete this description
*/ */
type Format map [string] expr; type Format struct {
// TODO(gri) Eventually have import path info here
// once reflect provides import paths.
rules map [string] expr;
}
// ----------------------------------------------------------------------------
// Error handling
// Error implements an os.Error that may be returned as a
// result of calling Parse or any of the print functions.
//
type Error struct {
Pos token.Position; // source position, if any (otherwise Pos.Line == 0)
Msg string; // error message
Next *Error; // next error, if any (or nil)
}
// String converts a list of Error messages into a string,
// with one error per line.
//
func (e *Error) String() string {
var buf io.ByteBuffer;
for ; e != nil; e = e.Next {
if e.Pos.Line > 0 {
fmt.Fprintf(&buf, "%d:%d: ", e.Pos.Line, e.Pos.Column);
}
fmt.Fprintf(&buf, "%s\n", e.Msg);
}
return string(buf.Data());
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
...@@ -226,20 +186,24 @@ type parser struct { ...@@ -226,20 +186,24 @@ type parser struct {
tok token.Token; // one token look-ahead tok token.Token; // one token look-ahead
lit []byte; // token literal lit []byte; // token literal
// error handling // errors
errors io.ByteBuffer; // errors.Len() > 0 if there were errors first, last *Error;
lastline int;
} }
// The parser implements the scanner.ErrorHandler interface. // The parser implements the scanner.ErrorHandler interface.
func (p *parser) Error(pos token.Position, msg string) { func (p *parser) Error(pos token.Position, msg string) {
if pos.Line != p.lastline { if p.last == nil || p.last.Pos.Line != pos.Line {
// only report error if not on the same line as previous error // only report error if not on the same line as previous error
// in the hope to reduce number of follow-up errors reported // in the hope to reduce number of follow-up errors reported
fmt.Fprintf(&p.errors, "%d:%d: %s\n", pos.Line, pos.Column, msg); err := &Error{pos, msg, nil};
if p.last == nil {
p.first = err;
} else {
p.last.Next = err;
}
p.last = err;
} }
p.lastline = pos.Line;
} }
...@@ -299,7 +263,7 @@ func (p *parser) parseValue() []byte { ...@@ -299,7 +263,7 @@ func (p *parser) parseValue() []byte {
// (change value to string?) // (change value to string?)
s, err := strconv.Unquote(string(p.lit)); s, err := strconv.Unquote(string(p.lit));
if err != nil { if err != nil {
panic("scanner error?"); panic("scanner error");
} }
p.next(); p.next();
...@@ -308,7 +272,7 @@ func (p *parser) parseValue() []byte { ...@@ -308,7 +272,7 @@ func (p *parser) parseValue() []byte {
func (p *parser) parseFactor() (x expr) func (p *parser) parseFactor() (x expr)
func (p *parser) parseExpr() expr func (p *parser) parseExpression() expr
func (p *parser) parseField() expr { func (p *parser) parseField() expr {
var fname string; var fname string;
...@@ -344,33 +308,28 @@ func (p *parser) parseFactor() (x expr) { ...@@ -344,33 +308,28 @@ func (p *parser) parseFactor() (x expr) {
case token.SHR: case token.SHR:
p.next(); p.next();
x = &indentation{p.parseFactor()}; iexpr := p.parseFactor();
body := p.parseExpression();
case token.SHL: p.expect(token.SHL);
p.next(); return &indentation{iexpr, body};
x = &indentation{nil};
case token.NOT:
p.next();
x = &negation{p.parseFactor()};
case token.LPAREN: case token.LPAREN:
p.next(); p.next();
x = p.parseExpr(); x = p.parseExpression();
p.expect(token.RPAREN); p.expect(token.RPAREN);
case token.LBRACK: case token.LBRACK:
p.next(); p.next();
x = &option{p.parseExpr()}; x = &option{p.parseExpression()};
p.expect(token.RBRACK); p.expect(token.RBRACK);
case token.LBRACE: case token.LBRACE:
p.next(); p.next();
x = p.parseExpr(); x = p.parseExpression();
var div expr; var div expr;
if p.tok == token.QUO { if p.tok == token.QUO {
p.next(); p.next();
div = p.parseExpr(); div = p.parseExpression();
} }
x = &repetition{x, div}; x = &repetition{x, div};
p.expect(token.RBRACE); p.expect(token.RBRACE);
...@@ -400,7 +359,7 @@ func (p *parser) parseTerm() expr { ...@@ -400,7 +359,7 @@ func (p *parser) parseTerm() expr {
} }
func (p *parser) parseExpr() expr { func (p *parser) parseExpression() expr {
x := p.parseTerm(); x := p.parseTerm();
for p.tok == token.OR { for p.tok == token.OR {
...@@ -413,24 +372,34 @@ func (p *parser) parseExpr() expr { ...@@ -413,24 +372,34 @@ func (p *parser) parseExpr() expr {
} }
func (p *parser) parseProd() (string, expr) { func (p *parser) parseProduction() (string, expr) {
name := p.parseName(); var name string;
switch p.tok {
case token.DEFAULT:
p.next();
name = "default";
case token.QUO:
p.next();
name = "/";
default:
name = p.parseName();
}
p.expect(token.ASSIGN); p.expect(token.ASSIGN);
x := p.parseExpr(); x := p.parseExpression();
return name, x; return name, x;
} }
func (p *parser) parseFormat() Format { func (p *parser) parseFormat() *Format {
format := make(Format); rules := make(map [string] expr);
for p.tok != token.EOF { for p.tok != token.EOF {
pos := p.pos; pos := p.pos;
name, x := p.parseProd(); name, x := p.parseProduction();
// add production to format // add production to rules
if t, found := format[name]; !found { if t, found := rules[name]; !found {
format[name] = x; rules[name] = x;
} else { } else {
p.Error(pos, "production already declared: " + name); p.Error(pos, "production already declared: " + name);
} }
...@@ -443,198 +412,153 @@ func (p *parser) parseFormat() Format { ...@@ -443,198 +412,153 @@ func (p *parser) parseFormat() Format {
} }
p.expect(token.EOF); p.expect(token.EOF);
return format; return &Format{rules};
} }
type formatError string // Parse parses a set of format productions from source src. If there are no
// errors, the result is a Format and the error is nil. Otherwise the format
func (p formatError) String() string { // is nil and the os.Error string contains a line for each error encountered.
return string(p);
}
func readSource(src interface{}) ([]byte, os.Error) {
if src == nil {
return nil, formatError("src is nil");
}
switch s := src.(type) {
case string:
return io.StringBytes(s), nil;
case []byte:
if s == nil {
return nil, formatError("src is nil");
}
return s, nil;
case *io.ByteBuffer:
// is io.Read, but src is already available in []byte form
if s == nil {
return nil, formatError("src is nil");
}
return s.Data(), nil;
case io.Reader:
var buf io.ByteBuffer;
n, err := io.Copy(s, &buf);
if err != nil {
return nil, err;
}
return buf.Data(), nil
}
return nil, formatError("src type not supported");
}
// Parse parses a set of format productions. The format src may be
// a string, a []byte, or implement io.Read. The result is a Format
// if no errors occured; otherwise Parse returns nil.
// //
func Parse(src interface{}, fmap FormatterMap) (f Format, err os.Error) { func Parse(src []byte, fmap FormatterMap) (*Format, os.Error) {
s, err := readSource(src); // parse source
if err != nil {
return nil, err;
}
// parse format description
var p parser; var p parser;
p.scanner.Init(s, &p, false); p.scanner.Init(src, &p, false);
p.next(); p.next();
f = p.parseFormat(); f := p.parseFormat();
// add custom formatters, if any // add custom formatters, if any
// TODO should we test that name is a legal name?
for name, form := range fmap { for name, form := range fmap {
if t, found := f[name]; !found { if t, found := f.rules[name]; !found {
f[name] = &custom{name, form}; f.rules[name] = &custom{name, form};
} else { } else {
fmt.Fprintf(&p.errors, "formatter already declared: %s", name); p.Error(token.Position{0, 0, 0}, "formatter already declared: " + name);
} }
} }
if p.errors.Len() > 0 { if p.first != nil {
return nil, formatError(string(p.errors.Data())); return nil, p.first;
} }
return f, nil; return f, nil;
} }
func ParseOrDie(src interface{}, fmap FormatterMap) Format { // ----------------------------------------------------------------------------
f, err := Parse(src, fmap); // Formatting
if err != nil {
panic(err.String()); type state struct {
} f *Format;
return f; env interface{};
sep expr;
errors chan os.Error; // not chan *Error: errors <- nil would be wrong!
indent io.ByteBuffer;
} }
func (f Format) Dump() { func (ps *state) init(f *Format, env interface{}) {
for name, form := range f { ps.f = f;
fmt.Printf("%s = %v;\n", name, form); ps.env = env;
// if we have a separator ("/") production, cache it for easy access
if sep, has_sep := f.rules["/"]; has_sep {
ps.sep = sep;
} }
ps.errors = make(chan os.Error);
} }
// ---------------------------------------------------------------------------- func (ps *state) error(msg string) {
// Formatting ps.errors <- &Error{token.Position{0, 0, 0}, msg, nil};
runtime.Goexit();
}
func getField(val reflect.Value, fieldname string) (reflect.Value, int) {
// do we have a struct in the first place?
if val.Kind() != reflect.StructKind {
return nil, 0;
}
sval, styp := val.(reflect.StructValue), val.Type().(reflect.StructType);
// look for field at the top level
for i := 0; i < styp.Len(); i++ {
name, typ, tag, offset := styp.Field(i);
if name == fieldname || name == "" && strings.HasSuffix(typ.Name(), "." + fieldname) /* anonymous field */ {
return sval.Field(i), 0;
}
}
func getField(v reflect.StructValue, fieldname string) reflect.Value { // look for field in anonymous fields
t := v.Type().(reflect.StructType); var field reflect.Value;
for i := 0; i < t.Len(); i++ { level := 1000; // infinity
name, typ, tag, offset := t.Field(i); for i := 0; i < styp.Len(); i++ {
if name == fieldname { name, typ, tag, offset := styp.Field(i);
return v.Field(i); if name == "" {
} else if name == "" { f, l := getField(sval.Field(i), fieldname);
// anonymous field - check type name // keep the most shallow field
// TODO this is only going down one level - fix if f != nil && l < level {
if strings.HasSuffix(typ.Name(), "." + fieldname) { field, level = f, l;
return v.Field(i);
} }
} }
} }
panicln(fmt.Sprintf("no field %s int %s", fieldname, t.Name()));
return nil; return field, level + 1;
}
var default_names = map[int]string {
reflect.ArrayKind: "array",
reflect.BoolKind: "bool",
reflect.ChanKind: "chan",
reflect.DotDotDotKind: "ellipsis",
reflect.FloatKind: "float",
reflect.Float32Kind: "float32",
reflect.Float64Kind: "float64",
reflect.FuncKind: "func",
reflect.IntKind: "int",
reflect.Int16Kind: "int16",
reflect.Int32Kind: "int32",
reflect.Int64Kind: "int64",
reflect.Int8Kind: "int8",
reflect.InterfaceKind: "interface",
reflect.MapKind: "map",
reflect.PtrKind: "pointer",
reflect.StringKind: "string",
reflect.StructKind: "struct",
reflect.UintKind: "uint",
reflect.Uint16Kind: "uint16",
reflect.Uint32Kind: "uint32",
reflect.Uint64Kind: "uint64",
reflect.Uint8Kind: "uint8",
reflect.UintptrKind: "uintptr",
} }
func typename(value reflect.Value) string { func typename(value reflect.Value) string {
name := value.Type().Name(); name := value.Type().Name();
if name == "" {
if name != "" { if default_name, found := default_names[value.Kind()]; found {
return name; name = default_name;
} }
switch value.Kind() {
case reflect.ArrayKind: name = "array";
case reflect.BoolKind: name = "bool";
case reflect.ChanKind: name = "chan";
case reflect.DotDotDotKind: name = "ellipsis";
case reflect.FloatKind: name = "float";
case reflect.Float32Kind: name = "float32";
case reflect.Float64Kind: name = "float64";
case reflect.FuncKind: name = "func";
case reflect.IntKind: name = "int";
case reflect.Int16Kind: name = "int16";
case reflect.Int32Kind: name = "int32";
case reflect.Int64Kind: name = "int64";
case reflect.Int8Kind: name = "int8";
case reflect.InterfaceKind: name = "interface";
case reflect.MapKind: name = "map";
case reflect.PtrKind: name = "pointer";
case reflect.StringKind: name = "string";
case reflect.StructKind: name = "struct";
case reflect.UintKind: name = "uint";
case reflect.Uint16Kind: name = "uint16";
case reflect.Uint32Kind: name = "uint32";
case reflect.Uint64Kind: name = "uint64";
case reflect.Uint8Kind: name = "uint8";
case reflect.UintptrKind: name = "uintptr";
} }
return name; return name;
} }
var defaults = map [int] expr { func (ps *state) getFormat(name string) expr {
reflect.ArrayKind: &field{"*", ""}, if fexpr, found := ps.f.rules[name]; found {
reflect.DotDotDotKind: &field{"*", ""},
reflect.InterfaceKind: &field{"*", ""},
reflect.MapKind: &field{"*", ""},
reflect.PtrKind: &field{"*", ""},
reflect.StringKind: &literal{io.StringBytes("%s")},
}
var catchAll = &literal{io.StringBytes("%v")};
func (f Format) getFormat(name string, value reflect.Value) expr {
/*
if name == "nil" {
fmt.Printf("value = %T %v, kind = %d\n", value, value, value.Kind());
panic();
}
*/
if fexpr, found := f[name]; found {
return fexpr; return fexpr;
} }
if *debug { if fexpr, found := ps.f.rules["default"]; found {
fmt.Printf("no production for type: %s\n", name);
}
// no fexpr found - return kind-specific default value, if any
if fexpr, found := defaults[value.Kind()]; found {
return fexpr; return fexpr;
} }
if *debug { ps.error(fmt.Sprintf("no production for type: '%s'\n", name));
fmt.Printf("no default for type: %s\n", name); panic("unreachable");
} return nil;
return catchAll;
} }
...@@ -654,7 +578,7 @@ func percentCount(s []byte) int { ...@@ -654,7 +578,7 @@ func percentCount(s []byte) int {
} }
func rawPrintf(w io.Writer, format []byte, value reflect.Value) { func (ps *state) rawPrintf(w io.Writer, format []byte, value reflect.Value) {
// TODO find a better way to do this // TODO find a better way to do this
x := value.Interface(); x := value.Interface();
switch percentCount(format) { switch percentCount(format) {
...@@ -668,69 +592,13 @@ func rawPrintf(w io.Writer, format []byte, value reflect.Value) { ...@@ -668,69 +592,13 @@ func rawPrintf(w io.Writer, format []byte, value reflect.Value) {
} }
// TODO this should become a Go built-in
func push(dst []int, x int) []int {
n := len(dst);
if n > cap(dst) {
panic("dst too small");
}
dst = dst[0 : n+1];
dst[n] = x;
return dst;
}
func append(dst, src []byte) []byte {
n, m := len(dst), len(src);
if n+m > cap(dst) {
panic("dst too small");
}
dst = dst[0 : n+m];
for i := 0; i < m; i++ {
dst[n+i] = src[i];
}
return dst;
}
type state struct {
f Format;
// indentation
indent_text []byte;
indent_widths []int;
}
func (ps *state) init(f Format) {
ps.f = f;
ps.indent_text = make([]byte, 0, 1000); // TODO don't use fixed cap
ps.indent_widths = make([]int, 0, 100); // TODO don't use fixed cap
}
func (ps *state) indent(text []byte) {
ps.indent_widths = push(ps.indent_widths, len(ps.indent_text));
ps.indent_text = append(ps.indent_text, text);
}
func (ps *state) outdent() {
i := len(ps.indent_widths);
if i > 0 {
ps.indent_text = ps.indent_text[0 : ps.indent_widths[i-1]];
ps.indent_widths = ps.indent_widths[0 : i-1];
}
}
func (ps *state) printIndented(w io.Writer, s []byte) { func (ps *state) printIndented(w io.Writer, s []byte) {
// replace each '\n' with the indent + '\n' // replace each '\n' with the indent + '\n'
i0 := 0; i0 := 0;
for i := 0; i < len(s); i++ { for i := 0; i < len(s); i++ {
if s[i] == '\n' { if s[i] == '\n' {
w.Write(s[i0 : i+1]); w.Write(s[i0 : i+1]);
w.Write(ps.indent_text); w.Write(ps.indent.Data());
i0 = i+1; i0 = i+1;
} }
} }
...@@ -739,22 +607,20 @@ func (ps *state) printIndented(w io.Writer, s []byte) { ...@@ -739,22 +607,20 @@ func (ps *state) printIndented(w io.Writer, s []byte) {
func (ps *state) printf(w io.Writer, format []byte, value reflect.Value) { func (ps *state) printf(w io.Writer, format []byte, value reflect.Value) {
if len(ps.indent_widths) == 0 { if ps.indent.Len()== 0 {
// no indentation // no indentation
rawPrintf(w, format, value); ps.rawPrintf(w, format, value);
} else { } else {
// print into temporary buffer // print into temporary buffer
var buf io.ByteBuffer; var buf io.ByteBuffer;
rawPrintf(&buf, format, value); ps.rawPrintf(&buf, format, value);
ps.printIndented(w, buf.Data()); ps.printIndented(w, buf.Data());
} }
} }
func (ps *state) print(w io.Writer, fexpr expr, value reflect.Value, index, level int) bool
// Returns true if a non-empty field value was found. // Returns true if a non-empty field value was found.
func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, level int) bool { func (ps *state) print(w io.Writer, fexpr expr, value reflect.Value, index int) bool {
if fexpr == nil { if fexpr == nil {
return true; return true;
} }
...@@ -764,12 +630,12 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev ...@@ -764,12 +630,12 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev
// - print the contents of the first alternative with a non-empty field // - print the contents of the first alternative with a non-empty field
// - result is true if there is at least one non-empty field // - result is true if there is at least one non-empty field
var buf io.ByteBuffer; var buf io.ByteBuffer;
if ps.print(&buf, t.x, value, 0, level) { if ps.print(&buf, t.x, value, 0) {
w.Write(buf.Data()); w.Write(buf.Data());
return true; return true;
} else { } else {
var buf io.ByteBuffer; var buf io.ByteBuffer;
if ps.print(&buf, t.y, value, 0, level) { if ps.print(&buf, t.y, value, 0) {
w.Write(buf.Data()); w.Write(buf.Data());
return true; return true;
} }
...@@ -780,9 +646,12 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev ...@@ -780,9 +646,12 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev
// - print the contents of the sequence // - print the contents of the sequence
// - result is true if there is no empty field // - result is true if there is no empty field
// TODO do we need to buffer here? why not? // TODO do we need to buffer here? why not?
b1 := ps.print(w, t.x, value, index, level); b := ps.print(w, t.x, value, index);
b2 := ps.print(w, t.y, value, index, level); // TODO should invoke separator only inbetween terminal symbols?
return b1 && b2; if ps.sep != nil {
b = ps.print(w, ps.sep, value, index) && b;
}
return ps.print(w, t.y, value, index) && b;
case *literal: case *literal:
// - print the literal // - print the literal
...@@ -790,19 +659,6 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev ...@@ -790,19 +659,6 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev
ps.printf(w, t.value, value); ps.printf(w, t.value, value);
return true; return true;
case *indentation:
if t.iexpr != nil {
// indent
var buf io.ByteBuffer;
ps.print(&buf, t.iexpr, value, index, level);
ps.indent(buf.Data());
} else {
// outdent
ps.outdent();
}
return true;
case *field: case *field:
// - print the contents of the field // - print the contents of the field
// - format is either the field format or the type-specific format // - format is either the field format or the type-specific format
...@@ -822,7 +678,7 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev ...@@ -822,7 +678,7 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev
value = v.Elem(index); value = v.Elem(index);
case reflect.MapValue: case reflect.MapValue:
panic("reflection support for maps incomplete"); ps.error("reflection support for maps incomplete\n");
case reflect.PtrValue: case reflect.PtrValue:
if v.Get() == nil { if v.Get() == nil {
...@@ -838,17 +694,16 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev ...@@ -838,17 +694,16 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev
default: default:
// TODO fix this // TODO fix this
panic(fmt.Sprintf("error: * does not apply to `%s`\n", value.Type().Name())); ps.error(fmt.Sprintf("error: * does not apply to `%s`\n", value.Type().Name()));
} }
default: default:
// field // field
if s, is_struct := value.(reflect.StructValue); is_struct { field, _ := getField(value, t.fname);
value = getField(s, t.fname); if field == nil {
} else { ps.error(fmt.Sprintf("error: no field `%s` in `%s`\n", t.fname, value.Type().Name()));
// TODO fix this
panic(fmt.Sprintf("error: %s has no field `%s`\n", value.Type().Name(), t.fname));
} }
value = field;
} }
// determine format // determine format
...@@ -856,23 +711,21 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev ...@@ -856,23 +711,21 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev
if tname == "" { if tname == "" {
tname = typename(value) tname = typename(value)
} }
fexpr = ps.f.getFormat(tname, value); fexpr = ps.getFormat(tname);
return ps.print(w, fexpr, value, index, level); return ps.print(w, fexpr, value, index);
case *negation: case *indentation:
// TODO is this operation useful at all? saved_len := ps.indent.Len();
// print the contents of the option if is contains an empty field ps.print(&ps.indent, t.indent, value, index); // add additional indentation
var buf io.ByteBuffer; b := ps.print(w, t.body, value, index);
if !ps.print(&buf, t.neg, value, 0, level) { ps.indent.Truncate(saved_len); // reset indentation
w.Write(buf.Data()); return b;
}
return true;
case *option: case *option:
// print the contents of the option if it contains a non-empty field // print the contents of the option if it contains a non-empty field
var buf io.ByteBuffer; var buf io.ByteBuffer;
if ps.print(&buf, t.opt, value, 0, level) { if ps.print(&buf, t.body, value, 0) {
w.Write(buf.Data()); w.Write(buf.Data());
} }
return true; return true;
...@@ -880,9 +733,9 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev ...@@ -880,9 +733,9 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev
case *repetition: case *repetition:
// print the contents of the repetition while there is a non-empty field // print the contents of the repetition while there is a non-empty field
var buf io.ByteBuffer; var buf io.ByteBuffer;
for i := 0; ps.print(&buf, t.rep, value, i, level); i++ { for i := 0; ps.print(&buf, t.body, value, i); i++ {
if i > 0 { if i > 0 {
ps.print(w, t.div, value, i, level); ps.print(w, t.div, value, i);
} }
w.Write(buf.Data()); w.Write(buf.Data());
buf.Reset(); buf.Reset();
...@@ -891,7 +744,7 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev ...@@ -891,7 +744,7 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev
case *custom: case *custom:
var buf io.ByteBuffer; var buf io.ByteBuffer;
if t.form(&buf, value.Interface(), t.name) { if t.form(&buf, ps.env, value.Interface(), t.name) {
ps.printIndented(w, buf.Data()); ps.printIndented(w, buf.Data());
return true; return true;
} }
...@@ -903,63 +756,41 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev ...@@ -903,63 +756,41 @@ func (ps *state) print0(w io.Writer, fexpr expr, value reflect.Value, index, lev
} }
func printTrace(indent int, format string, a ...) {
const dots =
". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ";
const n = len(dots);
i := 2*indent;
for ; i > n; i -= n {
fmt.Print(dots);
}
fmt.Print(dots[0 : i]);
fmt.Printf(format, a);
}
func (ps *state) print(w io.Writer, fexpr expr, value reflect.Value, index, level int) bool {
if *trace {
printTrace(level, "%v, %d {\n", fexpr, /*value.Interface(), */index);
}
result := ps.print0(w, fexpr, value, index, level+1);
if *trace {
printTrace(level, "} %v\n", result);
}
return result;
}
// TODO proper error reporting
// Fprint formats each argument according to the format f // Fprint formats each argument according to the format f
// and writes to w. // and writes to w.
// //
func (f Format) Fprint(w io.Writer, args ...) { func (f *Format) Fprint(w io.Writer, env interface{}, args ...) (int, os.Error) {
value := reflect.NewValue(args).(reflect.StructValue); var ps state;
for i := 0; i < value.Len(); i++ { ps.init(f, env);
fld := value.Field(i);
var ps state; go func() {
ps.init(f); value := reflect.NewValue(args).(reflect.StructValue);
ps.print(w, f.getFormat(typename(fld), fld), fld, 0, 0); for i := 0; i < value.Len(); i++ {
} fld := value.Field(i);
ps.print(w, ps.getFormat(typename(fld)), fld, 0);
}
ps.errors <- nil; // no errors
}();
// TODO return correct value for count instead of 0
return 0, <-ps.errors;
} }
// Print formats each argument according to the format f // Print formats each argument according to the format f
// and writes to standard output. // and writes to standard output.
// //
func (f Format) Print(args ...) { func (f *Format) Print(args ...) (int, os.Error) {
f.Fprint(os.Stdout, args); return f.Fprint(os.Stdout, nil, args);
} }
// Sprint formats each argument according to the format f // Sprint formats each argument according to the format f
// and returns the resulting string. // and returns the resulting string.
// //
func (f Format) Sprint(args ...) string { func (f *Format) Sprint(args ...) string {
var buf io.ByteBuffer; var buf io.ByteBuffer;
f.Fprint(&buf, args); // TODO what to do in case of errors?
f.Fprint(&buf, nil, args);
return string(buf.Data()); return string(buf.Data());
} }
...@@ -6,12 +6,17 @@ package format ...@@ -6,12 +6,17 @@ package format
import ( import (
"format"; "format";
"io";
"testing"; "testing";
) )
func check(t *testing.T, form, expected string, args ...) { func check(t *testing.T, form, expected string, args ...) {
result := format.ParseOrDie(form, nil).Sprint(args); f, err := format.Parse(io.StringBytes(form), nil);
if err != nil {
panic(err.String());
}
result := f.Sprint(args);
if result != expected { if result != expected {
t.Errorf( t.Errorf(
"format : %s\nresult : `%s`\nexpected: `%s`\n\n", "format : %s\nresult : `%s`\nexpected: `%s`\n\n",
...@@ -39,7 +44,6 @@ func Test0(t *testing.T) { ...@@ -39,7 +44,6 @@ func Test0(t *testing.T) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// - default formatting of basic type int
// - formatting of a struct // - formatting of a struct
type T1 struct { type T1 struct {
...@@ -47,6 +51,7 @@ type T1 struct { ...@@ -47,6 +51,7 @@ type T1 struct {
} }
const F1 = const F1 =
`int = "%d";`
`format.T1 = "<" a ">";` `format.T1 = "<" a ">";`
func Test1(t *testing.T) { func Test1(t *testing.T) {
...@@ -56,7 +61,6 @@ func Test1(t *testing.T) { ...@@ -56,7 +61,6 @@ func Test1(t *testing.T) {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// - formatting of a struct with an optional field (pointer) // - formatting of a struct with an optional field (pointer)
// - default formatting for pointers
type T2 struct { type T2 struct {
s string; s string;
...@@ -65,11 +69,14 @@ type T2 struct { ...@@ -65,11 +69,14 @@ type T2 struct {
const F2a = const F2a =
F1 + F1 +
`string = "%s";`
`pointer = *;` `pointer = *;`
`format.T2 = s ["-" p "-"];` `format.T2 = s ["-" p "-"];`
const F2b = const F2b =
F1 + F1 +
`string = "%s";`
`pointer = *;`
`format.T2 = s ("-" p "-" | "empty");`; `format.T2 = s ("-" p "-" | "empty");`;
func Test2(t *testing.T) { func Test2(t *testing.T) {
...@@ -88,9 +95,14 @@ type T3 struct { ...@@ -88,9 +95,14 @@ type T3 struct {
} }
const F3a = const F3a =
`default = "%v";`
`array = *;`
`format.T3 = s {" " a a / ","};` `format.T3 = s {" " a a / ","};`
const F3b = const F3b =
`int = "%d";`
`string = "%s";`
`array = *;`
`nil = ;` `nil = ;`
`empty = *:nil;` `empty = *:nil;`
`format.T3 = s [a:empty ": " {a / "-"}]` `format.T3 = s [a:empty ": " {a / "-"}]`
...@@ -112,11 +124,17 @@ type T4 struct { ...@@ -112,11 +124,17 @@ type T4 struct {
} }
const F4a = const F4a =
`int = "%d";`
`pointer = *;`
`array = *;`
`nil = ;` `nil = ;`
`empty = *:nil;` `empty = *:nil;`
`format.T4 = "<" (x:empty x | "-") ">" ` `format.T4 = "<" (x:empty x | "-") ">" `
const F4b = const F4b =
`int = "%d";`
`pointer = *;`
`array = *;`
`nil = ;` `nil = ;`
`empty = *:nil;` `empty = *:nil;`
`format.T4 = "<" (a:empty {a / ", "} | "-") ">" ` `format.T4 = "<" (a:empty {a / ", "} | "-") ">" `
......
...@@ -94,20 +94,32 @@ func (h *ErrorHandler) Error(pos token.Position, msg string) { ...@@ -94,20 +94,32 @@ func (h *ErrorHandler) Error(pos token.Position, msg string) {
} }
func isValidPos(w io.Writer, value interface{}, name string) bool { func isValidPos(w io.Writer, env, value interface{}, name string) bool {
return value.(token.Position).Line > 0; return value.(token.Position).Line > 0;
} }
func isSend(w io.Writer, value interface{}, name string) bool { func isSend(w io.Writer, env, value interface{}, name string) bool {
return value.(ast.ChanDir) & ast.SEND != 0; return value.(ast.ChanDir) & ast.SEND != 0;
} }
func isRecv(w io.Writer, value interface{}, name string) bool { func isRecv(w io.Writer, env, value interface{}, name string) bool {
return value.(ast.ChanDir) & ast.RECV != 0; return value.(ast.ChanDir) & ast.RECV != 0;
} }
func isMultiLineComment(w io.Writer, env, value interface{}, name string) bool {
return value.([]byte)[1] == '*'
}
var fmap = format.FormatterMap{
"isValidPos": isValidPos,
"isSend": isSend,
"isRecv": isRecv,
"isMultiLineComment": isMultiLineComment,
}
func main() { func main() {
// handle flags // handle flags
...@@ -129,7 +141,7 @@ func main() { ...@@ -129,7 +141,7 @@ func main() {
fmt.Fprintf(os.Stderr, "%s: %v\n", ast_txt, err); fmt.Fprintf(os.Stderr, "%s: %v\n", ast_txt, err);
os.Exit(1); os.Exit(1);
} }
ast_format, err := format.Parse(src, format.FormatterMap{"isValidPos": isValidPos, "isSend": isSend, "isRecv": isRecv}); ast_format, err := format.Parse(src, fmap);
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "%s: format errors:\n%s", ast_txt, err); fmt.Fprintf(os.Stderr, "%s: format errors:\n%s", ast_txt, err);
os.Exit(1); os.Exit(1);
...@@ -156,7 +168,13 @@ func main() { ...@@ -156,7 +168,13 @@ func main() {
if !*silent { if !*silent {
tw := makeTabwriter(os.Stdout); tw := makeTabwriter(os.Stdout);
if *formatter { if *formatter {
ast_format.Fprint(tw, prog); var optSemi bool; // formatting environment
_, err := ast_format.Fprint(tw, &optSemi, prog);
if err != nil {
fmt.Fprintf(os.Stderr, "format error$$: %s", err);
exitcode = 1;
continue; // proceed with next file
}
} else { } else {
var p astPrinter.Printer; var p astPrinter.Printer;
p.Init(tw, nil, nil /*prog.Comments*/, false); p.Init(tw, nil, nil /*prog.Comments*/, false);
......
...@@ -69,7 +69,7 @@ type Object struct { ...@@ -69,7 +69,7 @@ type Object struct {
func (obj *Object) IsExported() bool { func (obj *Object) IsExported() bool {
switch obj.Kind { switch obj.Kind {
case NONE /* FUNC for now */, CONST, TYPE, VAR, FUNC: case NONE /* FUNC for now */, CONST, TYPE, VAR, FUNC:
ch, size := utf8.DecodeRuneInString(obj.Ident, 0); ch, size := utf8.DecodeRuneInString(obj.Ident);
return unicode.IsUpper(ch); return unicode.IsUpper(ch);
} }
return false; return false;
......
...@@ -36,8 +36,7 @@ apply1() { ...@@ -36,8 +36,7 @@ apply1() {
# apply to local files # apply to local files
applydot() { applydot() {
for F in *.go for F in `find . -name "*.go" | grep -v "OLD" | grep -v "._"`; do
do
apply1 $1 $F apply1 $1 $F
done done
} }
...@@ -45,7 +44,7 @@ applydot() { ...@@ -45,7 +44,7 @@ applydot() {
# apply to all .go files we can find # apply to all .go files we can find
apply() { apply() {
for F in `find $GOROOT -name "*.go" | grep -v "OLD"`; do for F in `find $GOROOT -name "*.go" | grep -v "OLD" | grep -v "._"`; do
apply1 $1 $F apply1 $1 $F
done done
} }
......
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