| // 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 datafmt implements syntax-directed, type-driven formatting | |
| of arbitrary data structures. Formatting a data structure consists of | |
| two phases: first, a parser reads a format specification and builds a | |
| "compiled" format. Then, the format can be applied repeatedly to | |
| arbitrary values. Applying a format to a value evaluates to a []byte | |
| containing the formatted value bytes, or nil. | |
| A format specification is a set of package declarations and format rules: | |
| Format = [ Entry { ";" Entry } [ ";" ] ] . | |
| Entry = PackageDecl | FormatRule . | |
| (The syntax of a format specification is presented in the same EBNF | |
| notation as used in the Go language specification. The syntax of white | |
| space, comments, identifiers, and string literals is the same as in Go.) | |
| A package declaration binds a package name (such as 'ast') to a | |
| package import path (such as '"go/ast"'). Each package used (in | |
| a type name, see below) must be declared once before use. | |
| PackageDecl = PackageName ImportPath . | |
| PackageName = identifier . | |
| ImportPath = string . | |
| A format rule binds a rule name to a format expression. A rule name | |
| may be a type name or one of the special names 'default' or '/'. | |
| A type name may be the name of a predeclared type (for example, 'int', | |
| 'float32', etc.), the package-qualified name of a user-defined type | |
| (for example, 'ast.MapType'), or an identifier indicating the structure | |
| of unnamed composite types ('array', 'chan', 'func', 'interface', 'map', | |
| or 'ptr'). Each rule must have a unique name; rules can be declared in | |
| any order. | |
| FormatRule = RuleName "=" Expression . | |
| RuleName = TypeName | "default" | "/" . | |
| TypeName = [ PackageName "." ] identifier . | |
| To format a value, the value's type name is used to select the format rule | |
| (there is an override mechanism, see below). The format expression of the | |
| selected rule specifies how the value is formatted. Each format expression, | |
| when applied to a value, evaluates to a byte sequence or nil. | |
| In its most general form, a format expression is a list of alternatives, | |
| each of which is a sequence of operands: | |
| Expression = [ Sequence ] { "|" [ Sequence ] } . | |
| Sequence = Operand { Operand } . | |
| The formatted result produced by an expression is the result of the first | |
| alternative sequence that evaluates to a non-nil result; if there is no | |
| such alternative, the expression evaluates to nil. The result produced by | |
| an operand sequence is the concatenation of the results of its operands. | |
| If any operand in the sequence evaluates to nil, the entire sequence | |
| evaluates to nil. | |
| There are five kinds of operands: | |
| Operand = Literal | Field | Group | Option | Repetition . | |
| Literals evaluate to themselves, with two substitutions. First, | |
| %-formats expand in the manner of fmt.Printf, with the current value | |
| passed as the parameter. Second, the current indentation (see below) | |
| is inserted after every newline or form feed character. | |
| Literal = string . | |
| This table shows string literals applied to the value 42 and the | |
| corresponding formatted result: | |
| "foo" foo | |
| "%x" 2a | |
| "x = %d" x = 42 | |
| "%#x = %d" 0x2a = 42 | |
| A field operand is a field name optionally followed by an alternate | |
| rule name. The field name may be an identifier or one of the special | |
| names @ or *. | |
| Field = FieldName [ ":" RuleName ] . | |
| FieldName = identifier | "@" | "*" . | |
| If the field name is an identifier, the current value must be a struct, | |
| and there must be a field with that name in the struct. The same lookup | |
| rules apply as in the Go language (for instance, the name of an anonymous | |
| field is the unqualified type name). The field name denotes the field | |
| value in the struct. If the field is not found, formatting is aborted | |
| and an error message is returned. (TODO consider changing the semantics | |
| such that if a field is not found, it evaluates to nil). | |
| The special name '@' denotes the current value. | |
| The meaning of the special name '*' depends on the type of the current | |
| value: | |
| array, slice types array, slice element (inside {} only, see below) | |
| interfaces value stored in interface | |
| pointers value pointed to by pointer | |
| (Implementation restriction: channel, function and map types are not | |
| supported due to missing reflection support). | |
| Fields are evaluated as follows: If the field value is nil, or an array | |
| or slice element does not exist, the result is nil (see below for details | |
| on array/slice elements). If the value is not nil the field value is | |
| formatted (recursively) using the rule corresponding to its type name, | |
| or the alternate rule name, if given. | |
| The following example shows a complete format specification for a | |
| struct 'myPackage.Point'. Assume the package | |
| package myPackage // in directory myDir/myPackage | |
| type Point struct { | |
| name string; | |
| x, y int; | |
| } | |
| Applying the format specification | |
| myPackage "myDir/myPackage"; | |
| int = "%d"; | |
| hexInt = "0x%x"; | |
| string = "---%s---"; | |
| myPackage.Point = name "{" x ", " y:hexInt "}"; | |
| to the value myPackage.Point{"foo", 3, 15} results in | |
| ---foo---{3, 0xf} | |
| Finally, an operand may be a grouped, optional, or repeated expression. | |
| A grouped expression ("group") groups a more complex expression (body) | |
| so that it can be used in place of a single operand: | |
| Group = "(" [ Indentation ">>" ] Body ")" . | |
| Indentation = Expression . | |
| Body = Expression . | |
| A group body may be prefixed by an indentation expression followed by '>>'. | |
| The indentation expression is applied to the current value like any other | |
| expression and the result, if not nil, is appended to the current indentation | |
| during the evaluation of the body (see also formatting state, below). | |
| An optional expression ("option") is enclosed in '[]' brackets. | |
| Option = "[" Body "]" . | |
| An option evaluates to its body, except that if the body evaluates to nil, | |
| the option expression evaluates to an empty []byte. Thus an option's purpose | |
| is to protect the expression containing the option from a nil operand. | |
| A repeated expression ("repetition") is enclosed in '{}' braces. | |
| Repetition = "{" Body [ "/" Separator ] "}" . | |
| Separator = Expression . | |
| A repeated expression is evaluated as follows: The body is evaluated | |
| repeatedly and its results are concatenated until the body evaluates | |
| to nil. The result of the repetition is the (possibly empty) concatenation, | |
| but it is never nil. An implicit index is supplied for the evaluation of | |
| the body: that index is used to address elements of arrays or slices. If | |
| the corresponding elements do not exist, the field denoting the element | |
| evaluates to nil (which in turn may terminate the repetition). | |
| The body of a repetition may be followed by a '/' and a "separator" | |
| expression. If the separator is present, it is invoked between repetitions | |
| of the body. | |
| The following example shows a complete format specification for formatting | |
| a slice of unnamed type. Applying the specification | |
| int = "%b"; | |
| array = { * / ", " }; // array is the type name for an unnamed slice | |
| to the value '[]int{2, 3, 5, 7}' results in | |
| 10, 11, 101, 111 | |
| Default rule: If a format rule named 'default' is present, it is used for | |
| formatting a value if no other rule was found. A common default rule is | |
| default = "%v" | |
| to provide default formatting for basic types without having to specify | |
| a specific rule for each basic type. | |
| Global separator rule: If a format rule named '/' is present, it is | |
| invoked with the current value between literals. If the separator | |
| expression evaluates to nil, it is ignored. | |
| For instance, a global separator rule may be used to punctuate a sequence | |
| of values with commas. The rules: | |
| default = "%v"; | |
| / = ", "; | |
| will format an argument list by printing each one in its default format, | |
| separated by a comma and a space. | |
| */ | |
| package datafmt | |
| import ( | |
| "bytes" | |
| "fmt" | |
| "go/token" | |
| "io" | |
| "os" | |
| "reflect" | |
| "runtime" | |
| ) | |
| // ---------------------------------------------------------------------------- | |
| // Format representation | |
| // Custom formatters implement the Formatter function type. | |
| // A formatter is invoked with the current formatting state, the | |
| // value to format, and the rule name under which the formatter | |
| // was installed (the same formatter function may be installed | |
| // under different names). The formatter may access the current state | |
| // to guide formatting and use State.Write to append to the state's | |
| // output. | |
| // | |
| // A formatter must return a boolean value indicating if it evaluated | |
| // to a non-nil value (true), or a nil value (false). | |
| // | |
| type Formatter func(state *State, value interface{}, ruleName string) bool | |
| // A FormatterMap is a set of custom formatters. | |
| // It maps a rule name to a formatter function. | |
| // | |
| type FormatterMap map[string]Formatter | |
| // A parsed format expression is built from the following nodes. | |
| // | |
| type ( | |
| expr interface{} | |
| alternatives []expr // x | y | z | |
| sequence []expr // x y z | |
| literal [][]byte // a list of string segments, possibly starting with '%' | |
| field struct { | |
| fieldName string // including "@", "*" | |
| ruleName string // "" if no rule name specified | |
| } | |
| group struct { | |
| indent, body expr // (indent >> body) | |
| } | |
| option struct { | |
| body expr // [body] | |
| } | |
| repetition struct { | |
| body, separator expr // {body / separator} | |
| } | |
| custom struct { | |
| ruleName string | |
| fun Formatter | |
| } | |
| ) | |
| // A Format is the result of parsing a format specification. | |
| // The format may be applied repeatedly to format values. | |
| // | |
| type Format map[string]expr | |
| // ---------------------------------------------------------------------------- | |
| // Formatting | |
| // An application-specific environment may be provided to Format.Apply; | |
| // the environment is available inside custom formatters via State.Env(). | |
| // Environments must implement copying; the Copy method must return an | |
| // complete copy of the receiver. This is necessary so that the formatter | |
| // can save and restore an environment (in case of an absent expression). | |
| // | |
| // If the Environment doesn't change during formatting (this is under | |
| // control of the custom formatters), the Copy function can simply return | |
| // the receiver, and thus can be very light-weight. | |
| // | |
| type Environment interface { | |
| Copy() Environment | |
| } | |
| // State represents the current formatting state. | |
| // It is provided as argument to custom formatters. | |
| // | |
| type State struct { | |
| fmt Format // format in use | |
| env Environment // user-supplied environment | |
| errors chan os.Error // not chan *Error (errors <- nil would be wrong!) | |
| hasOutput bool // true after the first literal has been written | |
| indent bytes.Buffer // current indentation | |
| output bytes.Buffer // format output | |
| linePos token.Position // position of line beginning (Column == 0) | |
| default_ expr // possibly nil | |
| separator expr // possibly nil | |
| } | |
| func newState(fmt Format, env Environment, errors chan os.Error) *State { | |
| s := new(State) | |
| s.fmt = fmt | |
| s.env = env | |
| s.errors = errors | |
| s.linePos = token.Position{Line: 1} | |
| // if we have a default rule, cache it's expression for fast access | |
| if x, found := fmt["default"]; found { | |
| s.default_ = x | |
| } | |
| // if we have a global separator rule, cache it's expression for fast access | |
| if x, found := fmt["/"]; found { | |
| s.separator = x | |
| } | |
| return s | |
| } | |
| // Env returns the environment passed to Format.Apply. | |
| func (s *State) Env() interface{} { return s.env } | |
| // LinePos returns the position of the current line beginning | |
| // in the state's output buffer. Line numbers start at 1. | |
| // | |
| func (s *State) LinePos() token.Position { return s.linePos } | |
| // Pos returns the position of the next byte to be written to the | |
| // output buffer. Line numbers start at 1. | |
| // | |
| func (s *State) Pos() token.Position { | |
| offs := s.output.Len() | |
| return token.Position{Line: s.linePos.Line, Column: offs - s.linePos.Offset, Offset: offs} | |
| } | |
| // Write writes data to the output buffer, inserting the indentation | |
| // string after each newline or form feed character. It cannot return an error. | |
| // | |
| func (s *State) Write(data []byte) (int, os.Error) { | |
| n := 0 | |
| i0 := 0 | |
| for i, ch := range data { | |
| if ch == '\n' || ch == '\f' { | |
| // write text segment and indentation | |
| n1, _ := s.output.Write(data[i0 : i+1]) | |
| n2, _ := s.output.Write(s.indent.Bytes()) | |
| n += n1 + n2 | |
| i0 = i + 1 | |
| s.linePos.Offset = s.output.Len() | |
| s.linePos.Line++ | |
| } | |
| } | |
| n3, _ := s.output.Write(data[i0:]) | |
| return n + n3, nil | |
| } | |
| type checkpoint struct { | |
| env Environment | |
| hasOutput bool | |
| outputLen int | |
| linePos token.Position | |
| } | |
| func (s *State) save() checkpoint { | |
| saved := checkpoint{nil, s.hasOutput, s.output.Len(), s.linePos} | |
| if s.env != nil { | |
| saved.env = s.env.Copy() | |
| } | |
| return saved | |
| } | |
| func (s *State) restore(m checkpoint) { | |
| s.env = m.env | |
| s.output.Truncate(m.outputLen) | |
| } | |
| func (s *State) error(msg string) { | |
| s.errors <- os.NewError(msg) | |
| runtime.Goexit() | |
| } | |
| // TODO At the moment, unnamed types are simply mapped to the default | |
| // names below. For instance, all unnamed arrays are mapped to | |
| // 'array' which is not really sufficient. Eventually one may want | |
| // to be able to specify rules for say an unnamed slice of T. | |
| // | |
| func typename(typ reflect.Type) string { | |
| switch typ.Kind() { | |
| case reflect.Array: | |
| return "array" | |
| case reflect.Slice: | |
| return "array" | |
| case reflect.Chan: | |
| return "chan" | |
| case reflect.Func: | |
| return "func" | |
| case reflect.Interface: | |
| return "interface" | |
| case reflect.Map: | |
| return "map" | |
| case reflect.Ptr: | |
| return "ptr" | |
| } | |
| return typ.String() | |
| } | |
| func (s *State) getFormat(name string) expr { | |
| if fexpr, found := s.fmt[name]; found { | |
| return fexpr | |
| } | |
| if s.default_ != nil { | |
| return s.default_ | |
| } | |
| s.error(fmt.Sprintf("no format rule for type: '%s'", name)) | |
| return nil | |
| } | |
| // eval applies a format expression fexpr to a value. If the expression | |
| // evaluates internally to a non-nil []byte, that slice is appended to | |
| // the state's output buffer and eval returns true. Otherwise, eval | |
| // returns false and the state remains unchanged. | |
| // | |
| func (s *State) eval(fexpr expr, value reflect.Value, index int) bool { | |
| // an empty format expression always evaluates | |
| // to a non-nil (but empty) []byte | |
| if fexpr == nil { | |
| return true | |
| } | |
| switch t := fexpr.(type) { | |
| case alternatives: | |
| // append the result of the first alternative that evaluates to | |
| // a non-nil []byte to the state's output | |
| mark := s.save() | |
| for _, x := range t { | |
| if s.eval(x, value, index) { | |
| return true | |
| } | |
| s.restore(mark) | |
| } | |
| return false | |
| case sequence: | |
| // append the result of all operands to the state's output | |
| // unless a nil result is encountered | |
| mark := s.save() | |
| for _, x := range t { | |
| if !s.eval(x, value, index) { | |
| s.restore(mark) | |
| return false | |
| } | |
| } | |
| return true | |
| case literal: | |
| // write separator, if any | |
| if s.hasOutput { | |
| // not the first literal | |
| if s.separator != nil { | |
| sep := s.separator // save current separator | |
| s.separator = nil // and disable it (avoid recursion) | |
| mark := s.save() | |
| if !s.eval(sep, value, index) { | |
| s.restore(mark) | |
| } | |
| s.separator = sep // enable it again | |
| } | |
| } | |
| s.hasOutput = true | |
| // write literal segments | |
| for _, lit := range t { | |
| if len(lit) > 1 && lit[0] == '%' { | |
| // segment contains a %-format at the beginning | |
| if lit[1] == '%' { | |
| // "%%" is printed as a single "%" | |
| s.Write(lit[1:]) | |
| } else { | |
| // use s instead of s.output to get indentation right | |
| fmt.Fprintf(s, string(lit), value.Interface()) | |
| } | |
| } else { | |
| // segment contains no %-formats | |
| s.Write(lit) | |
| } | |
| } | |
| return true // a literal never evaluates to nil | |
| case *field: | |
| // determine field value | |
| switch t.fieldName { | |
| case "@": | |
| // field value is current value | |
| case "*": | |
| // indirection: operation is type-specific | |
| switch v := value; v.Kind() { | |
| case reflect.Array: | |
| if v.Len() <= index { | |
| return false | |
| } | |
| value = v.Index(index) | |
| case reflect.Slice: | |
| if v.IsNil() || v.Len() <= index { | |
| return false | |
| } | |
| value = v.Index(index) | |
| case reflect.Map: | |
| s.error("reflection support for maps incomplete") | |
| case reflect.Ptr: | |
| if v.IsNil() { | |
| return false | |
| } | |
| value = v.Elem() | |
| case reflect.Interface: | |
| if v.IsNil() { | |
| return false | |
| } | |
| value = v.Elem() | |
| case reflect.Chan: | |
| s.error("reflection support for chans incomplete") | |
| case reflect.Func: | |
| s.error("reflection support for funcs incomplete") | |
| default: | |
| s.error(fmt.Sprintf("error: * does not apply to `%s`", value.Type())) | |
| } | |
| default: | |
| // value is value of named field | |
| var field reflect.Value | |
| if sval := value; sval.Kind() == reflect.Struct { | |
| field = sval.FieldByName(t.fieldName) | |
| if !field.IsValid() { | |
| // TODO consider just returning false in this case | |
| s.error(fmt.Sprintf("error: no field `%s` in `%s`", t.fieldName, value.Type())) | |
| } | |
| } | |
| value = field | |
| } | |
| // determine rule | |
| ruleName := t.ruleName | |
| if ruleName == "" { | |
| // no alternate rule name, value type determines rule | |
| ruleName = typename(value.Type()) | |
| } | |
| fexpr = s.getFormat(ruleName) | |
| mark := s.save() | |
| if !s.eval(fexpr, value, index) { | |
| s.restore(mark) | |
| return false | |
| } | |
| return true | |
| case *group: | |
| // remember current indentation | |
| indentLen := s.indent.Len() | |
| // update current indentation | |
| mark := s.save() | |
| s.eval(t.indent, value, index) | |
| // if the indentation evaluates to nil, the state's output buffer | |
| // didn't change - either way it's ok to append the difference to | |
| // the current indentation | |
| s.indent.Write(s.output.Bytes()[mark.outputLen:s.output.Len()]) | |
| s.restore(mark) | |
| // format group body | |
| mark = s.save() | |
| b := true | |
| if !s.eval(t.body, value, index) { | |
| s.restore(mark) | |
| b = false | |
| } | |
| // reset indentation | |
| s.indent.Truncate(indentLen) | |
| return b | |
| case *option: | |
| // evaluate the body and append the result to the state's output | |
| // buffer unless the result is nil | |
| mark := s.save() | |
| if !s.eval(t.body, value, 0) { // TODO is 0 index correct? | |
| s.restore(mark) | |
| } | |
| return true // an option never evaluates to nil | |
| case *repetition: | |
| // evaluate the body and append the result to the state's output | |
| // buffer until a result is nil | |
| for i := 0; ; i++ { | |
| mark := s.save() | |
| // write separator, if any | |
| if i > 0 && t.separator != nil { | |
| // nil result from separator is ignored | |
| mark := s.save() | |
| if !s.eval(t.separator, value, i) { | |
| s.restore(mark) | |
| } | |
| } | |
| if !s.eval(t.body, value, i) { | |
| s.restore(mark) | |
| break | |
| } | |
| } | |
| return true // a repetition never evaluates to nil | |
| case *custom: | |
| // invoke the custom formatter to obtain the result | |
| mark := s.save() | |
| if !t.fun(s, value.Interface(), t.ruleName) { | |
| s.restore(mark) | |
| return false | |
| } | |
| return true | |
| } | |
| panic("unreachable") | |
| return false | |
| } | |
| // Eval formats each argument according to the format | |
| // f and returns the resulting []byte and os.Error. If | |
| // an error occurred, the []byte contains the partially | |
| // formatted result. An environment env may be passed | |
| // in which is available in custom formatters through | |
| // the state parameter. | |
| // | |
| func (f Format) Eval(env Environment, args ...interface{}) ([]byte, os.Error) { | |
| if f == nil { | |
| return nil, os.NewError("format is nil") | |
| } | |
| errors := make(chan os.Error) | |
| s := newState(f, env, errors) | |
| go func() { | |
| for _, v := range args { | |
| fld := reflect.ValueOf(v) | |
| if !fld.IsValid() { | |
| errors <- os.NewError("nil argument") | |
| return | |
| } | |
| mark := s.save() | |
| if !s.eval(s.getFormat(typename(fld.Type())), fld, 0) { // TODO is 0 index correct? | |
| s.restore(mark) | |
| } | |
| } | |
| errors <- nil // no errors | |
| }() | |
| err := <-errors | |
| return s.output.Bytes(), err | |
| } | |
| // ---------------------------------------------------------------------------- | |
| // Convenience functions | |
| // Fprint formats each 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) Fprint(w io.Writer, env Environment, args ...interface{}) (int, os.Error) { | |
| data, err := f.Eval(env, args...) | |
| if err != nil { | |
| // TODO should we print partial result in case of error? | |
| return 0, err | |
| } | |
| return w.Write(data) | |
| } | |
| // Print formats each 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) Print(args ...interface{}) (int, os.Error) { | |
| return f.Fprint(os.Stdout, nil, args...) | |
| } | |
| // Sprint formats each argument according to the format f | |
| // and returns the resulting string. If an error occurs | |
| // during formatting, the result string contains the | |
| // partially formatted result followed by an error message. | |
| // | |
| func (f Format) Sprint(args ...interface{}) string { | |
| var buf bytes.Buffer | |
| _, err := f.Fprint(&buf, nil, args...) | |
| if err != nil { | |
| var i interface{} = args | |
| fmt.Fprintf(&buf, "--- Sprint(%s) failed: %v", fmt.Sprint(i), err) | |
| } | |
| return buf.String() | |
| } |