pax_global_header00006660000000000000000000000064131006032330014501gustar00rootroot0000000000000052 comment=e6f5723bf2a66af014955e0888881314cf294129 toml-0.1.1/000077500000000000000000000000001310060323300124535ustar00rootroot00000000000000toml-0.1.1/.travis.yml000066400000000000000000000001361310060323300145640ustar00rootroot00000000000000language: go go: - 1.3 - 1.x install: - go get -t -v ./... script: - go test ./... toml-0.1.1/LICENSE000066400000000000000000000020621310060323300134600ustar00rootroot00000000000000Copyright (c) 2014 Naoya Inada Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. toml-0.1.1/README.md000066400000000000000000000151041310060323300137330ustar00rootroot00000000000000# TOML parser and encoder library for Golang [![Build Status](https://travis-ci.org/naoina/toml.png?branch=master)](https://travis-ci.org/naoina/toml) [TOML](https://github.com/toml-lang/toml) parser and encoder library for [Golang](http://golang.org/). This library is compatible with TOML version [v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md). ## Installation go get -u github.com/naoina/toml ## Usage The following TOML save as `example.toml`. ```toml # This is a TOML document. Boom. title = "TOML Example" [owner] name = "Lance Uppercut" dob = 1979-05-27T07:32:00-08:00 # First class dates? Why not? [database] server = "192.168.1.1" ports = [ 8001, 8001, 8002 ] connection_max = 5000 enabled = true [servers] # You can indent as you please. Tabs or spaces. TOML don't care. [servers.alpha] ip = "10.0.0.1" dc = "eqdc10" [servers.beta] ip = "10.0.0.2" dc = "eqdc10" [clients] data = [ ["gamma", "delta"], [1, 2] ] # Line breaks are OK when inside arrays hosts = [ "alpha", "omega" ] ``` Then above TOML will mapping to `tomlConfig` struct using `toml.Unmarshal`. ```go package main import ( "io/ioutil" "os" "time" "github.com/naoina/toml" ) type tomlConfig struct { Title string Owner struct { Name string Dob time.Time } Database struct { Server string Ports []int ConnectionMax uint Enabled bool } Servers map[string]ServerInfo Clients struct { Data [][]interface{} Hosts []string } } type ServerInfo struct { IP net.IP DC string } func main() { f, err := os.Open("example.toml") if err != nil { panic(err) } defer f.Close() var config Config if err := toml.NewDecoder(f).Decode(&config); err != nil { panic(err) } // then to use the unmarshaled config... fmt.Println("IP of server 'alpha':", config.Servers["alpha"].IP) } ``` ## Mappings A key and value of TOML will map to the corresponding field. The fields of struct for mapping must be exported. The rules of the mapping of key are following: #### Exact matching ```toml timeout_seconds = 256 ``` ```go type Config struct { Timeout_seconds int } ``` #### Camelcase matching ```toml server_name = "srv1" ``` ```go type Config struct { ServerName string } ``` #### Uppercase matching ```toml ip = "10.0.0.1" ``` ```go type Config struct { IP string } ``` See the following examples for the value mappings. ### String ```toml val = "string" ``` ```go type Config struct { Val string } ``` ### Integer ```toml val = 100 ``` ```go type Config struct { Val int } ``` All types that can be used are following: * int8 (from `-128` to `127`) * int16 (from `-32768` to `32767`) * int32 (from `-2147483648` to `2147483647`) * int64 (from `-9223372036854775808` to `9223372036854775807`) * int (same as `int32` on 32bit environment, or `int64` on 64bit environment) * uint8 (from `0` to `255`) * uint16 (from `0` to `65535`) * uint32 (from `0` to `4294967295`) * uint64 (from `0` to `18446744073709551615`) * uint (same as `uint` on 32bit environment, or `uint64` on 64bit environment) ### Float ```toml val = 3.1415 ``` ```go type Config struct { Val float32 } ``` All types that can be used are following: * float32 * float64 ### Boolean ```toml val = true ``` ```go type Config struct { Val bool } ``` ### Datetime ```toml val = 2014-09-28T21:27:39Z ``` ```go type Config struct { Val time.Time } ``` ### Array ```toml val = ["a", "b", "c"] ``` ```go type Config struct { Val []string } ``` Also following examples all can be mapped: ```toml val1 = [1, 2, 3] val2 = [["a", "b"], ["c", "d"]] val3 = [[1, 2, 3], ["a", "b", "c"]] val4 = [[1, 2, 3], [["a", "b"], [true, false]]] ``` ```go type Config struct { Val1 []int Val2 [][]string Val3 [][]interface{} Val4 [][]interface{} } ``` ### Table ```toml [server] type = "app" [server.development] ip = "10.0.0.1" [server.production] ip = "10.0.0.2" ``` ```go type Config struct { Server map[string]Server } type Server struct { IP string } ``` You can also use the following struct instead of map of struct. ```go type Config struct { Server struct { Development Server Production Server } } type Server struct { IP string } ``` ### Array of Tables ```toml [[fruit]] name = "apple" [fruit.physical] color = "red" shape = "round" [[fruit.variety]] name = "red delicious" [[fruit.variety]] name = "granny smith" [[fruit]] name = "banana" [[fruit.variety]] name = "plantain" ``` ```go type Config struct { Fruit []struct { Name string Physical struct { Color string Shape string } Variety []struct { Name string } } } ``` ### Using the `encoding.TextUnmarshaler` interface Package toml supports `encoding.TextUnmarshaler` (and `encoding.TextMarshaler`). You can use it to apply custom marshaling rules for certain types. The `UnmarshalText` method is called with the value text found in the TOML input. TOML strings are passed unquoted. ```toml duration = "10s" ``` ```go import time type Duration time.Duration // UnmarshalText implements encoding.TextUnmarshaler func (d *Duration) UnmarshalText(data []byte) error { duration, err := time.ParseDuration(string(data)) if err == nil { *d = Duration(duration) } return err } // MarshalText implements encoding.TextMarshaler func (d Duration) MarshalText() ([]byte, error) { return []byte(time.Duration(d).String()), nil } type ConfigWithDuration struct { Duration Duration } ``` ### Using the `toml.UnmarshalerRec` interface You can also override marshaling rules specifically for TOML using the `UnmarshalerRec` and `MarshalerRec` interfaces. These are useful if you want to control how structs or arrays are handled. You can apply additional validation or set unexported struct fields. Note: `encoding.TextUnmarshaler` and `encoding.TextMarshaler` should be preferred for simple (scalar) values because they're also compatible with other formats like JSON or YAML. [See the UnmarshalerRec example](https://godoc.org/github.com/naoina/toml/#example_UnmarshalerRec). ### Using the `toml.Unmarshaler` interface If you want to deal with raw TOML syntax, use the `Unmarshaler` and `Marshaler` interfaces. Their input and output is raw TOML syntax. As such, these interfaces are useful if you want to handle TOML at the syntax level. [See the Unmarshaler example](https://godoc.org/github.com/naoina/toml/#example_Unmarshaler). ## API documentation See [Godoc](http://godoc.org/github.com/naoina/toml). ## License MIT toml-0.1.1/ast/000077500000000000000000000000001310060323300132425ustar00rootroot00000000000000toml-0.1.1/ast/ast.go000066400000000000000000000053561310060323300143710ustar00rootroot00000000000000package ast import ( "strconv" "strings" "time" ) type Position struct { Begin int End int } type Value interface { Pos() int End() int Source() string } type String struct { Position Position Value string Data []rune } func (s *String) Pos() int { return s.Position.Begin } func (s *String) End() int { return s.Position.End } func (s *String) Source() string { return string(s.Data) } type Integer struct { Position Position Value string Data []rune } func (i *Integer) Pos() int { return i.Position.Begin } func (i *Integer) End() int { return i.Position.End } func (i *Integer) Source() string { return string(i.Data) } func (i *Integer) Int() (int64, error) { return strconv.ParseInt(i.Value, 10, 64) } type Float struct { Position Position Value string Data []rune } func (f *Float) Pos() int { return f.Position.Begin } func (f *Float) End() int { return f.Position.End } func (f *Float) Source() string { return string(f.Data) } func (f *Float) Float() (float64, error) { return strconv.ParseFloat(f.Value, 64) } type Boolean struct { Position Position Value string Data []rune } func (b *Boolean) Pos() int { return b.Position.Begin } func (b *Boolean) End() int { return b.Position.End } func (b *Boolean) Source() string { return string(b.Data) } func (b *Boolean) Boolean() (bool, error) { return strconv.ParseBool(b.Value) } type Datetime struct { Position Position Value string Data []rune } func (d *Datetime) Pos() int { return d.Position.Begin } func (d *Datetime) End() int { return d.Position.End } func (d *Datetime) Source() string { return string(d.Data) } func (d *Datetime) Time() (time.Time, error) { switch { case !strings.Contains(d.Value, ":"): return time.Parse("2006-01-02", d.Value) case !strings.Contains(d.Value, "-"): return time.Parse("15:04:05.999999999", d.Value) default: return time.Parse(time.RFC3339Nano, d.Value) } } type Array struct { Position Position Value []Value Data []rune } func (a *Array) Pos() int { return a.Position.Begin } func (a *Array) End() int { return a.Position.End } func (a *Array) Source() string { return string(a.Data) } type TableType uint8 const ( TableTypeNormal TableType = iota TableTypeArray ) var tableTypes = [...]string{ "normal", "array", } func (t TableType) String() string { return tableTypes[t] } type Table struct { Position Position Line int Name string Fields map[string]interface{} Type TableType Data []rune } func (t *Table) Pos() int { return t.Position.Begin } func (t *Table) End() int { return t.Position.End } func (t *Table) Source() string { return string(t.Data) } type KeyValue struct { Key string Value Value Line int } toml-0.1.1/config.go000066400000000000000000000055671310060323300142640ustar00rootroot00000000000000package toml import ( "fmt" "io" "reflect" "strings" stringutil "github.com/naoina/go-stringutil" "github.com/naoina/toml/ast" ) // Config contains options for encoding and decoding. type Config struct { // NormFieldName is used to match TOML keys to struct fields. The function runs for // both input keys and struct field names and should return a string that makes the // two match. You must set this field to use the decoder. // // Example: The function in the default config removes _ and lowercases all keys. This // allows a key called 'api_key' to match the struct field 'APIKey' because both are // normalized to 'apikey'. // // Note that NormFieldName is not used for fields which define a TOML // key through the struct tag. NormFieldName func(typ reflect.Type, keyOrField string) string // FieldToKey determines the TOML key of a struct field when encoding. // You must set this field to use the encoder. // // Note that FieldToKey is not used for fields which define a TOML // key through the struct tag. FieldToKey func(typ reflect.Type, field string) string // MissingField, if non-nil, is called when the decoder encounters a key for which no // matching struct field exists. The default behavior is to return an error. MissingField func(typ reflect.Type, key string) error } // DefaultConfig contains the default options for encoding and decoding. // Snake case (i.e. 'foo_bar') is used for key names. var DefaultConfig = Config{ NormFieldName: defaultNormFieldName, FieldToKey: snakeCase, } func defaultNormFieldName(typ reflect.Type, s string) string { return strings.Replace(strings.ToLower(s), "_", "", -1) } func snakeCase(typ reflect.Type, s string) string { return stringutil.ToSnakeCase(s) } func defaultMissingField(typ reflect.Type, key string) error { return fmt.Errorf("field corresponding to `%s' is not defined in %v", key, typ) } // NewEncoder returns a new Encoder that writes to w. // It is shorthand for DefaultConfig.NewEncoder(w). func NewEncoder(w io.Writer) *Encoder { return DefaultConfig.NewEncoder(w) } // Marshal returns the TOML encoding of v. // It is shorthand for DefaultConfig.Marshal(v). func Marshal(v interface{}) ([]byte, error) { return DefaultConfig.Marshal(v) } // Unmarshal parses the TOML data and stores the result in the value pointed to by v. // It is shorthand for DefaultConfig.Unmarshal(data, v). func Unmarshal(data []byte, v interface{}) error { return DefaultConfig.Unmarshal(data, v) } // UnmarshalTable applies the contents of an ast.Table to the value pointed at by v. // It is shorthand for DefaultConfig.UnmarshalTable(t, v). func UnmarshalTable(t *ast.Table, v interface{}) error { return DefaultConfig.UnmarshalTable(t, v) } // NewDecoder returns a new Decoder that reads from r. // It is shorthand for DefaultConfig.NewDecoder(r). func NewDecoder(r io.Reader) *Decoder { return DefaultConfig.NewDecoder(r) } toml-0.1.1/config_test.go000066400000000000000000000032561310060323300153140ustar00rootroot00000000000000package toml import ( "bytes" "reflect" "strings" "testing" ) func TestConfigNormField(t *testing.T) { cfg := Config{NormFieldName: func(reflect.Type, string) string { return "a" }} var x struct{ B int } input := []byte(`a = 1`) if err := cfg.Unmarshal(input, &x); err != nil { t.Fatal(err) } if x.B != 1 { t.Fatalf("wrong value after Unmarshal: got %d, want %d", x.B, 1) } dec := cfg.NewDecoder(strings.NewReader(`a = 2`)) if err := dec.Decode(&x); err != nil { t.Fatal(err) } if x.B != 2 { t.Fatalf("wrong value after Decode: got %d, want %d", x.B, 2) } tbl, _ := Parse([]byte(`a = 3`)) if err := cfg.UnmarshalTable(tbl, &x); err != nil { t.Fatal(err) } if x.B != 3 { t.Fatalf("wrong value after UnmarshalTable: got %d, want %d", x.B, 3) } } func TestConfigFieldToKey(t *testing.T) { cfg := Config{FieldToKey: func(reflect.Type, string) string { return "A" }} x := struct{ B int }{B: 999} enc, err := cfg.Marshal(&x) if err != nil { t.Fatal(err) } if !bytes.Equal(enc, []byte("A = 999\n")) { t.Fatalf(`got %q, want "A = 999"`, enc) } } func TestConfigMissingField(t *testing.T) { calls := make(map[string]bool) cfg := Config{ NormFieldName: func(rt reflect.Type, field string) string { return field }, MissingField: func(rt reflect.Type, field string) error { calls[field] = true return nil }, } var x struct{ B int } input := []byte(` A = 1 B = 2 `) if err := cfg.Unmarshal(input, &x); err != nil { t.Fatal(err) } if x.B != 2 { t.Errorf("wrong value after Unmarshal: got %d, want %d", x.B, 1) } if !calls["A"] { t.Error("MissingField not called for 'A'") } if calls["B"] { t.Error("MissingField called for 'B'") } } toml-0.1.1/decode.go000066400000000000000000000304311310060323300142260ustar00rootroot00000000000000// Package toml encodes and decodes the TOML configuration format using reflection. // // This library is compatible with TOML version v0.4.0. package toml import ( "encoding" "fmt" "io" "io/ioutil" "reflect" "strconv" "strings" "time" "github.com/naoina/toml/ast" ) const ( tableSeparator = '.' ) var ( escapeReplacer = strings.NewReplacer( "\b", "\\n", "\f", "\\f", "\n", "\\n", "\r", "\\r", "\t", "\\t", ) underscoreReplacer = strings.NewReplacer( "_", "", ) ) var timeType = reflect.TypeOf(time.Time{}) // Unmarshal parses the TOML data and stores the result in the value pointed to by v. // // Unmarshal will mapped to v that according to following rules: // // TOML strings to string // TOML integers to any int type // TOML floats to float32 or float64 // TOML booleans to bool // TOML datetimes to time.Time // TOML arrays to any type of slice // TOML tables to struct or map // TOML array tables to slice of struct or map func (cfg *Config) Unmarshal(data []byte, v interface{}) error { table, err := Parse(data) if err != nil { return err } if err := cfg.UnmarshalTable(table, v); err != nil { return err } return nil } // A Decoder reads and decodes TOML from an input stream. type Decoder struct { r io.Reader cfg *Config } // NewDecoder returns a new Decoder that reads from r. // Note that it reads all from r before parsing it. func (cfg *Config) NewDecoder(r io.Reader) *Decoder { return &Decoder{r, cfg} } // Decode parses the TOML data from its input and stores it in the value pointed to by v. // See the documentation for Unmarshal for details about the conversion of TOML into a Go value. func (d *Decoder) Decode(v interface{}) error { b, err := ioutil.ReadAll(d.r) if err != nil { return err } return d.cfg.Unmarshal(b, v) } // UnmarshalerRec may be implemented by types to customize their behavior when being // unmarshaled from TOML. You can use it to implement custom validation or to set // unexported fields. // // UnmarshalTOML receives a function that can be called to unmarshal the original TOML // value into a field or variable. It is safe to call the function more than once if // necessary. type UnmarshalerRec interface { UnmarshalTOML(fn func(interface{}) error) error } // Unmarshaler can be used to capture and process raw TOML source of a table or value. // UnmarshalTOML must copy the input if it wishes to retain it after returning. // // Note: this interface is retained for backwards compatibility. You probably want // to implement encoding.TextUnmarshaler or UnmarshalerRec instead. type Unmarshaler interface { UnmarshalTOML(input []byte) error } // UnmarshalTable applies the contents of an ast.Table to the value pointed at by v. // // UnmarshalTable will mapped to v that according to following rules: // // TOML strings to string // TOML integers to any int type // TOML floats to float32 or float64 // TOML booleans to bool // TOML datetimes to time.Time // TOML arrays to any type of slice // TOML tables to struct or map // TOML array tables to slice of struct or map func (cfg *Config) UnmarshalTable(t *ast.Table, v interface{}) error { rv := reflect.ValueOf(v) toplevelMap := rv.Kind() == reflect.Map if (!toplevelMap && rv.Kind() != reflect.Ptr) || rv.IsNil() { return &invalidUnmarshalError{reflect.TypeOf(v)} } return unmarshalTable(cfg, rv, t, toplevelMap) } // used for UnmarshalerRec. func unmarshalTableOrValue(cfg *Config, rv reflect.Value, av interface{}) error { if (rv.Kind() != reflect.Ptr && rv.Kind() != reflect.Map) || rv.IsNil() { return &invalidUnmarshalError{rv.Type()} } rv = indirect(rv) switch av.(type) { case *ast.KeyValue, *ast.Table, []*ast.Table: if err := unmarshalField(cfg, rv, av); err != nil { return lineError(fieldLineNumber(av), err) } return nil case ast.Value: return setValue(cfg, rv, av.(ast.Value)) default: panic(fmt.Sprintf("BUG: unhandled AST node type %T", av)) } } // unmarshalTable unmarshals the fields of a table into a struct or map. // // toplevelMap is true when rv is an (unadressable) map given to UnmarshalTable. In this // (special) case, the map is used as-is instead of creating a new map. func unmarshalTable(cfg *Config, rv reflect.Value, t *ast.Table, toplevelMap bool) error { rv = indirect(rv) if err, ok := setUnmarshaler(cfg, rv, t); ok { return lineError(t.Line, err) } switch { case rv.Kind() == reflect.Struct: fc := makeFieldCache(cfg, rv.Type()) for key, fieldAst := range t.Fields { fv, fieldName, err := fc.findField(cfg, rv, key) if err != nil { return lineError(fieldLineNumber(fieldAst), err) } if fv.IsValid() { if err := unmarshalField(cfg, fv, fieldAst); err != nil { return lineErrorField(fieldLineNumber(fieldAst), rv.Type().String()+"."+fieldName, err) } } } case rv.Kind() == reflect.Map || isEface(rv): m := rv if !toplevelMap { if rv.Kind() == reflect.Interface { m = reflect.ValueOf(make(map[string]interface{})) } else { m = reflect.MakeMap(rv.Type()) } } elemtyp := m.Type().Elem() for key, fieldAst := range t.Fields { kv, err := unmarshalMapKey(m.Type().Key(), key) if err != nil { return lineError(fieldLineNumber(fieldAst), err) } fv := reflect.New(elemtyp).Elem() if err := unmarshalField(cfg, fv, fieldAst); err != nil { return lineError(fieldLineNumber(fieldAst), err) } m.SetMapIndex(kv, fv) } if !toplevelMap { rv.Set(m) } default: return lineError(t.Line, &unmarshalTypeError{"table", "struct or map", rv.Type()}) } return nil } func fieldLineNumber(fieldAst interface{}) int { switch av := fieldAst.(type) { case *ast.KeyValue: return av.Line case *ast.Table: return av.Line case []*ast.Table: return av[0].Line default: panic(fmt.Sprintf("BUG: unhandled node type %T", fieldAst)) } } func unmarshalField(cfg *Config, rv reflect.Value, fieldAst interface{}) error { switch av := fieldAst.(type) { case *ast.KeyValue: return setValue(cfg, rv, av.Value) case *ast.Table: return unmarshalTable(cfg, rv, av, false) case []*ast.Table: rv = indirect(rv) if err, ok := setUnmarshaler(cfg, rv, fieldAst); ok { return err } var slice reflect.Value switch { case rv.Kind() == reflect.Slice: slice = reflect.MakeSlice(rv.Type(), len(av), len(av)) case isEface(rv): slice = reflect.ValueOf(make([]interface{}, len(av))) default: return &unmarshalTypeError{"array table", "slice", rv.Type()} } for i, tbl := range av { vv := reflect.New(slice.Type().Elem()).Elem() if err := unmarshalTable(cfg, vv, tbl, false); err != nil { return err } slice.Index(i).Set(vv) } rv.Set(slice) default: panic(fmt.Sprintf("BUG: unhandled AST node type %T", av)) } return nil } func unmarshalMapKey(typ reflect.Type, key string) (reflect.Value, error) { rv := reflect.New(typ).Elem() if u, ok := rv.Addr().Interface().(encoding.TextUnmarshaler); ok { return rv, u.UnmarshalText([]byte(key)) } switch typ.Kind() { case reflect.String: rv.SetString(key) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: i, err := strconv.ParseInt(key, 10, int(typ.Size()*8)) if err != nil { return rv, convertNumError(typ.Kind(), err) } rv.SetInt(i) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: i, err := strconv.ParseUint(key, 10, int(typ.Size()*8)) if err != nil { return rv, convertNumError(typ.Kind(), err) } rv.SetUint(i) default: return rv, fmt.Errorf("invalid map key type %s", typ) } return rv, nil } func setValue(cfg *Config, lhs reflect.Value, val ast.Value) error { lhs = indirect(lhs) if err, ok := setUnmarshaler(cfg, lhs, val); ok { return err } if err, ok := setTextUnmarshaler(lhs, val); ok { return err } switch v := val.(type) { case *ast.Integer: return setInt(lhs, v) case *ast.Float: return setFloat(lhs, v) case *ast.String: return setString(lhs, v) case *ast.Boolean: return setBoolean(lhs, v) case *ast.Datetime: return setDatetime(lhs, v) case *ast.Array: return setArray(cfg, lhs, v) default: panic(fmt.Sprintf("BUG: unhandled node type %T", v)) } } func indirect(rv reflect.Value) reflect.Value { for rv.Kind() == reflect.Ptr { if rv.IsNil() { rv.Set(reflect.New(rv.Type().Elem())) } rv = rv.Elem() } return rv } func setUnmarshaler(cfg *Config, lhs reflect.Value, av interface{}) (error, bool) { if lhs.CanAddr() { if u, ok := lhs.Addr().Interface().(UnmarshalerRec); ok { err := u.UnmarshalTOML(func(v interface{}) error { return unmarshalTableOrValue(cfg, reflect.ValueOf(v), av) }) return err, true } if u, ok := lhs.Addr().Interface().(Unmarshaler); ok { return u.UnmarshalTOML(unmarshalerSource(av)), true } } return nil, false } func unmarshalerSource(av interface{}) []byte { var source []byte switch av := av.(type) { case []*ast.Table: for i, tab := range av { source = append(source, tab.Source()...) if i != len(av)-1 { source = append(source, '\n') } } case ast.Value: source = []byte(av.Source()) default: panic(fmt.Sprintf("BUG: unhandled node type %T", av)) } return source } func setTextUnmarshaler(lhs reflect.Value, val ast.Value) (error, bool) { if !lhs.CanAddr() { return nil, false } u, ok := lhs.Addr().Interface().(encoding.TextUnmarshaler) if !ok || lhs.Type() == timeType { return nil, false } var data string switch val := val.(type) { case *ast.Array: return &unmarshalTypeError{"array", "", lhs.Type()}, true case *ast.String: data = val.Value default: data = val.Source() } return u.UnmarshalText([]byte(data)), true } func setInt(fv reflect.Value, v *ast.Integer) error { k := fv.Kind() switch { case k >= reflect.Int && k <= reflect.Int64: i, err := strconv.ParseInt(v.Value, 10, int(fv.Type().Size()*8)) if err != nil { return convertNumError(fv.Kind(), err) } fv.SetInt(i) case k >= reflect.Uint && k <= reflect.Uintptr: i, err := strconv.ParseUint(v.Value, 10, int(fv.Type().Size()*8)) if err != nil { return convertNumError(fv.Kind(), err) } fv.SetUint(i) case isEface(fv): i, err := strconv.ParseInt(v.Value, 10, 64) if err != nil { return convertNumError(reflect.Int64, err) } fv.Set(reflect.ValueOf(i)) default: return &unmarshalTypeError{"integer", "", fv.Type()} } return nil } func setFloat(fv reflect.Value, v *ast.Float) error { f, err := v.Float() if err != nil { return err } switch { case fv.Kind() == reflect.Float32 || fv.Kind() == reflect.Float64: if fv.OverflowFloat(f) { return &overflowError{fv.Kind(), v.Value} } fv.SetFloat(f) case isEface(fv): fv.Set(reflect.ValueOf(f)) default: return &unmarshalTypeError{"float", "", fv.Type()} } return nil } func setString(fv reflect.Value, v *ast.String) error { switch { case fv.Kind() == reflect.String: fv.SetString(v.Value) case isEface(fv): fv.Set(reflect.ValueOf(v.Value)) default: return &unmarshalTypeError{"string", "", fv.Type()} } return nil } func setBoolean(fv reflect.Value, v *ast.Boolean) error { b, _ := v.Boolean() switch { case fv.Kind() == reflect.Bool: fv.SetBool(b) case isEface(fv): fv.Set(reflect.ValueOf(b)) default: return &unmarshalTypeError{"boolean", "", fv.Type()} } return nil } func setDatetime(rv reflect.Value, v *ast.Datetime) error { t, err := v.Time() if err != nil { return err } if !timeType.AssignableTo(rv.Type()) { return &unmarshalTypeError{"datetime", "", rv.Type()} } rv.Set(reflect.ValueOf(t)) return nil } func setArray(cfg *Config, rv reflect.Value, v *ast.Array) error { var slicetyp reflect.Type switch { case rv.Kind() == reflect.Slice: slicetyp = rv.Type() case isEface(rv): slicetyp = reflect.SliceOf(rv.Type()) default: return &unmarshalTypeError{"array", "slice", rv.Type()} } if len(v.Value) == 0 { // Ensure defined slices are always set to a non-nil value. rv.Set(reflect.MakeSlice(slicetyp, 0, 0)) return nil } tomltyp := reflect.TypeOf(v.Value[0]) slice := reflect.MakeSlice(slicetyp, len(v.Value), len(v.Value)) typ := slicetyp.Elem() for i, vv := range v.Value { if i > 0 && tomltyp != reflect.TypeOf(vv) { return errArrayMultiType } tmp := reflect.New(typ).Elem() if err := setValue(cfg, tmp, vv); err != nil { return err } slice.Index(i).Set(tmp) } rv.Set(slice) return nil } func isEface(rv reflect.Value) bool { return rv.Kind() == reflect.Interface && rv.Type().NumMethod() == 0 } toml-0.1.1/decode_bench_test.go000066400000000000000000000003661310060323300164300ustar00rootroot00000000000000package toml import ( "testing" ) func BenchmarkUnmarshal(b *testing.B) { var v testStruct data := loadTestData("test.toml") b.ResetTimer() for i := 0; i < b.N; i++ { if err := Unmarshal(data, &v); err != nil { b.Fatal(err) } } } toml-0.1.1/decode_test.go000066400000000000000000000774341310060323300153030ustar00rootroot00000000000000package toml import ( "errors" "fmt" "io/ioutil" "path/filepath" "reflect" "testing" "time" "github.com/kylelemons/godebug/pretty" ) func loadTestData(file string) []byte { f := filepath.Join("testdata", file) data, err := ioutil.ReadFile(f) if err != nil { panic(err) } return data } func mustTime(tm time.Time, err error) time.Time { if err != nil { panic(err) } return tm } type Name struct { First string Last string } type Inline struct { Name Name Point map[string]int } type Subtable struct { Key string } type Table struct { Key string Subtable Subtable Inline Inline } type W struct { } type Z struct { W W } type Y struct { Z Z } type X struct { Y Y } type Basic struct { Basic string } type Continued struct { Key1 string Key2 string Key3 string } type Multiline struct { Key1 string Key2 string Key3 string Continued Continued } type LiteralMultiline struct { Regex2 string Lines string } type Literal struct { Winpath string Winpath2 string Quoted string Regex string Multiline LiteralMultiline } type String struct { Basic Basic Multiline Multiline Literal Literal } type IntegerUnderscores struct { Key1 int Key2 int Key3 int } type Integer struct { Key1 int Key2 int Key3 int Key4 int Underscores IntegerUnderscores } type Fractional struct { Key1 float64 Key2 float64 Key3 float64 } type Exponent struct { Key1 float64 Key2 float64 Key3 float64 } type Both struct { Key float64 } type FloatUnderscores struct { Key1 float64 Key2 float64 } type Float struct { Fractional Fractional Exponent Exponent Both Both Underscores FloatUnderscores } type Boolean struct { True bool False bool } type Datetime struct { Key1 time.Time Key2 time.Time Key3 time.Time } type Array struct { Key1 []int Key2 []string Key3 [][]int Key4 [][]interface{} Key5 []int Key6 []int } type Product struct { Name string `toml:",omitempty"` Sku int64 `toml:",omitempty"` Color string `toml:",omitempty"` } type Physical struct { Color string Shape string } type Variety struct { Name string } type Fruit struct { Name string Physical Physical Variety []Variety } type testStruct struct { Table Table X X String String Integer Integer Float Float Boolean Boolean Datetime Datetime Array Array Products []Product Fruit []Fruit } func theTestStruct() *testStruct { return &testStruct{ Table: Table{ Key: "value", Subtable: Subtable{ Key: "another value", }, Inline: Inline{ Name: Name{ First: "Tom", Last: "Preston-Werner", }, Point: map[string]int{ "x": 1, "y": 2, }, }, }, X: X{}, String: String{ Basic: Basic{ Basic: "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF.", }, Multiline: Multiline{ Key1: "One\nTwo", Key2: "One\nTwo", Key3: "One\nTwo", Continued: Continued{ Key1: "The quick brown fox jumps over the lazy dog.", Key2: "The quick brown fox jumps over the lazy dog.", Key3: "The quick brown fox jumps over the lazy dog.", }, }, Literal: Literal{ Winpath: `C:\Users\nodejs\templates`, Winpath2: `\\ServerX\admin$\system32\`, Quoted: `Tom "Dubs" Preston-Werner`, Regex: `<\i\c*\s*>`, Multiline: LiteralMultiline{ Regex2: `I [dw]on't need \d{2} apples`, Lines: "The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n", }, }, }, Integer: Integer{ Key1: 99, Key2: 42, Key3: 0, Key4: -17, Underscores: IntegerUnderscores{ Key1: 1000, Key2: 5349221, Key3: 12345, }, }, Float: Float{ Fractional: Fractional{ Key1: 1.0, Key2: 3.1415, Key3: -0.01, }, Exponent: Exponent{ Key1: 5e22, Key2: 1e6, Key3: -2e-2, }, Both: Both{ Key: 6.626e-34, }, Underscores: FloatUnderscores{ Key1: 9224617.445991228313, Key2: 1e100, }, }, Boolean: Boolean{ True: true, False: false, }, Datetime: Datetime{ Key1: mustTime(time.Parse(time.RFC3339Nano, "1979-05-27T07:32:00Z")), Key2: mustTime(time.Parse(time.RFC3339Nano, "1979-05-27T00:32:00-07:00")), Key3: mustTime(time.Parse(time.RFC3339Nano, "1979-05-27T00:32:00.999999-07:00")), }, Array: Array{ Key1: []int{1, 2, 3}, Key2: []string{"red", "yellow", "green"}, Key3: [][]int{{1, 2}, {3, 4, 5}}, Key4: [][]interface{}{{int64(1), int64(2)}, {"a", "b", "c"}}, Key5: []int{1, 2, 3}, Key6: []int{1, 2}, }, Products: []Product{ {Name: "Hammer", Sku: 738594937}, {}, {Name: "Nail", Sku: 284758393, Color: "gray"}, }, Fruit: []Fruit{ { Name: "apple", Physical: Physical{ Color: "red", Shape: "round", }, Variety: []Variety{ {Name: "red delicious"}, {Name: "granny smith"}, }, }, { Name: "banana", Variety: []Variety{ {Name: "plantain"}, }, }, }, } } func TestUnmarshal(t *testing.T) { testUnmarshal(t, []testcase{ { data: string(loadTestData("test.toml")), expect: theTestStruct(), }, }) } type testcase struct { data string err error expect interface{} } func testUnmarshal(t *testing.T, testcases []testcase) { for _, test := range testcases { // Create a test value of the same type as expect. typ := reflect.TypeOf(test.expect) var val interface{} if typ.Kind() == reflect.Map { val = reflect.MakeMap(typ).Interface() } else if typ.Kind() == reflect.Ptr { val = reflect.New(typ.Elem()).Interface() } else { panic("invalid 'expect' type " + typ.String()) } err := Unmarshal([]byte(test.data), val) if !reflect.DeepEqual(err, test.err) { t.Errorf("Error mismatch for input:\n%s\ngot: %+v\nwant: %+v", test.data, err, test.err) } if err == nil && !reflect.DeepEqual(val, test.expect) { t.Errorf("Unmarshal value mismatch for input:\n%s\ndiff:\n%s", test.data, pretty.Compare(val, test.expect)) } } } func TestUnmarshal_WithString(t *testing.T) { type testStruct struct { Str string Key1 string Key2 string Key3 string Winpath string Winpath2 string Quoted string Regex string Regex2 string Lines string } testUnmarshal(t, []testcase{ { data: `str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."`, expect: &testStruct{ Str: "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF.", }, }, { data: string(loadTestData("unmarshal-string-1.toml")), expect: &testStruct{Key1: "One\nTwo", Key2: "One\nTwo", Key3: "One\nTwo"}, }, { data: string(loadTestData("unmarshal-string-2.toml")), expect: &testStruct{ Key1: "The quick brown fox jumps over the lazy dog.", Key2: "The quick brown fox jumps over the lazy dog.", Key3: "The quick brown fox jumps over the lazy dog.", }, }, { data: string(loadTestData("unmarshal-string-3.toml")), expect: &testStruct{ Winpath: `C:\Users\nodejs\templates`, Winpath2: `\\ServerX\admin$\system32\`, Quoted: `Tom "Dubs" Preston-Werner`, Regex: `<\i\c*\s*>`, }, }, { data: string(loadTestData("unmarshal-string-4.toml")), expect: &testStruct{ Regex2: `I [dw]on't need \d{2} apples`, Lines: "The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n", }, }, }) } func TestUnmarshal_WithInteger(t *testing.T) { type testStruct struct { Intval int64 } testUnmarshal(t, []testcase{ {`intval = 0`, nil, &testStruct{0}}, {`intval = +0`, nil, &testStruct{0}}, {`intval = -0`, nil, &testStruct{-0}}, {`intval = 1`, nil, &testStruct{1}}, {`intval = +1`, nil, &testStruct{1}}, {`intval = -1`, nil, &testStruct{-1}}, {`intval = 10`, nil, &testStruct{10}}, {`intval = 777`, nil, &testStruct{777}}, {`intval = 2147483647`, nil, &testStruct{2147483647}}, {`intval = 2147483648`, nil, &testStruct{2147483648}}, {`intval = +2147483648`, nil, &testStruct{2147483648}}, {`intval = -2147483648`, nil, &testStruct{-2147483648}}, {`intval = -2147483649`, nil, &testStruct{-2147483649}}, {`intval = 9223372036854775807`, nil, &testStruct{9223372036854775807}}, {`intval = +9223372036854775807`, nil, &testStruct{9223372036854775807}}, {`intval = -9223372036854775808`, nil, &testStruct{-9223372036854775808}}, {`intval = 1_000`, nil, &testStruct{1000}}, {`intval = 5_349_221`, nil, &testStruct{5349221}}, {`intval = 1_2_3_4_5`, nil, &testStruct{12345}}, // overflow { data: `intval = 9223372036854775808`, err: lineErrorField(1, "toml.testStruct.Intval", &overflowError{reflect.Int64, "9223372036854775808"}), expect: &testStruct{}, }, { data: `intval = +9223372036854775808`, err: lineErrorField(1, "toml.testStruct.Intval", &overflowError{reflect.Int64, "+9223372036854775808"}), expect: &testStruct{}, }, { data: `intval = -9223372036854775809`, err: lineErrorField(1, "toml.testStruct.Intval", &overflowError{reflect.Int64, "-9223372036854775809"}), expect: &testStruct{}, }, // invalid _ {`intval = _1_000`, lineError(1, errParse), &testStruct{}}, {`intval = 1_000_`, lineError(1, errParse), &testStruct{}}, }) } func TestUnmarshal_WithFloat(t *testing.T) { type testStruct struct { Floatval float64 } testUnmarshal(t, []testcase{ {`floatval = 0.0`, nil, &testStruct{0.0}}, {`floatval = +0.0`, nil, &testStruct{0.0}}, {`floatval = -0.0`, nil, &testStruct{-0.0}}, {`floatval = 0.1`, nil, &testStruct{0.1}}, {`floatval = +0.1`, nil, &testStruct{0.1}}, {`floatval = -0.1`, nil, &testStruct{-0.1}}, {`floatval = 0.2`, nil, &testStruct{0.2}}, {`floatval = +0.2`, nil, &testStruct{0.2}}, {`floatval = -0.2`, nil, &testStruct{-0.2}}, {`floatval = 1.0`, nil, &testStruct{1.0}}, {`floatval = +1.0`, nil, &testStruct{1.0}}, {`floatval = -1.0`, nil, &testStruct{-1.0}}, {`floatval = 1.1`, nil, &testStruct{1.1}}, {`floatval = +1.1`, nil, &testStruct{1.1}}, {`floatval = -1.1`, nil, &testStruct{-1.1}}, {`floatval = 3.1415`, nil, &testStruct{3.1415}}, {`floatval = +3.1415`, nil, &testStruct{3.1415}}, {`floatval = -3.1415`, nil, &testStruct{-3.1415}}, {`floatval = 10.2e5`, nil, &testStruct{10.2e5}}, {`floatval = +10.2e5`, nil, &testStruct{10.2e5}}, {`floatval = -10.2e5`, nil, &testStruct{-10.2e5}}, {`floatval = 10.2E5`, nil, &testStruct{10.2e5}}, {`floatval = +10.2E5`, nil, &testStruct{10.2e5}}, {`floatval = -10.2E5`, nil, &testStruct{-10.2e5}}, {`floatval = 5e+22`, nil, &testStruct{5e+22}}, {`floatval = 1e6`, nil, &testStruct{1e6}}, {`floatval = -2E-2`, nil, &testStruct{-2E-2}}, {`floatval = 6.626e-34`, nil, &testStruct{6.626e-34}}, {`floatval = 9_224_617.445_991_228_313`, nil, &testStruct{9224617.445991228313}}, {`floatval = 1e1_00`, nil, &testStruct{1e100}}, {`floatval = 1e02`, nil, &testStruct{1e2}}, {`floatval = _1e1_00`, lineError(1, errParse), &testStruct{}}, {`floatval = 1e1_00_`, lineError(1, errParse), &testStruct{}}, }) } func TestUnmarshal_WithBoolean(t *testing.T) { type testStruct struct { Boolval bool } testUnmarshal(t, []testcase{ {`boolval = true`, nil, &testStruct{true}}, {`boolval = false`, nil, &testStruct{false}}, }) } func TestUnmarshal_WithDatetime(t *testing.T) { type testStruct struct { Datetimeval time.Time } testUnmarshal(t, []testcase{ {`datetimeval = 1979-05-27T07:32:00Z`, nil, &testStruct{ mustTime(time.Parse(time.RFC3339Nano, "1979-05-27T07:32:00Z")), }}, {`datetimeval = 2014-09-13T12:37:39Z`, nil, &testStruct{ mustTime(time.Parse(time.RFC3339Nano, "2014-09-13T12:37:39Z")), }}, {`datetimeval = 1979-05-27T00:32:00-07:00`, nil, &testStruct{ mustTime(time.Parse(time.RFC3339Nano, "1979-05-27T00:32:00-07:00")), }}, {`datetimeval = 1979-05-27T00:32:00.999999-07:00`, nil, &testStruct{ mustTime(time.Parse(time.RFC3339Nano, "1979-05-27T00:32:00.999999-07:00")), }}, {`datetimeval = 1979-05-27`, nil, &testStruct{ mustTime(time.Parse(time.RFC3339, "1979-05-27T00:00:00Z")), }}, {`datetimeval = 07:32:00`, nil, &testStruct{ mustTime(time.Parse(time.RFC3339, "0000-01-01T07:32:00Z")), }}, {`datetimeval = 00:32:00.999999`, nil, &testStruct{ mustTime(time.Parse(time.RFC3339Nano, "0000-01-01T00:32:00.999999Z")), }}, }) } func TestUnmarshal_WithArray(t *testing.T) { type arrays struct { Ints []int Strings []string } testUnmarshal(t, []testcase{ {`ints = []`, nil, &arrays{Ints: []int{}}}, {`ints = [ 1 ]`, nil, &arrays{Ints: []int{1}}}, {`ints = [ 1, 2, 3 ]`, nil, &arrays{Ints: []int{1, 2, 3}}}, {`ints = [ 1, 2, 3, ]`, nil, &arrays{Ints: []int{1, 2, 3}}}, {`strings = ["red", "yellow", "green"]`, nil, &arrays{Strings: []string{"red", "yellow", "green"}}}, { data: `strings = [ "all", 'strings', """are the same""", '''type''']`, expect: &arrays{Strings: []string{"all", "strings", "are the same", "type"}}, }, {`arrayval = [[1,2],[3,4,5]]`, nil, &struct{ Arrayval [][]int }{ [][]int{ {1, 2}, {3, 4, 5}, }, }}, {`arrayval = [ [ 1, 2 ], ["a", "b", "c"] ] # this is ok`, nil, &struct{ Arrayval [][]interface{} }{ [][]interface{}{ {int64(1), int64(2)}, {"a", "b", "c"}, }, }}, {`arrayval = [ [ 1, 2 ], [ [3, 4], [5, 6] ] ] # this is ok`, nil, &struct{ Arrayval [][]interface{} }{ [][]interface{}{ {int64(1), int64(2)}, { []interface{}{int64(3), int64(4)}, []interface{}{int64(5), int64(6)}, }, }, }}, {`arrayval = [ [ 1, 2 ], [ [3, 4], [5, 6], [7, 8] ] ] # this is ok`, nil, &struct{ Arrayval [][]interface{} }{ [][]interface{}{ {int64(1), int64(2)}, { []interface{}{int64(3), int64(4)}, []interface{}{int64(5), int64(6)}, []interface{}{int64(7), int64(8)}, }, }, }}, {`arrayval = [ [[ 1, 2 ]], [3, 4], [5, 6] ] # this is ok`, nil, &struct{ Arrayval [][]interface{} }{ [][]interface{}{ { []interface{}{int64(1), int64(2)}, }, {int64(3), int64(4)}, {int64(5), int64(6)}, }, }}, { data: `ints = [ 1, 2.0 ] # note: this is NOT ok`, err: lineErrorField(1, "toml.arrays.Ints", errArrayMultiType), expect: &arrays{}, }, // whitespace + comments {string(loadTestData("unmarshal-array-1.toml")), nil, &arrays{Ints: []int{1, 2, 3}}}, {string(loadTestData("unmarshal-array-2.toml")), nil, &arrays{Ints: []int{1, 2, 3}}}, {string(loadTestData("unmarshal-array-3.toml")), nil, &arrays{Ints: []int{1, 2, 3}}}, {string(loadTestData("unmarshal-array-4.toml")), nil, &arrays{Ints: []int{1, 2, 3}}}, {string(loadTestData("unmarshal-array-5.toml")), nil, &arrays{Ints: []int{1, 2, 3}}}, {string(loadTestData("unmarshal-array-6.toml")), nil, &arrays{Ints: []int{1, 2, 3}}}, // parse errors {`ints = [ , ]`, lineError(1, errParse), &arrays{}}, {`ints = [ , 1 ]`, lineError(1, errParse), &arrays{}}, {`ints = [ 1 2 ]`, lineError(1, errParse), &arrays{}}, {`ints = [ 1 , , 2 ]`, lineError(1, errParse), &arrays{}}, }) } func TestUnmarshal_WithTable(t *testing.T) { type W struct{} type Z struct { W W } type Y struct { Z Z } type X struct { Y Y } type A struct { D int B struct { C int } } type testStruct struct { Table struct { Key string } Dog struct { Tater struct{} } X X A A } type testIgnoredFieldStruct struct { Ignored string `toml:"-"` } type testNamedFieldStruct struct { Named string `toml:"Named_Field"` } type testQuotedKeyStruct struct { Dog struct { TaterMan struct { Type string } `toml:"tater.man"` } } type testQuotedKeyWithWhitespaceStruct struct { Dog struct { TaterMan struct { Type string } `toml:"tater . man"` } } type testStructWithMap struct { Servers map[string]struct { IP string DC string } } type withTableArray struct { Tabarray []map[string]string } testUnmarshal(t, []testcase{ {`[table]`, nil, &testStruct{}}, {`[table] key = "value"`, nil, &testStruct{ Table: struct { Key string }{ Key: "value", }, }}, {`[dog.tater]`, nil, &testStruct{ Dog: struct { Tater struct{} }{ Tater: struct{}{}, }, }}, {`[dog."tater.man"] type = "pug"`, nil, &testQuotedKeyStruct{ Dog: struct { TaterMan struct { Type string } `toml:"tater.man"` }{ TaterMan: struct { Type string }{ Type: "pug", }, }, }}, {`[dog."tater . man"] type = "pug"`, nil, &testQuotedKeyWithWhitespaceStruct{ Dog: struct { TaterMan struct { Type string } `toml:"tater . man"` }{ TaterMan: struct { Type string }{ Type: "pug", }, }, }}, {`[x.y.z.w] # for this to work`, nil, &testStruct{ X: X{}, }}, {`[ x . y . z . w ]`, nil, &testStruct{ X: X{}, }}, {`[ x . "y" . z . "w" ]`, nil, &testStruct{ X: X{}, }}, {`table = {}`, nil, &testStruct{}}, {`table = { key = "value" }`, nil, &testStruct{ Table: struct { Key string }{ Key: "value", }, }}, {`x = { y = { "z" = { w = {} } } }`, nil, &testStruct{X: X{}}}, {`[a.b] c = 1 [a] d = 2`, nil, &testStruct{ A: struct { D int B struct { C int } }{ D: 2, B: struct { C int }{ C: 1, }, }, }}, { data: `Named_Field = "value"`, expect: &testNamedFieldStruct{Named: "value"}, }, { data: string(loadTestData("unmarshal-table-withmap.toml")), expect: &testStructWithMap{ Servers: map[string]struct { IP string DC string }{ "alpha": {IP: "10.0.0.1", DC: "eqdc10"}, "beta": {IP: "10.0.0.2", DC: "eqdc10"}, }, }, }, { data: string(loadTestData("unmarshal-table-withinline.toml")), expect: map[string]withTableArray{ "tab1": {Tabarray: []map[string]string{{"key": "1"}}}, "tab2": {Tabarray: []map[string]string{{"key": "2"}}}, }, }, // errors { data: string(loadTestData("unmarshal-table-conflict-1.toml")), err: lineError(7, fmt.Errorf("table `a' is in conflict with table in line 4")), expect: &testStruct{}, }, { data: string(loadTestData("unmarshal-table-conflict-2.toml")), err: lineError(7, fmt.Errorf("table `a.b' is in conflict with line 5")), expect: &testStruct{}, }, { data: string(loadTestData("unmarshal-table-conflict-3.toml")), err: lineError(8, fmt.Errorf("key `b' is in conflict with table in line 4")), expect: &testStruct{}, }, {`[]`, lineError(1, errParse), &testStruct{}}, {`[a.]`, lineError(1, errParse), &testStruct{}}, {`[a..b]`, lineError(1, errParse), &testStruct{}}, {`[.b]`, lineError(1, errParse), &testStruct{}}, {`[.]`, lineError(1, errParse), &testStruct{}}, {` = "no key name" # not allowed`, lineError(1, errParse), &testStruct{}}, { data: `ignored = "value"`, err: lineError(1, fmt.Errorf("field corresponding to `ignored' in toml.testIgnoredFieldStruct cannot be set through TOML")), expect: &testIgnoredFieldStruct{}, }, { data: `"-" = "value"`, err: lineError(1, fmt.Errorf("field corresponding to `-' is not defined in toml.testIgnoredFieldStruct")), expect: &testIgnoredFieldStruct{}, }, { data: `named = "value"`, err: lineError(1, fmt.Errorf("field corresponding to `named' is not defined in toml.testNamedFieldStruct")), expect: &testNamedFieldStruct{}, }, { data: ` [a] d = 2 y = 3 `, err: lineError(4, fmt.Errorf("field corresponding to `y' is not defined in toml.A")), expect: &testStruct{}, }, }) } func TestUnmarshal_WithEmbeddedStruct(t *testing.T) { type TestEmbStructA struct { A string } testUnmarshal(t, []testcase{ { data: `a = "value"`, expect: &struct { TestEmbStructA A string }{ A: "value", }, }, { data: `a = "value"`, expect: &struct { A string TestEmbStructA }{ A: "value", }, }, }) } func TestUnmarshal_WithArrayTable(t *testing.T) { type Product struct { Name string SKU int64 Color string } type Physical struct { Color string Shape string } type Variety struct { Name string } type Fruit struct { Name string Physical Physical Variety []Variety } type testStruct struct { Products []Product Fruit []Fruit } type testStructWithMap struct { Fruit []map[string][]struct { Name string } } testUnmarshal(t, []testcase{ { data: string(loadTestData("unmarshal-arraytable.toml")), expect: &testStruct{ Products: []Product{ {Name: "Hammer", SKU: 738594937}, {}, {Name: "Nail", SKU: 284758393, Color: "gray"}, }, }, }, { data: string(loadTestData("unmarshal-arraytable-inline.toml")), expect: &testStruct{ Products: []Product{ {Name: "Hammer", SKU: 738594937}, {}, {Name: "Nail", SKU: 284758393, Color: "gray"}, }, }, }, { data: string(loadTestData("unmarshal-arraytable-nested-1.toml")), expect: &testStruct{ Fruit: []Fruit{ { Name: "apple", Physical: Physical{ Color: "red", Shape: "round", }, Variety: []Variety{ {Name: "red delicious"}, {Name: "granny smith"}, }, }, { Name: "banana", Physical: Physical{ Color: "yellow", Shape: "lune", }, Variety: []Variety{ {Name: "plantain"}, }, }, }, }, }, { data: string(loadTestData("unmarshal-arraytable-nested-2.toml")), expect: &testStructWithMap{ Fruit: []map[string][]struct { Name string }{ {"variety": {{Name: "red delicious"}, {Name: "granny smith"}}}, {"variety": {{Name: "plantain"}}, "area": {{Name: "phillippines"}}}, }, }, }, { data: string(loadTestData("unmarshal-arraytable-nested-3.toml")), expect: &testStructWithMap{ Fruit: []map[string][]struct { Name string }{ {"variety": {{Name: "red delicious"}, {Name: "granny smith"}}}, {"variety": {{Name: "plantain"}}, "area": {{Name: "phillippines"}}}, }, }, }, // errors { data: string(loadTestData("unmarshal-arraytable-conflict-1.toml")), err: lineError(10, fmt.Errorf("table `fruit.variety' is in conflict with array table in line 6")), expect: &testStruct{}, }, { data: string(loadTestData("unmarshal-arraytable-conflict-2.toml")), err: lineError(10, fmt.Errorf("array table `fruit.variety' is in conflict with table in line 6")), expect: &testStruct{}, }, { data: string(loadTestData("unmarshal-arraytable-conflict-3.toml")), err: lineError(8, fmt.Errorf("array table `fruit.variety' is in conflict with table in line 5")), expect: &testStruct{}, }, }) } type testUnmarshalerString string func (u *testUnmarshalerString) UnmarshalTOML(data []byte) error { *u = testUnmarshalerString("Unmarshaled: " + string(data)) return nil } type testUnmarshalerStruct struct { Title string Author testUnmarshalerString } func (u *testUnmarshalerStruct) UnmarshalTOML(data []byte) error { u.Title = "Unmarshaled: " + string(data) return nil } func TestUnmarshal_WithUnmarshaler(t *testing.T) { type testStruct struct { Title testUnmarshalerString MaxConn testUnmarshalerString Ports testUnmarshalerString Servers testUnmarshalerString Table testUnmarshalerString Arraytable testUnmarshalerString ArrayOfStruct []testUnmarshalerStruct } data := loadTestData("unmarshal-unmarshaler.toml") var v testStruct if err := Unmarshal(data, &v); err != nil { t.Fatal(err) } actual := v expect := testStruct{ Title: `Unmarshaled: "testtitle"`, MaxConn: `Unmarshaled: 777`, Ports: `Unmarshaled: [8080, 8081, 8082]`, Servers: `Unmarshaled: [1, 2, 3]`, Table: "Unmarshaled: [table]\nname = \"alice\"", Arraytable: "Unmarshaled: [[arraytable]]\nname = \"alice\"\n[[arraytable]]\nname = \"bob\"", ArrayOfStruct: []testUnmarshalerStruct{ { Title: "Unmarshaled: [[array_of_struct]]\ntitle = \"Alice's Adventures in Wonderland\"\nauthor = \"Lewis Carroll\"", Author: "", }, }, } if !reflect.DeepEqual(actual, expect) { t.Errorf(`toml.Unmarshal(data, &v); v => %#v; want %#v`, actual, expect) } } func TestUnmarshal_WithUnmarshalerForTopLevelStruct(t *testing.T) { data := `title = "Alice's Adventures in Wonderland" author = "Lewis Carroll" ` var v testUnmarshalerStruct if err := Unmarshal([]byte(data), &v); err != nil { t.Fatal(err) } actual := v expect := testUnmarshalerStruct{ Title: `Unmarshaled: title = "Alice's Adventures in Wonderland" author = "Lewis Carroll" `, Author: "", } if !reflect.DeepEqual(actual, expect) { t.Errorf(`toml.Unmarshal(data, &v); v => %#v; want %#v`, actual, expect) } } type testTextUnmarshaler string var errTextUnmarshaler = errors.New("UnmarshalText called with data = error") func (x *testTextUnmarshaler) UnmarshalText(data []byte) error { *x = testTextUnmarshaler("Unmarshaled: " + string(data)) if string(data) == "error" { return errTextUnmarshaler } return nil } func TestUnmarshal_WithTextUnmarshaler(t *testing.T) { type testStruct struct { Str testTextUnmarshaler Int testTextUnmarshaler Float testTextUnmarshaler Arraytable []testStruct } tests := []testcase{ { data: string(loadTestData("unmarshal-textunmarshaler.toml")), expect: &testStruct{ Str: "Unmarshaled: str", Int: "Unmarshaled: 11", Float: "Unmarshaled: 12.0", Arraytable: []testStruct{{Str: "Unmarshaled: str2", Int: "Unmarshaled: 22", Float: "Unmarshaled: 23.0"}}, }, }, { data: `str = "error"`, expect: &testStruct{Str: "Unmarshaled: error"}, err: lineErrorField(1, "toml.testStruct.Str", errTextUnmarshaler), }, } testUnmarshal(t, tests) } type testUnmarshalerRecString string func (u *testUnmarshalerRecString) UnmarshalTOML(fn func(interface{}) error) error { var s string if err := fn(&s); err != nil { return err } *u = testUnmarshalerRecString("Unmarshaled: " + s) return nil } type testUnmarshalerRecStruct struct { a, b int } func (u *testUnmarshalerRecStruct) UnmarshalTOML(fn func(interface{}) error) error { var uu struct{ A, B int } if err := fn(&uu); err != nil { return err } u.a, u.b = uu.A, uu.B return nil } func TestUnmarshal_WithUnmarshalerRec(t *testing.T) { type testStruct struct { String testUnmarshalerRecString Struct testUnmarshalerRecStruct Arraytable []testStruct } var v testStruct err := Unmarshal(loadTestData("unmarshal-unmarshalerrec.toml"), &v) if err != nil { t.Fatal("Unexpected error:", err) } expect := testStruct{ String: "Unmarshaled: str1", Struct: testUnmarshalerRecStruct{a: 1, b: 2}, Arraytable: []testStruct{ { String: "Unmarshaled: str2", Struct: testUnmarshalerRecStruct{a: 3, b: 4}, }, }, } if !reflect.DeepEqual(v, expect) { t.Errorf(`toml.Unmarshal(data, &v); v => %#v; want %#v`, v, expect) } } func TestUnmarshal_WithMultibyteString(t *testing.T) { type testStruct struct { Name string Numbers []string } v := testStruct{} data := `name = "七一〇七" numbers = ["壱", "弐", "参"] ` if err := Unmarshal([]byte(data), &v); err != nil { t.Fatal(err) } actual := v expect := testStruct{ Name: "七一〇七", Numbers: []string{"壱", "弐", "参"}, } if !reflect.DeepEqual(actual, expect) { t.Errorf(`toml.Unmarshal([]byte(data), &v); v => %#v; want %#v`, actual, expect) } } func TestUnmarshal_WithPointers(t *testing.T) { type Inline struct { Key1 string Key2 *string Key3 **string } type Table struct { Key1 *string Key2 **string Key3 ***string } type testStruct struct { Inline *Inline Tables []*Table } type testStruct2 struct { Inline **Inline Tables []**Table } type testStruct3 struct { Inline ***Inline Tables []***Table } s1 := "a" s2 := &s1 s3 := &s2 s4 := &s3 s5 := "b" s6 := &s5 s7 := &s6 s8 := &s7 i1 := &Inline{"test", s2, s7} i2 := &i1 i3 := &i2 t1 := &Table{s2, s3, s4} t2 := &Table{s6, s7, s8} t3 := &t1 t4 := &t2 sc := &testStruct{ Inline: i1, Tables: []*Table{t1, t2}, } data := string(loadTestData("unmarshal-pointer.toml")) testUnmarshal(t, []testcase{ {data, nil, sc}, {data, nil, &testStruct2{ Inline: i2, Tables: []**Table{&t1, &t2}, }}, {data, nil, &testStruct3{ Inline: i3, Tables: []***Table{&t3, &t4}, }}, }) } // This test checks that maps can be unmarshaled into directly. func TestUnmarshalMap(t *testing.T) { testUnmarshal(t, []testcase{ { data: ` name = "evan" foo = 1 `, expect: map[string]interface{}{"name": "evan", "foo": int64(1)}, }, { data: `[""] a = 1 `, expect: map[string]interface{}{"": map[string]interface{}{"a": int64(1)}}, }, { data: `["table"] a = 1 `, expect: map[string]interface{}{"table": map[string]interface{}{"a": int64(1)}}, }, { data: `["\u2222"] a = 1 `, expect: map[string]interface{}{"\u2222": map[string]interface{}{"a": int64(1)}}, }, { data: `[p] first = "evan" `, expect: map[string]*Name{"p": {First: "evan"}}, }, { data: `foo = 1 bar = 2 `, expect: map[testTextUnmarshaler]int{"Unmarshaled: foo": 1, "Unmarshaled: bar": 2}, }, { data: `"foo" = 1 "foo.bar" = 2 `, expect: map[testTextUnmarshaler]int{"Unmarshaled: foo": 1, "Unmarshaled: foo.bar": 2}, }, { data: `1 = 1 -2 = 2 `, expect: map[int]int{1: 1, -2: 2}, }, { data: `1 = 1 -129 = 2 `, expect: map[int8]int{1: 1}, err: lineError(2, &overflowError{reflect.Int8, "-129"}), }, }) } func TestUnmarshal_WithQuotedKeyValue(t *testing.T) { type nestedStruct struct { Truthy bool } type testStruct struct { Table map[string]nestedStruct } testUnmarshal(t, []testcase{ {data: `"a" = 1`, expect: map[string]int{"a": 1}}, {data: `"a.b" = 1`, expect: map[string]int{"a.b": 1}}, {data: `"\u2222" = 1`, expect: map[string]int{"\u2222": 1}}, {data: `"\"" = 1`, expect: map[string]int{"\"": 1}}, {data: `"" = 1`, expect: map[string]int{"": 1}}, {data: `'a' = 1`, expect: map[string]int{}, err: lineError(1, errParse)}, // Inline tables: { data: ` [table] "some.key" = {truthy = true} `, expect: &testStruct{Table: map[string]nestedStruct{ "some.key": {Truthy: true}, }}, }, { data: ` "some.key" = [{truthy = true}] `, expect: map[string][]nestedStruct{ "some.key": {{Truthy: true}}, }, }, }) } func TestUnmarshal_WithCustomPrimitiveType(t *testing.T) { type ( String string Int int Bool bool ) type X struct { S String I Int B Bool } input := ` s = "string" i = 1 b = true ` testUnmarshal(t, []testcase{ {input, nil, &X{"string", 1, true}}, }) } func TestUnmarshal_WithInterface(t *testing.T) { var exp interface{} = map[string]interface{}{ "string": "string", "int": int64(3), "float": float64(4), "boolean": true, "datetime": mustTime(time.Parse(time.RFC3339Nano, "1979-05-27T00:32:00.999999-07:00")), "array": []interface{}{int64(1), int64(2), int64(3)}, "inline": map[string]interface{}{"key": "value"}, "table": map[string]interface{}{"key": "value"}, "arraytable": []interface{}{ map[string]interface{}{"key": "value"}, map[string]interface{}{"key": "value"}, }, } type nonemptyIf interface { method() } nonemptyIfType := reflect.TypeOf((*nonemptyIf)(nil)).Elem() data := string(loadTestData("unmarshal-interface.toml")) testUnmarshal(t, []testcase{ {data, nil, &exp}, // can't unmarshal into non-empty interface{} {`v = "string"`, lineError(1, &unmarshalTypeError{"string", "", nonemptyIfType}), map[string]nonemptyIf{}}, {`v = 1`, lineError(1, &unmarshalTypeError{"integer", "", nonemptyIfType}), map[string]nonemptyIf{}}, {`v = 1.0`, lineError(1, &unmarshalTypeError{"float", "", nonemptyIfType}), map[string]nonemptyIf{}}, {`v = true`, lineError(1, &unmarshalTypeError{"boolean", "", nonemptyIfType}), map[string]nonemptyIf{}}, {`v = [1, 2]`, lineError(1, &unmarshalTypeError{"array", "slice", nonemptyIfType}), map[string]nonemptyIf{}}, {`[v]`, lineError(1, &unmarshalTypeError{"table", "struct or map", nonemptyIfType}), map[string]nonemptyIf{}}, {`[[v]]`, lineError(1, &unmarshalTypeError{"array table", "slice", nonemptyIfType}), map[string]nonemptyIf{}}, }) } toml-0.1.1/encode.go000066400000000000000000000244451310060323300142500ustar00rootroot00000000000000package toml import ( "bytes" "encoding" "fmt" "io" "reflect" "sort" "strconv" "time" "github.com/naoina/toml/ast" ) const ( tagOmitempty = "omitempty" tagSkip = "-" ) // Marshal returns the TOML encoding of v. // // Struct values encode as TOML. Each exported struct field becomes a field of // the TOML structure unless // - the field's tag is "-", or // - the field is empty and its tag specifies the "omitempty" option. // // The "toml" key in the struct field's tag value is the key name, followed by // an optional comma and options. Examples: // // // Field is ignored by this package. // Field int `toml:"-"` // // // Field appears in TOML as key "myName". // Field int `toml:"myName"` // // // Field appears in TOML as key "myName" and the field is omitted from the // // result of encoding if its value is empty. // Field int `toml:"myName,omitempty"` // // // Field appears in TOML as key "field", but the field is skipped if // // empty. Note the leading comma. // Field int `toml:",omitempty"` func (cfg *Config) Marshal(v interface{}) ([]byte, error) { buf := new(bytes.Buffer) err := cfg.NewEncoder(buf).Encode(v) return buf.Bytes(), err } // A Encoder writes TOML to an output stream. type Encoder struct { w io.Writer cfg *Config } // NewEncoder returns a new Encoder that writes to w. func (cfg *Config) NewEncoder(w io.Writer) *Encoder { return &Encoder{w, cfg} } // Encode writes the TOML of v to the stream. // See the documentation for Marshal for details about the conversion of Go values to TOML. func (e *Encoder) Encode(v interface{}) error { rv := reflect.ValueOf(v) for rv.Kind() == reflect.Ptr { if rv.IsNil() { return &marshalNilError{rv.Type()} } rv = rv.Elem() } buf := &tableBuf{typ: ast.TableTypeNormal} var err error switch rv.Kind() { case reflect.Struct: err = buf.structFields(e.cfg, rv) case reflect.Map: err = buf.mapFields(e.cfg, rv) default: err = &marshalTableError{rv.Type()} } if err != nil { return err } return buf.writeTo(e.w, "") } // Marshaler can be implemented to override the encoding of TOML values. The returned text // must be a simple TOML value (i.e. not a table) and is inserted into marshaler output. // // This interface exists for backwards-compatibility reasons. You probably want to // implement encoding.TextMarshaler or MarshalerRec instead. type Marshaler interface { MarshalTOML() ([]byte, error) } // MarshalerRec can be implemented to override the TOML encoding of a type. // The returned value is marshaled in place of the receiver. type MarshalerRec interface { MarshalTOML() (interface{}, error) } type tableBuf struct { name string // already escaped / quoted body []byte children []*tableBuf typ ast.TableType arrayDepth int } func (b *tableBuf) writeTo(w io.Writer, prefix string) error { key := b.name // TODO: escape dots if prefix != "" { key = prefix + "." + key } if b.name != "" { head := "[" + key + "]" if b.typ == ast.TableTypeArray { head = "[" + head + "]" } head += "\n" if _, err := io.WriteString(w, head); err != nil { return err } } if _, err := w.Write(b.body); err != nil { return err } for i, child := range b.children { if len(b.body) > 0 || i > 0 { if _, err := w.Write([]byte("\n")); err != nil { return err } } if err := child.writeTo(w, key); err != nil { return err } } return nil } func (b *tableBuf) newChild(name string) *tableBuf { child := &tableBuf{name: quoteName(name), typ: ast.TableTypeNormal} if b.arrayDepth > 0 { child.typ = ast.TableTypeArray } return child } func (b *tableBuf) addChild(child *tableBuf) { // Empty table elision: we can avoid writing a table that doesn't have any keys on its // own. Array tables can't be elided because they define array elements (which would // be missing if elided). if len(child.body) == 0 && child.typ == ast.TableTypeNormal { for _, gchild := range child.children { gchild.name = child.name + "." + gchild.name b.addChild(gchild) } return } b.children = append(b.children, child) } func (b *tableBuf) structFields(cfg *Config, rv reflect.Value) error { rt := rv.Type() for i := 0; i < rv.NumField(); i++ { ft := rt.Field(i) if ft.PkgPath != "" && !ft.Anonymous { // not exported continue } name, rest := extractTag(ft.Tag.Get(fieldTagName)) if name == tagSkip { continue } fv := rv.Field(i) if rest == tagOmitempty && isEmptyValue(fv) { continue } if name == "" { name = cfg.FieldToKey(rt, ft.Name) } if err := b.field(cfg, name, fv); err != nil { return err } } return nil } type mapKeyList []struct { key string value reflect.Value } func (l mapKeyList) Len() int { return len(l) } func (l mapKeyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } func (l mapKeyList) Less(i, j int) bool { return l[i].key < l[j].key } func (b *tableBuf) mapFields(cfg *Config, rv reflect.Value) error { keys := rv.MapKeys() keylist := make(mapKeyList, len(keys)) for i, key := range keys { var err error keylist[i].key, err = encodeMapKey(key) if err != nil { return err } keylist[i].value = rv.MapIndex(key) } sort.Sort(keylist) for _, kv := range keylist { if err := b.field(cfg, kv.key, kv.value); err != nil { return err } } return nil } func (b *tableBuf) field(cfg *Config, name string, rv reflect.Value) error { off := len(b.body) b.body = append(b.body, quoteName(name)...) b.body = append(b.body, " = "...) isTable, err := b.value(cfg, rv, name) if isTable { b.body = b.body[:off] // rub out "key =" } else { b.body = append(b.body, '\n') } return err } func (b *tableBuf) value(cfg *Config, rv reflect.Value, name string) (bool, error) { isMarshaler, isTable, err := b.marshaler(cfg, rv, name) if isMarshaler { return isTable, err } switch rv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: b.body = strconv.AppendInt(b.body, rv.Int(), 10) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: b.body = strconv.AppendUint(b.body, rv.Uint(), 10) case reflect.Float32, reflect.Float64: b.body = strconv.AppendFloat(b.body, rv.Float(), 'e', -1, 64) case reflect.Bool: b.body = strconv.AppendBool(b.body, rv.Bool()) case reflect.String: b.body = strconv.AppendQuote(b.body, rv.String()) case reflect.Ptr, reflect.Interface: if rv.IsNil() { return false, &marshalNilError{rv.Type()} } return b.value(cfg, rv.Elem(), name) case reflect.Slice, reflect.Array: rvlen := rv.Len() if rvlen == 0 { b.body = append(b.body, '[', ']') return false, nil } b.arrayDepth++ wroteElem := false b.body = append(b.body, '[') for i := 0; i < rvlen; i++ { isTable, err := b.value(cfg, rv.Index(i), name) if err != nil { return isTable, err } wroteElem = wroteElem || !isTable if wroteElem { if i < rvlen-1 { b.body = append(b.body, ',', ' ') } else { b.body = append(b.body, ']') } } } if !wroteElem { b.body = b.body[:len(b.body)-1] // rub out '[' } b.arrayDepth-- return !wroteElem, nil case reflect.Struct: child := b.newChild(name) err := child.structFields(cfg, rv) b.addChild(child) return true, err case reflect.Map: child := b.newChild(name) err := child.mapFields(cfg, rv) b.addChild(child) return true, err default: return false, fmt.Errorf("toml: marshal: unsupported type %v", rv.Kind()) } return false, nil } func (b *tableBuf) marshaler(cfg *Config, rv reflect.Value, name string) (handled, isTable bool, err error) { switch t := rv.Interface().(type) { case encoding.TextMarshaler: enc, err := t.MarshalText() if err != nil { return true, false, err } b.body = encodeTextMarshaler(b.body, string(enc)) return true, false, nil case MarshalerRec: newval, err := t.MarshalTOML() if err != nil { return true, false, err } isTable, err = b.value(cfg, reflect.ValueOf(newval), name) return true, isTable, err case Marshaler: enc, err := t.MarshalTOML() if err != nil { return true, false, err } b.body = append(b.body, enc...) return true, false, nil } return false, false, nil } func encodeTextMarshaler(buf []byte, v string) []byte { // Emit the value without quotes if possible. if v == "true" || v == "false" { return append(buf, v...) } else if _, err := time.Parse(time.RFC3339Nano, v); err == nil { return append(buf, v...) } else if _, err := strconv.ParseInt(v, 10, 64); err == nil { return append(buf, v...) } else if _, err := strconv.ParseUint(v, 10, 64); err == nil { return append(buf, v...) } else if _, err := strconv.ParseFloat(v, 64); err == nil { return append(buf, v...) } return strconv.AppendQuote(buf, v) } func encodeMapKey(rv reflect.Value) (string, error) { if rv.Kind() == reflect.String { return rv.String(), nil } if tm, ok := rv.Interface().(encoding.TextMarshaler); ok { b, err := tm.MarshalText() return string(b), err } switch rv.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return strconv.FormatInt(rv.Int(), 10), nil case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return strconv.FormatUint(rv.Uint(), 10), nil } return "", fmt.Errorf("toml: invalid map key type %v", rv.Type()) } func isEmptyValue(v reflect.Value) bool { switch v.Kind() { case reflect.Array: // encoding/json treats all arrays with non-zero length as non-empty. We check the // array content here because zero-length arrays are almost never used. len := v.Len() for i := 0; i < len; i++ { if !isEmptyValue(v.Index(i)) { return false } } return true case reflect.Map, reflect.Slice, reflect.String: return v.Len() == 0 case reflect.Bool: return !v.Bool() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return v.Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return v.Uint() == 0 case reflect.Float32, reflect.Float64: return v.Float() == 0 case reflect.Interface, reflect.Ptr: return v.IsNil() } return false } func quoteName(s string) string { if len(s) == 0 { return strconv.Quote(s) } for _, r := range s { if r >= '0' && r <= '9' || r >= 'A' && r <= 'Z' || r >= 'a' && r <= 'z' || r == '-' || r == '_' { continue } return strconv.Quote(s) } return s } toml-0.1.1/encode_test.go000066400000000000000000000130311310060323300152740ustar00rootroot00000000000000package toml import ( "bytes" "reflect" "testing" "time" "github.com/kylelemons/godebug/diff" "github.com/kylelemons/godebug/pretty" ) func init() { // These settings make 'mismatch' output look nicer. pretty.DefaultConfig.ShortList = 80 pretty.CompareConfig.ShortList = 80 } type testMarshaler struct{ S string } type testMarshalerPtr struct{ S string } func (t testMarshaler) MarshalTOML() ([]byte, error) { return []byte(t.S), nil } func (t *testMarshalerPtr) MarshalTOML() ([]byte, error) { return []byte(t.S), nil } type testMarshalerRec struct{ replacement interface{} } type testMarshalerRecPtr struct{ replacement interface{} } func (t testMarshalerRec) MarshalTOML() (interface{}, error) { return t.replacement, nil } func (t *testMarshalerRecPtr) MarshalTOML() (interface{}, error) { return t.replacement, nil } var marshalTests = []struct { v interface{} expect []byte }{ // single string: { v: struct{ Name string }{"alice"}, expect: []byte("name = \"alice\"\n"), }, // single int: { v: struct{ Age int }{7}, expect: []byte("age = 7\n"), }, // multiple fields: { v: struct { Name string Age int }{"alice", 7}, expect: []byte("name = \"alice\"\nage = 7\n"), }, // ignored fields: { v: struct { Name string `toml:"-"` Age int }{"alice", 7}, expect: []byte("age = 7\n"), }, // field name override: { v: struct { Name string `toml:"my_name"` }{"bob"}, expect: []byte("my_name = \"bob\"\n"), }, { v: struct { Name string `toml:"my_name,omitempty"` }{"bob"}, expect: []byte("my_name = \"bob\"\n"), }, // omitempty: { v: struct { Name string `toml:",omitempty"` }{"bob"}, expect: []byte("name = \"bob\"\n"), }, // slices: { v: struct { Ints []int }{[]int{1, 2, 3}}, expect: []byte("ints = [1, 2, 3]\n"), }, { v: struct { IntsOfInts [][]int }{[][]int{{}, {1}, {}, {2}, {3, 4}}}, expect: []byte("ints_of_ints = [[], [1], [], [2], [3, 4]]\n"), }, { v: struct { IntsOfInts [][]int }{[][]int{{1, 2}, {3, 4}}}, expect: []byte("ints_of_ints = [[1, 2], [3, 4]]\n"), }, // pointer: { v: struct{ Named *Name }{&Name{First: "name"}}, expect: []byte("[named]\nfirst = \"name\"\nlast = \"\"\n"), }, // canon test document: { v: theTestStruct(), expect: loadTestData("marshal-teststruct.toml"), }, // funky map key types: { v: map[string]interface{}{ "intKeys": map[int]int{1: 1, 2: 2, 3: 3}, "marshalerKeys": map[time.Time]int{time.Time{}: 1}, }, expect: loadTestData("marshal-funkymapkeys.toml"), }, // Marshaler: { v: map[string]interface{}{ "m1": testMarshaler{"1"}, "m2": &testMarshaler{"2"}, "m3": &testMarshalerPtr{"3"}, }, expect: loadTestData("marshal-marshaler.toml"), }, // MarshalerRec: { v: map[string]interface{}{ "m1": testMarshalerRec{1}, "m2": &testMarshalerRec{2}, "m3": &testMarshalerRecPtr{3}, "sub": &testMarshalerRec{map[string]interface{}{ "key": 1, }}, }, expect: loadTestData("marshal-marshalerrec.toml"), }, // key escaping: { v: map[string]interface{}{ "": "empty", " ": "space", "ʎǝʞ": "reverse", "1": "number (not quoted)", "-": "dash (not quoted)", "subtable with space": map[string]interface{}{ "depth": 1, "subsubtable with space": map[string]interface{}{ "depth": 2, }, }, }, expect: loadTestData("marshal-key-escape.toml"), }, } func TestMarshal(t *testing.T) { for _, test := range marshalTests { b, err := Marshal(test.v) if err != nil { t.Errorf("Unexpected error %v\nfor value:\n%s", err, pretty.Sprint(test.v)) } if d := checkOutput(b, test.expect); d != "" { t.Errorf("Output mismatch:\nValue:\n%s\nDiff:\n%s", pretty.Sprint(test.v), d) } } } func TestMarshalRoundTrip(t *testing.T) { v := theTestStruct() b, err := Marshal(v) if err != nil { t.Error("Unexpected Marshal error:", err) } dest := testStruct{} if err := Unmarshal(b, &dest); err != nil { t.Error("Unmarshal error:", err) } if !reflect.DeepEqual(theTestStruct(), &dest) { t.Errorf("Unmarshaled value mismatch:\n%s", pretty.Compare(v, dest)) } } func TestMarshalArrayTableEmptyParent(t *testing.T) { type Baz struct { Key int } type Bar struct { Baz Baz } type Foo struct { Bars []Bar } v := Foo{[]Bar{{Baz{1}}, {Baz{2}}}} b, err := Marshal(v) if err != nil { t.Fatal(err) } if d := checkOutput(b, loadTestData("marshal-arraytable-empty.toml")); d != "" { t.Errorf("Output mismatch:\n%s", d) } } func TestMarshalPointerError(t *testing.T) { type X struct{ Sub *X } want := &marshalNilError{reflect.TypeOf((*X)(nil))} if _, err := Marshal((*X)(nil)); !reflect.DeepEqual(err, want) { t.Errorf("Got %q, expected %q", err, want) } if _, err := Marshal(&X{nil}); !reflect.DeepEqual(err, want) { t.Errorf("Got %q, expected %q", err, want) } } func TestMarshalNonStruct(t *testing.T) { val := []string{} want := &marshalTableError{reflect.TypeOf(val)} if _, err := Marshal(val); !reflect.DeepEqual(err, want) { t.Errorf("Got %q, expected %q", err, want) } } func TestMarshalOmitempty(t *testing.T) { var x struct { ZeroArray [0]int `toml:",omitempty"` ZeroArray2 [10]int `toml:",omitempty"` Slice []int `toml:",omitempty"` Pointer *int `toml:",omitempty"` Int int `toml:",omitempty"` } out, err := Marshal(x) if err != nil { t.Fatal(err) } if len(out) > 0 { t.Fatalf("want no output, got %q", out) } } func checkOutput(got, want []byte) string { if bytes.Equal(got, want) { return "" } return diff.Diff(string(got), string(want)) } toml-0.1.1/error.go000066400000000000000000000043061310060323300141360ustar00rootroot00000000000000package toml import ( "errors" "fmt" "reflect" "strconv" ) var ( errArrayMultiType = errors.New("array can't contain multiple types") ) // LineError is returned by Unmarshal, UnmarshalTable and Parse // if the error is local to a line. type LineError struct { Line int StructField string Err error } func (err *LineError) Error() string { field := "" if err.StructField != "" { field = "(" + err.StructField + ") " } return fmt.Sprintf("line %d: %s%v", err.Line, field, err.Err) } func lineError(line int, err error) error { if err == nil { return nil } if _, ok := err.(*LineError); ok { return err } return &LineError{Line: line, Err: err} } func lineErrorField(line int, field string, err error) error { if lerr, ok := err.(*LineError); ok { return lerr } else if err != nil { err = &LineError{Line: line, StructField: field, Err: err} } return err } type overflowError struct { kind reflect.Kind v string } func (err *overflowError) Error() string { return fmt.Sprintf("value %s is out of range for %v", err.v, err.kind) } func convertNumError(kind reflect.Kind, err error) error { if numerr, ok := err.(*strconv.NumError); ok && numerr.Err == strconv.ErrRange { return &overflowError{kind, numerr.Num} } return err } type invalidUnmarshalError struct { typ reflect.Type } func (err *invalidUnmarshalError) Error() string { if err.typ == nil { return "toml: Unmarshal(nil)" } if err.typ.Kind() != reflect.Ptr { return "toml: Unmarshal(non-pointer " + err.typ.String() + ")" } return "toml: Unmarshal(nil " + err.typ.String() + ")" } type unmarshalTypeError struct { what string want string typ reflect.Type } func (err *unmarshalTypeError) Error() string { msg := fmt.Sprintf("cannot unmarshal TOML %s into %s", err.what, err.typ) if err.want != "" { msg += " (need " + err.want + ")" } return msg } type marshalNilError struct { typ reflect.Type } func (err *marshalNilError) Error() string { return fmt.Sprintf("toml: cannot marshal nil %s", err.typ) } type marshalTableError struct { typ reflect.Type } func (err *marshalTableError) Error() string { return fmt.Sprintf("toml: cannot marshal %s as table, want struct or map type", err.typ) } toml-0.1.1/example_decoder_test.go000066400000000000000000000014321310060323300171610ustar00rootroot00000000000000package toml_test import ( "fmt" "net" "os" "time" "github.com/naoina/toml" ) type Config struct { Title string Owner struct { Name string Org string `toml:"organization"` Bio string Dob time.Time } Database struct { Server string Ports []int ConnectionMax uint Enabled bool } Servers map[string]ServerInfo Clients struct { Data [][]interface{} Hosts []string } } type ServerInfo struct { IP net.IP DC string } func Example() { f, err := os.Open("testdata/example.toml") if err != nil { panic(err) } defer f.Close() var config Config if err := toml.NewDecoder(f).Decode(&config); err != nil { panic(err) } fmt.Println("IP of server 'alpha':", config.Servers["alpha"].IP) // Output: IP of server 'alpha': 10.0.0.1 } toml-0.1.1/example_marshaler_rec_test.go000066400000000000000000000031631310060323300203660ustar00rootroot00000000000000package toml_test import ( "errors" "fmt" "net" "time" "github.com/naoina/toml" ) // This example shows how the UnmarshalerRec interface can be used to apply field // validations and default values. type Server struct { Addr string // ":" Timeout time.Duration // defaults to 10s } // UnmarshalTOML implements toml.Unmarshaler. func (s *Server) UnmarshalTOML(decode func(interface{}) error) error { // Parse the input into type tomlServer, which defines the // expected format of Server in TOML. type tomlServer struct { Addr string Timeout string } var dec tomlServer if err := decode(&dec); err != nil { return err } // Validate the address. if dec.Addr == "" { return errors.New("missing server address") } _, _, err := net.SplitHostPort(dec.Addr) if err != nil { return fmt.Errorf("invalid server address %q: %v", dec.Addr, err) } // Validate the timeout and apply the default value. var timeout time.Duration if dec.Timeout == "" { timeout = 10 * time.Second } else if timeout, err = time.ParseDuration(dec.Timeout); err != nil { return fmt.Errorf("invalid server timeout %q: %v", dec.Timeout, err) } // Assign the decoded value. *s = Server{Addr: dec.Addr, Timeout: timeout} return nil } func ExampleUnmarshalerRec() { input := []byte(` [[servers]] addr = "198.51.100.3:80" [[servers]] addr = "192.0.2.10:8080" timeout = "30s" `) var config struct { Servers []Server } toml.Unmarshal(input, &config) fmt.Printf("Unmarshaled:\n%+v\n\n", config) // Output: // Unmarshaled: // {Servers:[{Addr:198.51.100.3:80 Timeout:10s} {Addr:192.0.2.10:8080 Timeout:30s}]} } toml-0.1.1/example_marshaler_test.go000066400000000000000000000016701310060323300175360ustar00rootroot00000000000000package toml_test import ( "fmt" "github.com/naoina/toml" ) // This example shows how the Unmarshaler interface can be used to access the TOML source // input during decoding. // RawTOML stores the raw TOML syntax that was passed to UnmarshalTOML. type RawTOML []byte func (r *RawTOML) UnmarshalTOML(input []byte) error { cpy := make([]byte, len(input)) copy(cpy, input) *r = cpy return nil } func ExampleUnmarshaler() { input := []byte(` foo = 1 [[servers]] addr = "198.51.100.3:80" # a comment [[servers]] addr = "192.0.2.10:8080" timeout = "30s" `) var config struct { Foo int Servers RawTOML } toml.Unmarshal(input, &config) fmt.Printf("config.Foo = %d\n", config.Foo) fmt.Printf("config.Servers =\n%s\n", indent(config.Servers, 2)) // Output: // config.Foo = 1 // config.Servers = // [[servers]] // addr = "198.51.100.3:80" # a comment // [[servers]] // addr = "192.0.2.10:8080" // timeout = "30s" } toml-0.1.1/example_text_marshaler_test.go000066400000000000000000000015601310060323300206000ustar00rootroot00000000000000package toml_test import ( "fmt" "net" "github.com/naoina/toml" ) func Example_textUnmarshaler() { type Config struct { Servers []net.IP } input := []byte(` servers = ["192.0.2.10", "198.51.100.3"] `) var config Config toml.Unmarshal(input, &config) fmt.Printf("Unmarshaled:\n%+v\n\n", config) output, _ := toml.Marshal(&config) fmt.Printf("Marshaled:\n%s", output) // Output: // Unmarshaled: // {Servers:[192.0.2.10 198.51.100.3]} // // Marshaled: // servers = ["192.0.2.10", "198.51.100.3"] } func Example_textUnmarshalerError() { type Config struct { Servers []net.IP } input := []byte(` servers = ["192.0.2.10", "198.51.100.500"] `) var config Config err := toml.Unmarshal(input, &config) fmt.Printf("Unmarshal error:\n%v", err) // Output: // Unmarshal error: // line 2: (toml_test.Config.Servers) invalid IP address: 198.51.100.500 } toml-0.1.1/example_util_test.go000066400000000000000000000002761310060323300165360ustar00rootroot00000000000000package toml_test import ( "strings" ) func indent(b []byte, spaces int) string { space := strings.Repeat(" ", spaces) return space + strings.Replace(string(b), "\n", "\n"+space, -1) } toml-0.1.1/parse.go000066400000000000000000000211421310060323300141140ustar00rootroot00000000000000package toml import ( "errors" "fmt" "strconv" "strings" "github.com/naoina/toml/ast" ) // The parser is generated by github.com/pointlander/peg. To regenerate it, do: // // go get -u github.com/pointlander/peg // go generate . //go:generate peg -switch -inline parse.peg var errParse = errors.New("invalid TOML syntax") // Parse returns an AST representation of TOML. // The toplevel is represented by a table. func Parse(data []byte) (*ast.Table, error) { d := &parseState{p: &tomlParser{Buffer: string(data)}} d.init() if err := d.parse(); err != nil { return nil, err } return d.p.toml.table, nil } type parseState struct { p *tomlParser } func (d *parseState) init() { d.p.Init() d.p.toml.init(d.p.buffer) } func (d *parseState) parse() error { if err := d.p.Parse(); err != nil { if err, ok := err.(*parseError); ok { return lineError(err.Line(), errParse) } return err } return d.execute() } func (d *parseState) execute() (err error) { defer func() { if e := recover(); e != nil { lerr, ok := e.(*LineError) if !ok { panic(e) } err = lerr } }() d.p.Execute() return nil } func (e *parseError) Line() int { tokens := []token32{e.max} positions, p := make([]int, 2*len(tokens)), 0 for _, token := range tokens { positions[p], p = int(token.begin), p+1 positions[p], p = int(token.end), p+1 } for _, t := range translatePositions(e.p.buffer, positions) { if e.p.line < t.line { e.p.line = t.line } } return e.p.line } type stack struct { key string table *ast.Table } type array struct { parent *array child *array current *ast.Array line int } type toml struct { table *ast.Table line int currentTable *ast.Table s string key string tableKeys []string val ast.Value arr *array stack []*stack skip bool } func (p *toml) init(data []rune) { p.line = 1 p.table = p.newTable(ast.TableTypeNormal, "") p.table.Position.End = len(data) - 1 p.table.Data = data[:len(data)-1] // truncate the end_symbol added by PEG parse generator. p.currentTable = p.table } func (p *toml) Error(err error) { panic(lineError(p.line, err)) } func (p *tomlParser) SetTime(begin, end int) { p.val = &ast.Datetime{ Position: ast.Position{Begin: begin, End: end}, Data: p.buffer[begin:end], Value: string(p.buffer[begin:end]), } } func (p *tomlParser) SetFloat64(begin, end int) { p.val = &ast.Float{ Position: ast.Position{Begin: begin, End: end}, Data: p.buffer[begin:end], Value: underscoreReplacer.Replace(string(p.buffer[begin:end])), } } func (p *tomlParser) SetInt64(begin, end int) { p.val = &ast.Integer{ Position: ast.Position{Begin: begin, End: end}, Data: p.buffer[begin:end], Value: underscoreReplacer.Replace(string(p.buffer[begin:end])), } } func (p *tomlParser) SetString(begin, end int) { p.val = &ast.String{ Position: ast.Position{Begin: begin, End: end}, Data: p.buffer[begin:end], Value: p.s, } p.s = "" } func (p *tomlParser) SetBool(begin, end int) { p.val = &ast.Boolean{ Position: ast.Position{Begin: begin, End: end}, Data: p.buffer[begin:end], Value: string(p.buffer[begin:end]), } } func (p *tomlParser) StartArray() { if p.arr == nil { p.arr = &array{line: p.line, current: &ast.Array{}} return } p.arr.child = &array{parent: p.arr, line: p.line, current: &ast.Array{}} p.arr = p.arr.child } func (p *tomlParser) AddArrayVal() { if p.arr.current == nil { p.arr.current = &ast.Array{} } p.arr.current.Value = append(p.arr.current.Value, p.val) } func (p *tomlParser) SetArray(begin, end int) { p.arr.current.Position = ast.Position{Begin: begin, End: end} p.arr.current.Data = p.buffer[begin:end] p.val = p.arr.current p.arr = p.arr.parent } func (p *toml) SetTable(buf []rune, begin, end int) { rawName := string(buf[begin:end]) p.setTable(p.table, rawName, p.tableKeys) p.tableKeys = nil } func (p *toml) setTable(parent *ast.Table, name string, names []string) { parent, err := p.lookupTable(parent, names[:len(names)-1]) if err != nil { p.Error(err) } last := names[len(names)-1] tbl := p.newTable(ast.TableTypeNormal, last) switch v := parent.Fields[last].(type) { case nil: parent.Fields[last] = tbl case []*ast.Table: p.Error(fmt.Errorf("table `%s' is in conflict with array table in line %d", name, v[0].Line)) case *ast.Table: if (v.Position == ast.Position{}) { // This table was created as an implicit parent. // Replace it with the real defined table. tbl.Fields = v.Fields parent.Fields[last] = tbl } else { p.Error(fmt.Errorf("table `%s' is in conflict with table in line %d", name, v.Line)) } case *ast.KeyValue: p.Error(fmt.Errorf("table `%s' is in conflict with line %d", name, v.Line)) default: p.Error(fmt.Errorf("BUG: table `%s' is in conflict but it's unknown type `%T'", last, v)) } p.currentTable = tbl } func (p *toml) newTable(typ ast.TableType, name string) *ast.Table { return &ast.Table{ Line: p.line, Name: name, Type: typ, Fields: make(map[string]interface{}), } } func (p *tomlParser) SetTableString(begin, end int) { p.currentTable.Data = p.buffer[begin:end] p.currentTable.Position.Begin = begin p.currentTable.Position.End = end } func (p *toml) SetArrayTable(buf []rune, begin, end int) { rawName := string(buf[begin:end]) p.setArrayTable(p.table, rawName, p.tableKeys) p.tableKeys = nil } func (p *toml) setArrayTable(parent *ast.Table, name string, names []string) { parent, err := p.lookupTable(parent, names[:len(names)-1]) if err != nil { p.Error(err) } last := names[len(names)-1] tbl := p.newTable(ast.TableTypeArray, last) switch v := parent.Fields[last].(type) { case nil: parent.Fields[last] = []*ast.Table{tbl} case []*ast.Table: parent.Fields[last] = append(v, tbl) case *ast.Table: p.Error(fmt.Errorf("array table `%s' is in conflict with table in line %d", name, v.Line)) case *ast.KeyValue: p.Error(fmt.Errorf("array table `%s' is in conflict with line %d", name, v.Line)) default: p.Error(fmt.Errorf("BUG: array table `%s' is in conflict but it's unknown type `%T'", name, v)) } p.currentTable = tbl } func (p *toml) StartInlineTable() { p.skip = false p.stack = append(p.stack, &stack{p.key, p.currentTable}) names := []string{p.key} if p.arr == nil { p.setTable(p.currentTable, names[0], names) } else { p.setArrayTable(p.currentTable, names[0], names) } } func (p *toml) EndInlineTable() { st := p.stack[len(p.stack)-1] p.key, p.currentTable = st.key, st.table p.stack[len(p.stack)-1] = nil p.stack = p.stack[:len(p.stack)-1] p.skip = true } func (p *toml) AddLineCount(i int) { p.line += i } func (p *toml) SetKey(buf []rune, begin, end int) { p.key = string(buf[begin:end]) if len(p.key) > 0 && p.key[0] == '"' { p.key = p.unquote(p.key) } } func (p *toml) AddTableKey() { p.tableKeys = append(p.tableKeys, p.key) } func (p *toml) AddKeyValue() { if p.skip { p.skip = false return } if val, exists := p.currentTable.Fields[p.key]; exists { switch v := val.(type) { case *ast.Table: p.Error(fmt.Errorf("key `%s' is in conflict with table in line %d", p.key, v.Line)) case *ast.KeyValue: p.Error(fmt.Errorf("key `%s' is in conflict with line %xd", p.key, v.Line)) default: p.Error(fmt.Errorf("BUG: key `%s' is in conflict but it's unknown type `%T'", p.key, v)) } } p.currentTable.Fields[p.key] = &ast.KeyValue{Key: p.key, Value: p.val, Line: p.line} } func (p *toml) SetBasicString(buf []rune, begin, end int) { p.s = p.unquote(string(buf[begin:end])) } func (p *toml) SetMultilineString() { p.s = p.unquote(`"` + escapeReplacer.Replace(strings.TrimLeft(p.s, "\r\n")) + `"`) } func (p *toml) AddMultilineBasicBody(buf []rune, begin, end int) { p.s += string(buf[begin:end]) } func (p *toml) SetLiteralString(buf []rune, begin, end int) { p.s = string(buf[begin:end]) } func (p *toml) SetMultilineLiteralString(buf []rune, begin, end int) { p.s = strings.TrimLeft(string(buf[begin:end]), "\r\n") } func (p *toml) unquote(s string) string { s, err := strconv.Unquote(s) if err != nil { p.Error(err) } return s } func (p *toml) lookupTable(t *ast.Table, keys []string) (*ast.Table, error) { for _, s := range keys { val, exists := t.Fields[s] if !exists { tbl := p.newTable(ast.TableTypeNormal, s) t.Fields[s] = tbl t = tbl continue } switch v := val.(type) { case *ast.Table: t = v case []*ast.Table: t = v[len(v)-1] case *ast.KeyValue: return nil, fmt.Errorf("key `%s' is in conflict with line %d", s, v.Line) default: return nil, fmt.Errorf("BUG: key `%s' is in conflict but it's unknown type `%T'", s, v) } } return t, nil } toml-0.1.1/parse.peg000066400000000000000000000065311310060323300142670ustar00rootroot00000000000000package toml type tomlParser Peg { toml } TOML <- Expression (newline Expression)* newline? !. { _ = buffer } Expression <- ( { p.SetTableString(begin, end) } / ws keyval ws comment? / ws comment? / ws ) newline <- <[\r\n]+> { p.AddLineCount(end - begin) } ws <- [ \t]* wsnl <- ( [ \t] / <[\r\n]> { p.AddLineCount(end - begin) } )* comment <- '#' <[\t -\0x10FFFF]*> keyval <- key ws '=' ws val { p.AddKeyValue() } key <- bareKey / quotedKey bareKey <- <[0-9A-Za-z\-_]+> { p.SetKey(p.buffer, begin, end) } quotedKey <- < '"' basicChar* '"' > { p.SetKey(p.buffer, begin, end) } val <- ( { p.SetTime(begin, end) } / { p.SetFloat64(begin, end) } / { p.SetInt64(begin, end) } / { p.SetString(begin, end) } / { p.SetBool(begin, end) } / { p.SetArray(begin, end) } / inlineTable ) table <- stdTable / arrayTable stdTable <- '[' ws ws ']' { p.SetTable(p.buffer, begin, end) } arrayTable <- '[[' ws ws ']]' { p.SetArrayTable(p.buffer, begin, end) } inlineTable <- ( '{' { p.StartInlineTable() } ws inlineTableKeyValues ws '}' { p.EndInlineTable() } ) inlineTableKeyValues <- (keyval inlineTableValSep?)* tableKey <- tableKeyComp (tableKeySep tableKeyComp)* tableKeyComp <- key { p.AddTableKey() } tableKeySep <- ws '.' ws inlineTableValSep <- ws ',' ws integer <- [\-+]? int int <- [1-9] (digit / '_' digit)+ / digit float <- integer (frac exp? / frac? exp) frac <- '.' digit (digit / '_' digit)* exp <- [eE] [\-+]? digit (digit / '_' digit)* string <- ( mlLiteralString / literalString / mlBasicString / basicString ) basicString <- <'"' basicChar* '"'> { p.SetBasicString(p.buffer, begin, end) } basicChar <- basicUnescaped / escaped escaped <- escape ([btnfr"/\\] / 'u' hexQuad / 'U' hexQuad hexQuad) basicUnescaped <- [ -!#-\[\]-\0x10FFFF] escape <- '\\' mlBasicString <- '"""' mlBasicBody '"""' { p.SetMultilineString() } mlBasicBody <- ( { p.AddMultilineBasicBody(p.buffer, begin, end) } / escape newline wsnl )* literalString <- "'" "'" { p.SetLiteralString(p.buffer, begin, end) } literalChar <- [\t -&(-\0x10FFFF] mlLiteralString <- "'''" "'''" { p.SetMultilineLiteralString(p.buffer, begin, end) } mlLiteralBody <- (!"'''" (mlLiteralChar / newline))* mlLiteralChar <- [\t -\0x10FFFF] hexdigit <- [0-9A-Fa-f] hexQuad <- hexdigit hexdigit hexdigit hexdigit boolean <- 'true' / 'false' dateFullYear <- digitQuad dateMonth <- digitDual dateMDay <- digitDual timeHour <- digitDual timeMinute <- digitDual timeSecond <- digitDual timeSecfrac <- '.' digit+ timeNumoffset <- [\-+] timeHour ':' timeMinute timeOffset <- 'Z' / timeNumoffset partialTime <- timeHour ':' timeMinute ':' timeSecond timeSecfrac? fullDate <- dateFullYear '-' dateMonth '-' dateMDay fullTime <- partialTime timeOffset datetime <- (fullDate ('T' fullTime)?) / partialTime digit <- [0-9] digitDual <- digit digit digitQuad <- digitDual digitDual array <- ( '[' { p.StartArray() } wsnl arrayValues? wsnl ']' ) arrayValues <- ( val { p.AddArrayVal() } ( wsnl comment? wsnl arraySep wsnl comment? wsnl val { p.AddArrayVal() } )* wsnl arraySep? wsnl comment? ) arraySep <- ',' toml-0.1.1/parse.peg.go000066400000000000000000001736571310060323300147110ustar00rootroot00000000000000package toml import ( "fmt" "math" "sort" "strconv" ) const endSymbol rune = 1114112 /* The rule types inferred from the grammar are below. */ type pegRule uint8 const ( ruleUnknown pegRule = iota ruleTOML ruleExpression rulenewline rulews rulewsnl rulecomment rulekeyval rulekey rulebareKey rulequotedKey ruleval ruletable rulestdTable rulearrayTable ruleinlineTable ruleinlineTableKeyValues ruletableKey ruletableKeyComp ruletableKeySep ruleinlineTableValSep ruleinteger ruleint rulefloat rulefrac ruleexp rulestring rulebasicString rulebasicChar ruleescaped rulebasicUnescaped ruleescape rulemlBasicString rulemlBasicBody ruleliteralString ruleliteralChar rulemlLiteralString rulemlLiteralBody rulemlLiteralChar rulehexdigit rulehexQuad ruleboolean ruledateFullYear ruledateMonth ruledateMDay ruletimeHour ruletimeMinute ruletimeSecond ruletimeSecfrac ruletimeNumoffset ruletimeOffset rulepartialTime rulefullDate rulefullTime ruledatetime ruledigit ruledigitDual ruledigitQuad rulearray rulearrayValues rulearraySep ruleAction0 rulePegText ruleAction1 ruleAction2 ruleAction3 ruleAction4 ruleAction5 ruleAction6 ruleAction7 ruleAction8 ruleAction9 ruleAction10 ruleAction11 ruleAction12 ruleAction13 ruleAction14 ruleAction15 ruleAction16 ruleAction17 ruleAction18 ruleAction19 ruleAction20 ruleAction21 ruleAction22 ruleAction23 ruleAction24 ruleAction25 ) var rul3s = [...]string{ "Unknown", "TOML", "Expression", "newline", "ws", "wsnl", "comment", "keyval", "key", "bareKey", "quotedKey", "val", "table", "stdTable", "arrayTable", "inlineTable", "inlineTableKeyValues", "tableKey", "tableKeyComp", "tableKeySep", "inlineTableValSep", "integer", "int", "float", "frac", "exp", "string", "basicString", "basicChar", "escaped", "basicUnescaped", "escape", "mlBasicString", "mlBasicBody", "literalString", "literalChar", "mlLiteralString", "mlLiteralBody", "mlLiteralChar", "hexdigit", "hexQuad", "boolean", "dateFullYear", "dateMonth", "dateMDay", "timeHour", "timeMinute", "timeSecond", "timeSecfrac", "timeNumoffset", "timeOffset", "partialTime", "fullDate", "fullTime", "datetime", "digit", "digitDual", "digitQuad", "array", "arrayValues", "arraySep", "Action0", "PegText", "Action1", "Action2", "Action3", "Action4", "Action5", "Action6", "Action7", "Action8", "Action9", "Action10", "Action11", "Action12", "Action13", "Action14", "Action15", "Action16", "Action17", "Action18", "Action19", "Action20", "Action21", "Action22", "Action23", "Action24", "Action25", } type token32 struct { pegRule begin, end uint32 } func (t *token32) String() string { return fmt.Sprintf("\x1B[34m%v\x1B[m %v %v", rul3s[t.pegRule], t.begin, t.end) } type node32 struct { token32 up, next *node32 } func (node *node32) print(pretty bool, buffer string) { var print func(node *node32, depth int) print = func(node *node32, depth int) { for node != nil { for c := 0; c < depth; c++ { fmt.Printf(" ") } rule := rul3s[node.pegRule] quote := strconv.Quote(string(([]rune(buffer)[node.begin:node.end]))) if !pretty { fmt.Printf("%v %v\n", rule, quote) } else { fmt.Printf("\x1B[34m%v\x1B[m %v\n", rule, quote) } if node.up != nil { print(node.up, depth+1) } node = node.next } } print(node, 0) } func (node *node32) Print(buffer string) { node.print(false, buffer) } func (node *node32) PrettyPrint(buffer string) { node.print(true, buffer) } type tokens32 struct { tree []token32 } func (t *tokens32) Trim(length uint32) { t.tree = t.tree[:length] } func (t *tokens32) Print() { for _, token := range t.tree { fmt.Println(token.String()) } } func (t *tokens32) AST() *node32 { type element struct { node *node32 down *element } tokens := t.Tokens() var stack *element for _, token := range tokens { if token.begin == token.end { continue } node := &node32{token32: token} for stack != nil && stack.node.begin >= token.begin && stack.node.end <= token.end { stack.node.next = node.up node.up = stack.node stack = stack.down } stack = &element{node: node, down: stack} } if stack != nil { return stack.node } return nil } func (t *tokens32) PrintSyntaxTree(buffer string) { t.AST().Print(buffer) } func (t *tokens32) PrettyPrintSyntaxTree(buffer string) { t.AST().PrettyPrint(buffer) } func (t *tokens32) Add(rule pegRule, begin, end, index uint32) { if tree := t.tree; int(index) >= len(tree) { expanded := make([]token32, 2*len(tree)) copy(expanded, tree) t.tree = expanded } t.tree[index] = token32{ pegRule: rule, begin: begin, end: end, } } func (t *tokens32) Tokens() []token32 { return t.tree } type tomlParser struct { toml Buffer string buffer []rune rules [88]func() bool parse func(rule ...int) error reset func() Pretty bool tokens32 } func (p *tomlParser) Parse(rule ...int) error { return p.parse(rule...) } func (p *tomlParser) Reset() { p.reset() } type textPosition struct { line, symbol int } type textPositionMap map[int]textPosition func translatePositions(buffer []rune, positions []int) textPositionMap { length, translations, j, line, symbol := len(positions), make(textPositionMap, len(positions)), 0, 1, 0 sort.Ints(positions) search: for i, c := range buffer { if c == '\n' { line, symbol = line+1, 0 } else { symbol++ } if i == positions[j] { translations[positions[j]] = textPosition{line, symbol} for j++; j < length; j++ { if i != positions[j] { continue search } } break search } } return translations } type parseError struct { p *tomlParser max token32 } func (e *parseError) Error() string { tokens, error := []token32{e.max}, "\n" positions, p := make([]int, 2*len(tokens)), 0 for _, token := range tokens { positions[p], p = int(token.begin), p+1 positions[p], p = int(token.end), p+1 } translations := translatePositions(e.p.buffer, positions) format := "parse error near %v (line %v symbol %v - line %v symbol %v):\n%v\n" if e.p.Pretty { format = "parse error near \x1B[34m%v\x1B[m (line %v symbol %v - line %v symbol %v):\n%v\n" } for _, token := range tokens { begin, end := int(token.begin), int(token.end) error += fmt.Sprintf(format, rul3s[token.pegRule], translations[begin].line, translations[begin].symbol, translations[end].line, translations[end].symbol, strconv.Quote(string(e.p.buffer[begin:end]))) } return error } func (p *tomlParser) PrintSyntaxTree() { if p.Pretty { p.tokens32.PrettyPrintSyntaxTree(p.Buffer) } else { p.tokens32.PrintSyntaxTree(p.Buffer) } } func (p *tomlParser) Execute() { buffer, _buffer, text, begin, end := p.Buffer, p.buffer, "", 0, 0 for _, token := range p.Tokens() { switch token.pegRule { case rulePegText: begin, end = int(token.begin), int(token.end) text = string(_buffer[begin:end]) case ruleAction0: _ = buffer case ruleAction1: p.SetTableString(begin, end) case ruleAction2: p.AddLineCount(end - begin) case ruleAction3: p.AddLineCount(end - begin) case ruleAction4: p.AddKeyValue() case ruleAction5: p.SetKey(p.buffer, begin, end) case ruleAction6: p.SetKey(p.buffer, begin, end) case ruleAction7: p.SetTime(begin, end) case ruleAction8: p.SetFloat64(begin, end) case ruleAction9: p.SetInt64(begin, end) case ruleAction10: p.SetString(begin, end) case ruleAction11: p.SetBool(begin, end) case ruleAction12: p.SetArray(begin, end) case ruleAction13: p.SetTable(p.buffer, begin, end) case ruleAction14: p.SetArrayTable(p.buffer, begin, end) case ruleAction15: p.StartInlineTable() case ruleAction16: p.EndInlineTable() case ruleAction17: p.AddTableKey() case ruleAction18: p.SetBasicString(p.buffer, begin, end) case ruleAction19: p.SetMultilineString() case ruleAction20: p.AddMultilineBasicBody(p.buffer, begin, end) case ruleAction21: p.SetLiteralString(p.buffer, begin, end) case ruleAction22: p.SetMultilineLiteralString(p.buffer, begin, end) case ruleAction23: p.StartArray() case ruleAction24: p.AddArrayVal() case ruleAction25: p.AddArrayVal() } } _, _, _, _, _ = buffer, _buffer, text, begin, end } func (p *tomlParser) Init() { var ( max token32 position, tokenIndex uint32 buffer []rune ) p.reset = func() { max = token32{} position, tokenIndex = 0, 0 p.buffer = []rune(p.Buffer) if len(p.buffer) == 0 || p.buffer[len(p.buffer)-1] != endSymbol { p.buffer = append(p.buffer, endSymbol) } buffer = p.buffer } p.reset() _rules := p.rules tree := tokens32{tree: make([]token32, math.MaxInt16)} p.parse = func(rule ...int) error { r := 1 if len(rule) > 0 { r = rule[0] } matches := p.rules[r]() p.tokens32 = tree if matches { p.Trim(tokenIndex) return nil } return &parseError{p, max} } add := func(rule pegRule, begin uint32) { tree.Add(rule, begin, position, tokenIndex) tokenIndex++ if begin != position && position > max.end { max = token32{rule, begin, position} } } matchDot := func() bool { if buffer[position] != endSymbol { position++ return true } return false } /*matchChar := func(c byte) bool { if buffer[position] == c { position++ return true } return false }*/ /*matchRange := func(lower byte, upper byte) bool { if c := buffer[position]; c >= lower && c <= upper { position++ return true } return false }*/ _rules = [...]func() bool{ nil, /* 0 TOML <- <(Expression (newline Expression)* newline? !. Action0)> */ func() bool { position0, tokenIndex0 := position, tokenIndex { position1 := position if !_rules[ruleExpression]() { goto l0 } l2: { position3, tokenIndex3 := position, tokenIndex if !_rules[rulenewline]() { goto l3 } if !_rules[ruleExpression]() { goto l3 } goto l2 l3: position, tokenIndex = position3, tokenIndex3 } { position4, tokenIndex4 := position, tokenIndex if !_rules[rulenewline]() { goto l4 } goto l5 l4: position, tokenIndex = position4, tokenIndex4 } l5: { position6, tokenIndex6 := position, tokenIndex if !matchDot() { goto l6 } goto l0 l6: position, tokenIndex = position6, tokenIndex6 } { add(ruleAction0, position) } add(ruleTOML, position1) } return true l0: position, tokenIndex = position0, tokenIndex0 return false }, /* 1 Expression <- <((<(ws table ws comment? (wsnl keyval ws comment?)*)> Action1) / (ws keyval ws comment?) / (ws comment?) / ws)> */ func() bool { position8, tokenIndex8 := position, tokenIndex { position9 := position { position10, tokenIndex10 := position, tokenIndex { position12 := position if !_rules[rulews]() { goto l11 } { position13 := position { position14, tokenIndex14 := position, tokenIndex { position16 := position if buffer[position] != rune('[') { goto l15 } position++ if !_rules[rulews]() { goto l15 } { position17 := position if !_rules[ruletableKey]() { goto l15 } add(rulePegText, position17) } if !_rules[rulews]() { goto l15 } if buffer[position] != rune(']') { goto l15 } position++ { add(ruleAction13, position) } add(rulestdTable, position16) } goto l14 l15: position, tokenIndex = position14, tokenIndex14 { position19 := position if buffer[position] != rune('[') { goto l11 } position++ if buffer[position] != rune('[') { goto l11 } position++ if !_rules[rulews]() { goto l11 } { position20 := position if !_rules[ruletableKey]() { goto l11 } add(rulePegText, position20) } if !_rules[rulews]() { goto l11 } if buffer[position] != rune(']') { goto l11 } position++ if buffer[position] != rune(']') { goto l11 } position++ { add(ruleAction14, position) } add(rulearrayTable, position19) } } l14: add(ruletable, position13) } if !_rules[rulews]() { goto l11 } { position22, tokenIndex22 := position, tokenIndex if !_rules[rulecomment]() { goto l22 } goto l23 l22: position, tokenIndex = position22, tokenIndex22 } l23: l24: { position25, tokenIndex25 := position, tokenIndex if !_rules[rulewsnl]() { goto l25 } if !_rules[rulekeyval]() { goto l25 } if !_rules[rulews]() { goto l25 } { position26, tokenIndex26 := position, tokenIndex if !_rules[rulecomment]() { goto l26 } goto l27 l26: position, tokenIndex = position26, tokenIndex26 } l27: goto l24 l25: position, tokenIndex = position25, tokenIndex25 } add(rulePegText, position12) } { add(ruleAction1, position) } goto l10 l11: position, tokenIndex = position10, tokenIndex10 if !_rules[rulews]() { goto l29 } if !_rules[rulekeyval]() { goto l29 } if !_rules[rulews]() { goto l29 } { position30, tokenIndex30 := position, tokenIndex if !_rules[rulecomment]() { goto l30 } goto l31 l30: position, tokenIndex = position30, tokenIndex30 } l31: goto l10 l29: position, tokenIndex = position10, tokenIndex10 if !_rules[rulews]() { goto l32 } { position33, tokenIndex33 := position, tokenIndex if !_rules[rulecomment]() { goto l33 } goto l34 l33: position, tokenIndex = position33, tokenIndex33 } l34: goto l10 l32: position, tokenIndex = position10, tokenIndex10 if !_rules[rulews]() { goto l8 } } l10: add(ruleExpression, position9) } return true l8: position, tokenIndex = position8, tokenIndex8 return false }, /* 2 newline <- <(<('\r' / '\n')+> Action2)> */ func() bool { position35, tokenIndex35 := position, tokenIndex { position36 := position { position37 := position { position40, tokenIndex40 := position, tokenIndex if buffer[position] != rune('\r') { goto l41 } position++ goto l40 l41: position, tokenIndex = position40, tokenIndex40 if buffer[position] != rune('\n') { goto l35 } position++ } l40: l38: { position39, tokenIndex39 := position, tokenIndex { position42, tokenIndex42 := position, tokenIndex if buffer[position] != rune('\r') { goto l43 } position++ goto l42 l43: position, tokenIndex = position42, tokenIndex42 if buffer[position] != rune('\n') { goto l39 } position++ } l42: goto l38 l39: position, tokenIndex = position39, tokenIndex39 } add(rulePegText, position37) } { add(ruleAction2, position) } add(rulenewline, position36) } return true l35: position, tokenIndex = position35, tokenIndex35 return false }, /* 3 ws <- <(' ' / '\t')*> */ func() bool { { position46 := position l47: { position48, tokenIndex48 := position, tokenIndex { position49, tokenIndex49 := position, tokenIndex if buffer[position] != rune(' ') { goto l50 } position++ goto l49 l50: position, tokenIndex = position49, tokenIndex49 if buffer[position] != rune('\t') { goto l48 } position++ } l49: goto l47 l48: position, tokenIndex = position48, tokenIndex48 } add(rulews, position46) } return true }, /* 4 wsnl <- <((&('\t') '\t') | (&(' ') ' ') | (&('\n' | '\r') (<('\r' / '\n')> Action3)))*> */ func() bool { { position52 := position l53: { position54, tokenIndex54 := position, tokenIndex { switch buffer[position] { case '\t': if buffer[position] != rune('\t') { goto l54 } position++ break case ' ': if buffer[position] != rune(' ') { goto l54 } position++ break default: { position56 := position { position57, tokenIndex57 := position, tokenIndex if buffer[position] != rune('\r') { goto l58 } position++ goto l57 l58: position, tokenIndex = position57, tokenIndex57 if buffer[position] != rune('\n') { goto l54 } position++ } l57: add(rulePegText, position56) } { add(ruleAction3, position) } break } } goto l53 l54: position, tokenIndex = position54, tokenIndex54 } add(rulewsnl, position52) } return true }, /* 5 comment <- <('#' <('\t' / [ -\U0010ffff])*>)> */ func() bool { position60, tokenIndex60 := position, tokenIndex { position61 := position if buffer[position] != rune('#') { goto l60 } position++ { position62 := position l63: { position64, tokenIndex64 := position, tokenIndex { position65, tokenIndex65 := position, tokenIndex if buffer[position] != rune('\t') { goto l66 } position++ goto l65 l66: position, tokenIndex = position65, tokenIndex65 if c := buffer[position]; c < rune(' ') || c > rune('\U0010ffff') { goto l64 } position++ } l65: goto l63 l64: position, tokenIndex = position64, tokenIndex64 } add(rulePegText, position62) } add(rulecomment, position61) } return true l60: position, tokenIndex = position60, tokenIndex60 return false }, /* 6 keyval <- <(key ws '=' ws val Action4)> */ func() bool { position67, tokenIndex67 := position, tokenIndex { position68 := position if !_rules[rulekey]() { goto l67 } if !_rules[rulews]() { goto l67 } if buffer[position] != rune('=') { goto l67 } position++ if !_rules[rulews]() { goto l67 } if !_rules[ruleval]() { goto l67 } { add(ruleAction4, position) } add(rulekeyval, position68) } return true l67: position, tokenIndex = position67, tokenIndex67 return false }, /* 7 key <- <(bareKey / quotedKey)> */ func() bool { position70, tokenIndex70 := position, tokenIndex { position71 := position { position72, tokenIndex72 := position, tokenIndex { position74 := position { position75 := position { switch buffer[position] { case '_': if buffer[position] != rune('_') { goto l73 } position++ break case '-': if buffer[position] != rune('-') { goto l73 } position++ break case 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z': if c := buffer[position]; c < rune('a') || c > rune('z') { goto l73 } position++ break case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': if c := buffer[position]; c < rune('0') || c > rune('9') { goto l73 } position++ break default: if c := buffer[position]; c < rune('A') || c > rune('Z') { goto l73 } position++ break } } l76: { position77, tokenIndex77 := position, tokenIndex { switch buffer[position] { case '_': if buffer[position] != rune('_') { goto l77 } position++ break case '-': if buffer[position] != rune('-') { goto l77 } position++ break case 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z': if c := buffer[position]; c < rune('a') || c > rune('z') { goto l77 } position++ break case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': if c := buffer[position]; c < rune('0') || c > rune('9') { goto l77 } position++ break default: if c := buffer[position]; c < rune('A') || c > rune('Z') { goto l77 } position++ break } } goto l76 l77: position, tokenIndex = position77, tokenIndex77 } add(rulePegText, position75) } { add(ruleAction5, position) } add(rulebareKey, position74) } goto l72 l73: position, tokenIndex = position72, tokenIndex72 { position81 := position { position82 := position if buffer[position] != rune('"') { goto l70 } position++ l83: { position84, tokenIndex84 := position, tokenIndex if !_rules[rulebasicChar]() { goto l84 } goto l83 l84: position, tokenIndex = position84, tokenIndex84 } if buffer[position] != rune('"') { goto l70 } position++ add(rulePegText, position82) } { add(ruleAction6, position) } add(rulequotedKey, position81) } } l72: add(rulekey, position71) } return true l70: position, tokenIndex = position70, tokenIndex70 return false }, /* 8 bareKey <- <(<((&('_') '_') | (&('-') '-') | (&('a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z') [a-z]) | (&('0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9') [0-9]) | (&('A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z') [A-Z]))+> Action5)> */ nil, /* 9 quotedKey <- <(<('"' basicChar* '"')> Action6)> */ nil, /* 10 val <- <(( Action7) / ( Action8) / ((&('{') inlineTable) | (&('[') ( Action12)) | (&('f' | 't') ( Action11)) | (&('"' | '\'') ( Action10)) | (&('+' | '-' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9') ( Action9))))> */ func() bool { position88, tokenIndex88 := position, tokenIndex { position89 := position { position90, tokenIndex90 := position, tokenIndex { position92 := position { position93 := position { position94, tokenIndex94 := position, tokenIndex { position96 := position { position97 := position { position98 := position if !_rules[ruledigitDual]() { goto l95 } if !_rules[ruledigitDual]() { goto l95 } add(ruledigitQuad, position98) } add(ruledateFullYear, position97) } if buffer[position] != rune('-') { goto l95 } position++ { position99 := position if !_rules[ruledigitDual]() { goto l95 } add(ruledateMonth, position99) } if buffer[position] != rune('-') { goto l95 } position++ { position100 := position if !_rules[ruledigitDual]() { goto l95 } add(ruledateMDay, position100) } add(rulefullDate, position96) } { position101, tokenIndex101 := position, tokenIndex if buffer[position] != rune('T') { goto l101 } position++ { position103 := position if !_rules[rulepartialTime]() { goto l101 } { position104 := position { position105, tokenIndex105 := position, tokenIndex if buffer[position] != rune('Z') { goto l106 } position++ goto l105 l106: position, tokenIndex = position105, tokenIndex105 { position107 := position { position108, tokenIndex108 := position, tokenIndex if buffer[position] != rune('-') { goto l109 } position++ goto l108 l109: position, tokenIndex = position108, tokenIndex108 if buffer[position] != rune('+') { goto l101 } position++ } l108: if !_rules[ruletimeHour]() { goto l101 } if buffer[position] != rune(':') { goto l101 } position++ if !_rules[ruletimeMinute]() { goto l101 } add(ruletimeNumoffset, position107) } } l105: add(ruletimeOffset, position104) } add(rulefullTime, position103) } goto l102 l101: position, tokenIndex = position101, tokenIndex101 } l102: goto l94 l95: position, tokenIndex = position94, tokenIndex94 if !_rules[rulepartialTime]() { goto l91 } } l94: add(ruledatetime, position93) } add(rulePegText, position92) } { add(ruleAction7, position) } goto l90 l91: position, tokenIndex = position90, tokenIndex90 { position112 := position { position113 := position if !_rules[ruleinteger]() { goto l111 } { position114, tokenIndex114 := position, tokenIndex if !_rules[rulefrac]() { goto l115 } { position116, tokenIndex116 := position, tokenIndex if !_rules[ruleexp]() { goto l116 } goto l117 l116: position, tokenIndex = position116, tokenIndex116 } l117: goto l114 l115: position, tokenIndex = position114, tokenIndex114 { position118, tokenIndex118 := position, tokenIndex if !_rules[rulefrac]() { goto l118 } goto l119 l118: position, tokenIndex = position118, tokenIndex118 } l119: if !_rules[ruleexp]() { goto l111 } } l114: add(rulefloat, position113) } add(rulePegText, position112) } { add(ruleAction8, position) } goto l90 l111: position, tokenIndex = position90, tokenIndex90 { switch buffer[position] { case '{': { position122 := position if buffer[position] != rune('{') { goto l88 } position++ { add(ruleAction15, position) } if !_rules[rulews]() { goto l88 } { position124 := position l125: { position126, tokenIndex126 := position, tokenIndex if !_rules[rulekeyval]() { goto l126 } { position127, tokenIndex127 := position, tokenIndex { position129 := position if !_rules[rulews]() { goto l127 } if buffer[position] != rune(',') { goto l127 } position++ if !_rules[rulews]() { goto l127 } add(ruleinlineTableValSep, position129) } goto l128 l127: position, tokenIndex = position127, tokenIndex127 } l128: goto l125 l126: position, tokenIndex = position126, tokenIndex126 } add(ruleinlineTableKeyValues, position124) } if !_rules[rulews]() { goto l88 } if buffer[position] != rune('}') { goto l88 } position++ { add(ruleAction16, position) } add(ruleinlineTable, position122) } break case '[': { position131 := position { position132 := position if buffer[position] != rune('[') { goto l88 } position++ { add(ruleAction23, position) } if !_rules[rulewsnl]() { goto l88 } { position134, tokenIndex134 := position, tokenIndex { position136 := position if !_rules[ruleval]() { goto l134 } { add(ruleAction24, position) } l138: { position139, tokenIndex139 := position, tokenIndex if !_rules[rulewsnl]() { goto l139 } { position140, tokenIndex140 := position, tokenIndex if !_rules[rulecomment]() { goto l140 } goto l141 l140: position, tokenIndex = position140, tokenIndex140 } l141: if !_rules[rulewsnl]() { goto l139 } if !_rules[rulearraySep]() { goto l139 } if !_rules[rulewsnl]() { goto l139 } { position142, tokenIndex142 := position, tokenIndex if !_rules[rulecomment]() { goto l142 } goto l143 l142: position, tokenIndex = position142, tokenIndex142 } l143: if !_rules[rulewsnl]() { goto l139 } if !_rules[ruleval]() { goto l139 } { add(ruleAction25, position) } goto l138 l139: position, tokenIndex = position139, tokenIndex139 } if !_rules[rulewsnl]() { goto l134 } { position145, tokenIndex145 := position, tokenIndex if !_rules[rulearraySep]() { goto l145 } goto l146 l145: position, tokenIndex = position145, tokenIndex145 } l146: if !_rules[rulewsnl]() { goto l134 } { position147, tokenIndex147 := position, tokenIndex if !_rules[rulecomment]() { goto l147 } goto l148 l147: position, tokenIndex = position147, tokenIndex147 } l148: add(rulearrayValues, position136) } goto l135 l134: position, tokenIndex = position134, tokenIndex134 } l135: if !_rules[rulewsnl]() { goto l88 } if buffer[position] != rune(']') { goto l88 } position++ add(rulearray, position132) } add(rulePegText, position131) } { add(ruleAction12, position) } break case 'f', 't': { position150 := position { position151 := position { position152, tokenIndex152 := position, tokenIndex if buffer[position] != rune('t') { goto l153 } position++ if buffer[position] != rune('r') { goto l153 } position++ if buffer[position] != rune('u') { goto l153 } position++ if buffer[position] != rune('e') { goto l153 } position++ goto l152 l153: position, tokenIndex = position152, tokenIndex152 if buffer[position] != rune('f') { goto l88 } position++ if buffer[position] != rune('a') { goto l88 } position++ if buffer[position] != rune('l') { goto l88 } position++ if buffer[position] != rune('s') { goto l88 } position++ if buffer[position] != rune('e') { goto l88 } position++ } l152: add(ruleboolean, position151) } add(rulePegText, position150) } { add(ruleAction11, position) } break case '"', '\'': { position155 := position { position156 := position { position157, tokenIndex157 := position, tokenIndex { position159 := position if buffer[position] != rune('\'') { goto l158 } position++ if buffer[position] != rune('\'') { goto l158 } position++ if buffer[position] != rune('\'') { goto l158 } position++ { position160 := position { position161 := position l162: { position163, tokenIndex163 := position, tokenIndex { position164, tokenIndex164 := position, tokenIndex if buffer[position] != rune('\'') { goto l164 } position++ if buffer[position] != rune('\'') { goto l164 } position++ if buffer[position] != rune('\'') { goto l164 } position++ goto l163 l164: position, tokenIndex = position164, tokenIndex164 } { position165, tokenIndex165 := position, tokenIndex { position167 := position { position168, tokenIndex168 := position, tokenIndex if buffer[position] != rune('\t') { goto l169 } position++ goto l168 l169: position, tokenIndex = position168, tokenIndex168 if c := buffer[position]; c < rune(' ') || c > rune('\U0010ffff') { goto l166 } position++ } l168: add(rulemlLiteralChar, position167) } goto l165 l166: position, tokenIndex = position165, tokenIndex165 if !_rules[rulenewline]() { goto l163 } } l165: goto l162 l163: position, tokenIndex = position163, tokenIndex163 } add(rulemlLiteralBody, position161) } add(rulePegText, position160) } if buffer[position] != rune('\'') { goto l158 } position++ if buffer[position] != rune('\'') { goto l158 } position++ if buffer[position] != rune('\'') { goto l158 } position++ { add(ruleAction22, position) } add(rulemlLiteralString, position159) } goto l157 l158: position, tokenIndex = position157, tokenIndex157 { position172 := position if buffer[position] != rune('\'') { goto l171 } position++ { position173 := position l174: { position175, tokenIndex175 := position, tokenIndex { position176 := position { switch buffer[position] { case '\t': if buffer[position] != rune('\t') { goto l175 } position++ break case ' ', '!', '"', '#', '$', '%', '&': if c := buffer[position]; c < rune(' ') || c > rune('&') { goto l175 } position++ break default: if c := buffer[position]; c < rune('(') || c > rune('\U0010ffff') { goto l175 } position++ break } } add(ruleliteralChar, position176) } goto l174 l175: position, tokenIndex = position175, tokenIndex175 } add(rulePegText, position173) } if buffer[position] != rune('\'') { goto l171 } position++ { add(ruleAction21, position) } add(ruleliteralString, position172) } goto l157 l171: position, tokenIndex = position157, tokenIndex157 { position180 := position if buffer[position] != rune('"') { goto l179 } position++ if buffer[position] != rune('"') { goto l179 } position++ if buffer[position] != rune('"') { goto l179 } position++ { position181 := position l182: { position183, tokenIndex183 := position, tokenIndex { position184, tokenIndex184 := position, tokenIndex { position186 := position { position187, tokenIndex187 := position, tokenIndex if !_rules[rulebasicChar]() { goto l188 } goto l187 l188: position, tokenIndex = position187, tokenIndex187 if !_rules[rulenewline]() { goto l185 } } l187: add(rulePegText, position186) } { add(ruleAction20, position) } goto l184 l185: position, tokenIndex = position184, tokenIndex184 if !_rules[ruleescape]() { goto l183 } if !_rules[rulenewline]() { goto l183 } if !_rules[rulewsnl]() { goto l183 } } l184: goto l182 l183: position, tokenIndex = position183, tokenIndex183 } add(rulemlBasicBody, position181) } if buffer[position] != rune('"') { goto l179 } position++ if buffer[position] != rune('"') { goto l179 } position++ if buffer[position] != rune('"') { goto l179 } position++ { add(ruleAction19, position) } add(rulemlBasicString, position180) } goto l157 l179: position, tokenIndex = position157, tokenIndex157 { position191 := position { position192 := position if buffer[position] != rune('"') { goto l88 } position++ l193: { position194, tokenIndex194 := position, tokenIndex if !_rules[rulebasicChar]() { goto l194 } goto l193 l194: position, tokenIndex = position194, tokenIndex194 } if buffer[position] != rune('"') { goto l88 } position++ add(rulePegText, position192) } { add(ruleAction18, position) } add(rulebasicString, position191) } } l157: add(rulestring, position156) } add(rulePegText, position155) } { add(ruleAction10, position) } break default: { position197 := position if !_rules[ruleinteger]() { goto l88 } add(rulePegText, position197) } { add(ruleAction9, position) } break } } } l90: add(ruleval, position89) } return true l88: position, tokenIndex = position88, tokenIndex88 return false }, /* 11 table <- <(stdTable / arrayTable)> */ nil, /* 12 stdTable <- <('[' ws ws ']' Action13)> */ nil, /* 13 arrayTable <- <('[' '[' ws ws (']' ']') Action14)> */ nil, /* 14 inlineTable <- <('{' Action15 ws inlineTableKeyValues ws '}' Action16)> */ nil, /* 15 inlineTableKeyValues <- <(keyval inlineTableValSep?)*> */ nil, /* 16 tableKey <- <(tableKeyComp (tableKeySep tableKeyComp)*)> */ func() bool { position204, tokenIndex204 := position, tokenIndex { position205 := position if !_rules[ruletableKeyComp]() { goto l204 } l206: { position207, tokenIndex207 := position, tokenIndex { position208 := position if !_rules[rulews]() { goto l207 } if buffer[position] != rune('.') { goto l207 } position++ if !_rules[rulews]() { goto l207 } add(ruletableKeySep, position208) } if !_rules[ruletableKeyComp]() { goto l207 } goto l206 l207: position, tokenIndex = position207, tokenIndex207 } add(ruletableKey, position205) } return true l204: position, tokenIndex = position204, tokenIndex204 return false }, /* 17 tableKeyComp <- <(key Action17)> */ func() bool { position209, tokenIndex209 := position, tokenIndex { position210 := position if !_rules[rulekey]() { goto l209 } { add(ruleAction17, position) } add(ruletableKeyComp, position210) } return true l209: position, tokenIndex = position209, tokenIndex209 return false }, /* 18 tableKeySep <- <(ws '.' ws)> */ nil, /* 19 inlineTableValSep <- <(ws ',' ws)> */ nil, /* 20 integer <- <(('-' / '+')? int)> */ func() bool { position214, tokenIndex214 := position, tokenIndex { position215 := position { position216, tokenIndex216 := position, tokenIndex { position218, tokenIndex218 := position, tokenIndex if buffer[position] != rune('-') { goto l219 } position++ goto l218 l219: position, tokenIndex = position218, tokenIndex218 if buffer[position] != rune('+') { goto l216 } position++ } l218: goto l217 l216: position, tokenIndex = position216, tokenIndex216 } l217: { position220 := position { position221, tokenIndex221 := position, tokenIndex if c := buffer[position]; c < rune('1') || c > rune('9') { goto l222 } position++ { position225, tokenIndex225 := position, tokenIndex if !_rules[ruledigit]() { goto l226 } goto l225 l226: position, tokenIndex = position225, tokenIndex225 if buffer[position] != rune('_') { goto l222 } position++ if !_rules[ruledigit]() { goto l222 } } l225: l223: { position224, tokenIndex224 := position, tokenIndex { position227, tokenIndex227 := position, tokenIndex if !_rules[ruledigit]() { goto l228 } goto l227 l228: position, tokenIndex = position227, tokenIndex227 if buffer[position] != rune('_') { goto l224 } position++ if !_rules[ruledigit]() { goto l224 } } l227: goto l223 l224: position, tokenIndex = position224, tokenIndex224 } goto l221 l222: position, tokenIndex = position221, tokenIndex221 if !_rules[ruledigit]() { goto l214 } } l221: add(ruleint, position220) } add(ruleinteger, position215) } return true l214: position, tokenIndex = position214, tokenIndex214 return false }, /* 21 int <- <(([1-9] (digit / ('_' digit))+) / digit)> */ nil, /* 22 float <- <(integer ((frac exp?) / (frac? exp)))> */ nil, /* 23 frac <- <('.' digit (digit / ('_' digit))*)> */ func() bool { position231, tokenIndex231 := position, tokenIndex { position232 := position if buffer[position] != rune('.') { goto l231 } position++ if !_rules[ruledigit]() { goto l231 } l233: { position234, tokenIndex234 := position, tokenIndex { position235, tokenIndex235 := position, tokenIndex if !_rules[ruledigit]() { goto l236 } goto l235 l236: position, tokenIndex = position235, tokenIndex235 if buffer[position] != rune('_') { goto l234 } position++ if !_rules[ruledigit]() { goto l234 } } l235: goto l233 l234: position, tokenIndex = position234, tokenIndex234 } add(rulefrac, position232) } return true l231: position, tokenIndex = position231, tokenIndex231 return false }, /* 24 exp <- <(('e' / 'E') ('-' / '+')? digit (digit / ('_' digit))*)> */ func() bool { position237, tokenIndex237 := position, tokenIndex { position238 := position { position239, tokenIndex239 := position, tokenIndex if buffer[position] != rune('e') { goto l240 } position++ goto l239 l240: position, tokenIndex = position239, tokenIndex239 if buffer[position] != rune('E') { goto l237 } position++ } l239: { position241, tokenIndex241 := position, tokenIndex { position243, tokenIndex243 := position, tokenIndex if buffer[position] != rune('-') { goto l244 } position++ goto l243 l244: position, tokenIndex = position243, tokenIndex243 if buffer[position] != rune('+') { goto l241 } position++ } l243: goto l242 l241: position, tokenIndex = position241, tokenIndex241 } l242: if !_rules[ruledigit]() { goto l237 } l245: { position246, tokenIndex246 := position, tokenIndex { position247, tokenIndex247 := position, tokenIndex if !_rules[ruledigit]() { goto l248 } goto l247 l248: position, tokenIndex = position247, tokenIndex247 if buffer[position] != rune('_') { goto l246 } position++ if !_rules[ruledigit]() { goto l246 } } l247: goto l245 l246: position, tokenIndex = position246, tokenIndex246 } add(ruleexp, position238) } return true l237: position, tokenIndex = position237, tokenIndex237 return false }, /* 25 string <- <(mlLiteralString / literalString / mlBasicString / basicString)> */ nil, /* 26 basicString <- <(<('"' basicChar* '"')> Action18)> */ nil, /* 27 basicChar <- <(basicUnescaped / escaped)> */ func() bool { position251, tokenIndex251 := position, tokenIndex { position252 := position { position253, tokenIndex253 := position, tokenIndex { position255 := position { switch buffer[position] { case ' ', '!': if c := buffer[position]; c < rune(' ') || c > rune('!') { goto l254 } position++ break case '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[': if c := buffer[position]; c < rune('#') || c > rune('[') { goto l254 } position++ break default: if c := buffer[position]; c < rune(']') || c > rune('\U0010ffff') { goto l254 } position++ break } } add(rulebasicUnescaped, position255) } goto l253 l254: position, tokenIndex = position253, tokenIndex253 { position257 := position if !_rules[ruleescape]() { goto l251 } { switch buffer[position] { case 'U': if buffer[position] != rune('U') { goto l251 } position++ if !_rules[rulehexQuad]() { goto l251 } if !_rules[rulehexQuad]() { goto l251 } break case 'u': if buffer[position] != rune('u') { goto l251 } position++ if !_rules[rulehexQuad]() { goto l251 } break case '\\': if buffer[position] != rune('\\') { goto l251 } position++ break case '/': if buffer[position] != rune('/') { goto l251 } position++ break case '"': if buffer[position] != rune('"') { goto l251 } position++ break case 'r': if buffer[position] != rune('r') { goto l251 } position++ break case 'f': if buffer[position] != rune('f') { goto l251 } position++ break case 'n': if buffer[position] != rune('n') { goto l251 } position++ break case 't': if buffer[position] != rune('t') { goto l251 } position++ break default: if buffer[position] != rune('b') { goto l251 } position++ break } } add(ruleescaped, position257) } } l253: add(rulebasicChar, position252) } return true l251: position, tokenIndex = position251, tokenIndex251 return false }, /* 28 escaped <- <(escape ((&('U') ('U' hexQuad hexQuad)) | (&('u') ('u' hexQuad)) | (&('\\') '\\') | (&('/') '/') | (&('"') '"') | (&('r') 'r') | (&('f') 'f') | (&('n') 'n') | (&('t') 't') | (&('b') 'b')))> */ nil, /* 29 basicUnescaped <- <((&(' ' | '!') [ -!]) | (&('#' | '$' | '%' | '&' | '\'' | '(' | ')' | '*' | '+' | ',' | '-' | '.' | '/' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' | '[') [#-[]) | (&(']' | '^' | '_' | '`' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' | '{' | '|' | '}' | '~' | '\u007f' | '\u0080' | '\u0081' | '\u0082' | '\u0083' | '\u0084' | '\u0085' | '\u0086' | '\u0087' | '\u0088' | '\u0089' | '\u008a' | '\u008b' | '\u008c' | '\u008d' | '\u008e' | '\u008f' | '\u0090' | '\u0091' | '\u0092' | '\u0093' | '\u0094' | '\u0095' | '\u0096' | '\u0097' | '\u0098' | '\u0099' | '\u009a' | '\u009b' | '\u009c' | '\u009d' | '\u009e' | '\u009f' | '\u00a0' | '¡' | '¢' | '£' | '¤' | '¥' | '¦' | '§' | '¨' | '©' | 'ª' | '«' | '¬' | '\u00ad' | '®' | '¯' | '°' | '±' | '²' | '³' | '´' | 'µ' | '¶' | '·' | '¸' | '¹' | 'º' | '»' | '¼' | '½' | '¾' | '¿' | 'À' | 'Á' | 'Â' | 'Ã' | 'Ä' | 'Å' | 'Æ' | 'Ç' | 'È' | 'É' | 'Ê' | 'Ë' | 'Ì' | 'Í' | 'Î' | 'Ï' | 'Ð' | 'Ñ' | 'Ò' | 'Ó' | 'Ô' | 'Õ' | 'Ö' | '×' | 'Ø' | 'Ù' | 'Ú' | 'Û' | 'Ü' | 'Ý' | 'Þ' | 'ß' | 'à' | 'á' | 'â' | 'ã' | 'ä' | 'å' | 'æ' | 'ç' | 'è' | 'é' | 'ê' | 'ë' | 'ì' | 'í' | 'î' | 'ï' | 'ð' | 'ñ' | 'ò' | 'ó' | 'ô' | 'õ' | 'ö' | '÷' | 'ø' | 'ù' | 'ú' | 'û' | 'ü' | 'ý' | 'þ' | 'ÿ') []-\U0010ffff]))> */ nil, /* 30 escape <- <'\\'> */ func() bool { position261, tokenIndex261 := position, tokenIndex { position262 := position if buffer[position] != rune('\\') { goto l261 } position++ add(ruleescape, position262) } return true l261: position, tokenIndex = position261, tokenIndex261 return false }, /* 31 mlBasicString <- <('"' '"' '"' mlBasicBody ('"' '"' '"') Action19)> */ nil, /* 32 mlBasicBody <- <((<(basicChar / newline)> Action20) / (escape newline wsnl))*> */ nil, /* 33 literalString <- <('\'' '\'' Action21)> */ nil, /* 34 literalChar <- <((&('\t') '\t') | (&(' ' | '!' | '"' | '#' | '$' | '%' | '&') [ -&]) | (&('(' | ')' | '*' | '+' | ',' | '-' | '.' | '/' | '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' | '[' | '\\' | ']' | '^' | '_' | '`' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' | '{' | '|' | '}' | '~' | '\u007f' | '\u0080' | '\u0081' | '\u0082' | '\u0083' | '\u0084' | '\u0085' | '\u0086' | '\u0087' | '\u0088' | '\u0089' | '\u008a' | '\u008b' | '\u008c' | '\u008d' | '\u008e' | '\u008f' | '\u0090' | '\u0091' | '\u0092' | '\u0093' | '\u0094' | '\u0095' | '\u0096' | '\u0097' | '\u0098' | '\u0099' | '\u009a' | '\u009b' | '\u009c' | '\u009d' | '\u009e' | '\u009f' | '\u00a0' | '¡' | '¢' | '£' | '¤' | '¥' | '¦' | '§' | '¨' | '©' | 'ª' | '«' | '¬' | '\u00ad' | '®' | '¯' | '°' | '±' | '²' | '³' | '´' | 'µ' | '¶' | '·' | '¸' | '¹' | 'º' | '»' | '¼' | '½' | '¾' | '¿' | 'À' | 'Á' | 'Â' | 'Ã' | 'Ä' | 'Å' | 'Æ' | 'Ç' | 'È' | 'É' | 'Ê' | 'Ë' | 'Ì' | 'Í' | 'Î' | 'Ï' | 'Ð' | 'Ñ' | 'Ò' | 'Ó' | 'Ô' | 'Õ' | 'Ö' | '×' | 'Ø' | 'Ù' | 'Ú' | 'Û' | 'Ü' | 'Ý' | 'Þ' | 'ß' | 'à' | 'á' | 'â' | 'ã' | 'ä' | 'å' | 'æ' | 'ç' | 'è' | 'é' | 'ê' | 'ë' | 'ì' | 'í' | 'î' | 'ï' | 'ð' | 'ñ' | 'ò' | 'ó' | 'ô' | 'õ' | 'ö' | '÷' | 'ø' | 'ù' | 'ú' | 'û' | 'ü' | 'ý' | 'þ' | 'ÿ') [(-\U0010ffff]))> */ nil, /* 35 mlLiteralString <- <('\'' '\'' '\'' ('\'' '\'' '\'') Action22)> */ nil, /* 36 mlLiteralBody <- <(!('\'' '\'' '\'') (mlLiteralChar / newline))*> */ nil, /* 37 mlLiteralChar <- <('\t' / [ -\U0010ffff])> */ nil, /* 38 hexdigit <- <((&('a' | 'b' | 'c' | 'd' | 'e' | 'f') [a-f]) | (&('A' | 'B' | 'C' | 'D' | 'E' | 'F') [A-F]) | (&('0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9') [0-9]))> */ func() bool { position270, tokenIndex270 := position, tokenIndex { position271 := position { switch buffer[position] { case 'a', 'b', 'c', 'd', 'e', 'f': if c := buffer[position]; c < rune('a') || c > rune('f') { goto l270 } position++ break case 'A', 'B', 'C', 'D', 'E', 'F': if c := buffer[position]; c < rune('A') || c > rune('F') { goto l270 } position++ break default: if c := buffer[position]; c < rune('0') || c > rune('9') { goto l270 } position++ break } } add(rulehexdigit, position271) } return true l270: position, tokenIndex = position270, tokenIndex270 return false }, /* 39 hexQuad <- <(hexdigit hexdigit hexdigit hexdigit)> */ func() bool { position273, tokenIndex273 := position, tokenIndex { position274 := position if !_rules[rulehexdigit]() { goto l273 } if !_rules[rulehexdigit]() { goto l273 } if !_rules[rulehexdigit]() { goto l273 } if !_rules[rulehexdigit]() { goto l273 } add(rulehexQuad, position274) } return true l273: position, tokenIndex = position273, tokenIndex273 return false }, /* 40 boolean <- <(('t' 'r' 'u' 'e') / ('f' 'a' 'l' 's' 'e'))> */ nil, /* 41 dateFullYear <- */ nil, /* 42 dateMonth <- */ nil, /* 43 dateMDay <- */ nil, /* 44 timeHour <- */ func() bool { position279, tokenIndex279 := position, tokenIndex { position280 := position if !_rules[ruledigitDual]() { goto l279 } add(ruletimeHour, position280) } return true l279: position, tokenIndex = position279, tokenIndex279 return false }, /* 45 timeMinute <- */ func() bool { position281, tokenIndex281 := position, tokenIndex { position282 := position if !_rules[ruledigitDual]() { goto l281 } add(ruletimeMinute, position282) } return true l281: position, tokenIndex = position281, tokenIndex281 return false }, /* 46 timeSecond <- */ nil, /* 47 timeSecfrac <- <('.' digit+)> */ nil, /* 48 timeNumoffset <- <(('-' / '+') timeHour ':' timeMinute)> */ nil, /* 49 timeOffset <- <('Z' / timeNumoffset)> */ nil, /* 50 partialTime <- <(timeHour ':' timeMinute ':' timeSecond timeSecfrac?)> */ func() bool { position287, tokenIndex287 := position, tokenIndex { position288 := position if !_rules[ruletimeHour]() { goto l287 } if buffer[position] != rune(':') { goto l287 } position++ if !_rules[ruletimeMinute]() { goto l287 } if buffer[position] != rune(':') { goto l287 } position++ { position289 := position if !_rules[ruledigitDual]() { goto l287 } add(ruletimeSecond, position289) } { position290, tokenIndex290 := position, tokenIndex { position292 := position if buffer[position] != rune('.') { goto l290 } position++ if !_rules[ruledigit]() { goto l290 } l293: { position294, tokenIndex294 := position, tokenIndex if !_rules[ruledigit]() { goto l294 } goto l293 l294: position, tokenIndex = position294, tokenIndex294 } add(ruletimeSecfrac, position292) } goto l291 l290: position, tokenIndex = position290, tokenIndex290 } l291: add(rulepartialTime, position288) } return true l287: position, tokenIndex = position287, tokenIndex287 return false }, /* 51 fullDate <- <(dateFullYear '-' dateMonth '-' dateMDay)> */ nil, /* 52 fullTime <- <(partialTime timeOffset)> */ nil, /* 53 datetime <- <((fullDate ('T' fullTime)?) / partialTime)> */ nil, /* 54 digit <- <[0-9]> */ func() bool { position298, tokenIndex298 := position, tokenIndex { position299 := position if c := buffer[position]; c < rune('0') || c > rune('9') { goto l298 } position++ add(ruledigit, position299) } return true l298: position, tokenIndex = position298, tokenIndex298 return false }, /* 55 digitDual <- <(digit digit)> */ func() bool { position300, tokenIndex300 := position, tokenIndex { position301 := position if !_rules[ruledigit]() { goto l300 } if !_rules[ruledigit]() { goto l300 } add(ruledigitDual, position301) } return true l300: position, tokenIndex = position300, tokenIndex300 return false }, /* 56 digitQuad <- <(digitDual digitDual)> */ nil, /* 57 array <- <('[' Action23 wsnl arrayValues? wsnl ']')> */ nil, /* 58 arrayValues <- <(val Action24 (wsnl comment? wsnl arraySep wsnl comment? wsnl val Action25)* wsnl arraySep? wsnl comment?)> */ nil, /* 59 arraySep <- <','> */ func() bool { position305, tokenIndex305 := position, tokenIndex { position306 := position if buffer[position] != rune(',') { goto l305 } position++ add(rulearraySep, position306) } return true l305: position, tokenIndex = position305, tokenIndex305 return false }, /* 61 Action0 <- <{ _ = buffer }> */ nil, nil, /* 63 Action1 <- <{ p.SetTableString(begin, end) }> */ nil, /* 64 Action2 <- <{ p.AddLineCount(end - begin) }> */ nil, /* 65 Action3 <- <{ p.AddLineCount(end - begin) }> */ nil, /* 66 Action4 <- <{ p.AddKeyValue() }> */ nil, /* 67 Action5 <- <{ p.SetKey(p.buffer, begin, end) }> */ nil, /* 68 Action6 <- <{ p.SetKey(p.buffer, begin, end) }> */ nil, /* 69 Action7 <- <{ p.SetTime(begin, end) }> */ nil, /* 70 Action8 <- <{ p.SetFloat64(begin, end) }> */ nil, /* 71 Action9 <- <{ p.SetInt64(begin, end) }> */ nil, /* 72 Action10 <- <{ p.SetString(begin, end) }> */ nil, /* 73 Action11 <- <{ p.SetBool(begin, end) }> */ nil, /* 74 Action12 <- <{ p.SetArray(begin, end) }> */ nil, /* 75 Action13 <- <{ p.SetTable(p.buffer, begin, end) }> */ nil, /* 76 Action14 <- <{ p.SetArrayTable(p.buffer, begin, end) }> */ nil, /* 77 Action15 <- <{ p.StartInlineTable() }> */ nil, /* 78 Action16 <- <{ p.EndInlineTable() }> */ nil, /* 79 Action17 <- <{ p.AddTableKey() }> */ nil, /* 80 Action18 <- <{ p.SetBasicString(p.buffer, begin, end) }> */ nil, /* 81 Action19 <- <{ p.SetMultilineString() }> */ nil, /* 82 Action20 <- <{ p.AddMultilineBasicBody(p.buffer, begin, end) }> */ nil, /* 83 Action21 <- <{ p.SetLiteralString(p.buffer, begin, end) }> */ nil, /* 84 Action22 <- <{ p.SetMultilineLiteralString(p.buffer, begin, end) }> */ nil, /* 85 Action23 <- <{ p.StartArray() }> */ nil, /* 86 Action24 <- <{ p.AddArrayVal() }> */ nil, /* 87 Action25 <- <{ p.AddArrayVal() }> */ nil, } p.rules = _rules } toml-0.1.1/testdata/000077500000000000000000000000001310060323300142645ustar00rootroot00000000000000toml-0.1.1/testdata/example.toml000066400000000000000000000011371310060323300166160ustar00rootroot00000000000000title = "TOML Example" [owner] name = "Tom Preston-Werner" organization = "GitHub" bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." dob = 1979-05-27T07:32:00Z # First class dates? Why not? [database] server = "192.168.1.1" ports = [ 8001, 8001, 8002 ] connection_max = 5000 enabled = true [servers] # You can indent as you please. Tabs or spaces. TOML don't care. [servers.alpha] ip = "10.0.0.1" dc = "eqdc10" [servers.beta] ip = "10.0.0.2" dc = "eqdc10" [clients] data = [ ["gamma", "delta"], [1, 2] ] # Line breaks are OK when inside arrays hosts = [ "alpha", "omega" ] toml-0.1.1/testdata/marshal-arraytable-empty.toml000066400000000000000000000000711310060323300220660ustar00rootroot00000000000000[[bars]] [bars.baz] key = 1 [[bars]] [bars.baz] key = 2 toml-0.1.1/testdata/marshal-funkymapkeys.toml000066400000000000000000000001101310060323300213240ustar00rootroot00000000000000[intKeys] 1 = 1 2 = 2 3 = 3 [marshalerKeys] "0001-01-01T00:00:00Z" = 1 toml-0.1.1/testdata/marshal-key-escape.toml000066400000000000000000000003011310060323300206260ustar00rootroot00000000000000"" = "empty" " " = "space" - = "dash (not quoted)" 1 = "number (not quoted)" "ʎǝʞ" = "reverse" ["subtable with space"] depth = 1 ["subtable with space"."subsubtable with space"] depth = 2 toml-0.1.1/testdata/marshal-marshaler.toml000066400000000000000000000000251310060323300205610ustar00rootroot00000000000000m1 = 1 m2 = 2 m3 = 3 toml-0.1.1/testdata/marshal-marshalerrec.toml000066400000000000000000000000441310060323300212540ustar00rootroot00000000000000m1 = 1 m2 = 2 m3 = 3 [sub] key = 1 toml-0.1.1/testdata/marshal-teststruct.toml000066400000000000000000000035031310060323300210330ustar00rootroot00000000000000[table] key = "value" [table.subtable] key = "another value" [table.inline.name] first = "Tom" last = "Preston-Werner" [table.inline.point] x = 1 y = 2 [string.basic] basic = "I'm a string. \"You can quote me\". Name\tJosé\nLocation\tSF." [string.multiline] key1 = "One\nTwo" key2 = "One\nTwo" key3 = "One\nTwo" [string.multiline.continued] key1 = "The quick brown fox jumps over the lazy dog." key2 = "The quick brown fox jumps over the lazy dog." key3 = "The quick brown fox jumps over the lazy dog." [string.literal] winpath = "C:\\Users\\nodejs\\templates" winpath2 = "\\\\ServerX\\admin$\\system32\\" quoted = "Tom \"Dubs\" Preston-Werner" regex = "<\\i\\c*\\s*>" [string.literal.multiline] regex2 = "I [dw]on't need \\d{2} apples" lines = "The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n" [integer] key1 = 99 key2 = 42 key3 = 0 key4 = -17 [integer.underscores] key1 = 1000 key2 = 5349221 key3 = 12345 [float.fractional] key1 = 1e+00 key2 = 3.1415e+00 key3 = -1e-02 [float.exponent] key1 = 5e+22 key2 = 1e+06 key3 = -2e-02 [float.both] key = 6.626e-34 [float.underscores] key1 = 9.224617445991227e+06 key2 = 1e+100 [boolean] true = true false = false [datetime] key1 = 1979-05-27T07:32:00Z key2 = 1979-05-27T00:32:00-07:00 key3 = 1979-05-27T00:32:00.999999-07:00 [array] key1 = [1, 2, 3] key2 = ["red", "yellow", "green"] key3 = [[1, 2], [3, 4, 5]] key4 = [[1, 2], ["a", "b", "c"]] key5 = [1, 2, 3] key6 = [1, 2] [[products]] name = "Hammer" sku = 738594937 [[products]] [[products]] name = "Nail" sku = 284758393 color = "gray" [[fruit]] name = "apple" [fruit.physical] color = "red" shape = "round" [[fruit.variety]] name = "red delicious" [[fruit.variety]] name = "granny smith" [[fruit]] name = "banana" [fruit.physical] color = "" shape = "" [[fruit.variety]] name = "plantain" toml-0.1.1/testdata/test.toml000066400000000000000000000122061310060323300161410ustar00rootroot00000000000000# test.toml ################################################################################ ## Comment # Speak your mind with the hash symbol. They go from the symbol to the end of # the line. ################################################################################ ## Table # Tables (also known as hash tables or dictionaries) are collections of # key/value pairs. They appear in square brackets on a line by themselves. [table] key = "value" # Yeah, you can do this. # Nested tables are denoted by table names with dots in them. Name your tables # whatever crap you please, just don't use #, ., [ or ]. [table.subtable] key = "another value" # You don't need to specify all the super-tables if you don't want to. TOML # knows how to do it for you. # [x] you # [x.y] don't # [x.y.z] need these [x.y.z.w] # for this to work ################################################################################ ## Inline Table # Inline tables provide a more compact syntax for expressing tables. They are # especially useful for grouped data that can otherwise quickly become verbose. # Inline tables are enclosed in curly braces `{` and `}`. No newlines are # allowed between the curly braces unless they are valid within a value. [table.inline] name = { first = "Tom", last = "Preston-Werner" } point = { x = 1, y = 2 } ################################################################################ ## String # There are four ways to express strings: basic, multi-line basic, literal, and # multi-line literal. All strings must contain only valid UTF-8 characters. [string.basic] basic = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF." [string.multiline] # The following strings are byte-for-byte equivalent: key1 = "One\nTwo" key2 = """One\nTwo""" key3 = """ One Two""" [string.multiline.continued] # The following strings are byte-for-byte equivalent: key1 = "The quick brown fox jumps over the lazy dog." key2 = """ The quick brown \ fox jumps over \ the lazy dog.""" key3 = """\ The quick brown \ fox jumps over \ the lazy dog.\ """ [string.literal] # What you see is what you get. winpath = 'C:\Users\nodejs\templates' winpath2 = '\\ServerX\admin$\system32\' quoted = 'Tom "Dubs" Preston-Werner' regex = '<\i\c*\s*>' [string.literal.multiline] regex2 = '''I [dw]on't need \d{2} apples''' lines = ''' The first newline is trimmed in raw strings. All other whitespace is preserved. ''' ################################################################################ ## Integer # Integers are whole numbers. Positive numbers may be prefixed with a plus sign. # Negative numbers are prefixed with a minus sign. [integer] key1 = +99 key2 = 42 key3 = 0 key4 = -17 [integer.underscores] # For large numbers, you may use underscores to enhance readability. Each # underscore must be surrounded by at least one digit. key1 = 1_000 key2 = 5_349_221 key3 = 1_2_3_4_5 # valid but inadvisable ################################################################################ ## Float # A float consists of an integer part (which may be prefixed with a plus or # minus sign) followed by a fractional part and/or an exponent part. [float.fractional] key1 = +1.0 key2 = 3.1415 key3 = -0.01 [float.exponent] key1 = 5e+22 key2 = 1e6 key3 = -2E-2 [float.both] key = 6.626e-34 [float.underscores] key1 = 9_224_617.445_991_228_313 key2 = 1e1_00 ################################################################################ ## Boolean # Booleans are just the tokens you're used to. Always lowercase. [boolean] True = true False = false ################################################################################ ## Datetime # Datetimes are RFC 3339 dates. [datetime] key1 = 1979-05-27T07:32:00Z key2 = 1979-05-27T00:32:00-07:00 key3 = 1979-05-27T00:32:00.999999-07:00 ################################################################################ ## Array # Arrays are square brackets with other primitives inside. Whitespace is # ignored. Elements are separated by commas. Data types may not be mixed. [array] key1 = [ 1, 2, 3 ] key2 = [ "red", "yellow", "green" ] key3 = [ [ 1, 2 ], [3, 4, 5] ] key4 = [ [ 1, 2 ], ["a", "b", "c"] ] # this is ok # Arrays can also be multiline. So in addition to ignoring whitespace, arrays # also ignore newlines between the brackets. Terminating commas are ok before # the closing bracket. key5 = [ 1, 2, 3 ] key6 = [ 1, 2, # this is ok ] ################################################################################ ## Array of Tables # These can be expressed by using a table name in double brackets. Each table # with the same double bracketed name will be an element in the array. The # tables are inserted in the order encountered. [[products]] name = "Hammer" sku = 738594937 [[products]] [[products]] name = "Nail" sku = 284758393 color = "gray" # You can create nested arrays of tables as well. [[fruit]] name = "apple" [fruit.physical] color = "red" shape = "round" [[fruit.variety]] name = "red delicious" [[fruit.variety]] name = "granny smith" [[fruit]] name = "banana" [[fruit.variety]] name = "plantain" toml-0.1.1/testdata/unmarshal-array-1.toml000066400000000000000000000000571310060323300204270ustar00rootroot00000000000000# unmarshal-array-1.toml ints = [ 1, 2, 3 ] toml-0.1.1/testdata/unmarshal-array-2.toml000066400000000000000000000000641310060323300204260ustar00rootroot00000000000000# unmarshal-array-2.toml ints = [ 1 , 2 , 3 ] toml-0.1.1/testdata/unmarshal-array-3.toml000066400000000000000000000001011310060323300204170ustar00rootroot00000000000000# unmarshal-array-3.toml ints = [ 1, 2, 3, # this is ok ] toml-0.1.1/testdata/unmarshal-array-4.toml000066400000000000000000000001001310060323300204170ustar00rootroot00000000000000# unmarshal-array-4.toml ints = [ 1, 2, # this is ok 3 ] toml-0.1.1/testdata/unmarshal-array-5.toml000066400000000000000000000001011310060323300204210ustar00rootroot00000000000000# unmarshal-array-5.toml ints = [ 1, 2 # this is ok , 3 ] toml-0.1.1/testdata/unmarshal-array-6.toml000066400000000000000000000001021310060323300204230ustar00rootroot00000000000000# unmarshal-array-6.toml ints = [ 1 # this is ok , 2 , 3 ] toml-0.1.1/testdata/unmarshal-arraytable-conflict-1.toml000066400000000000000000000003021310060323300232270ustar00rootroot00000000000000# unmarshal-arraytable-conflict-1.toml [[fruit]] name = "apple" [[fruit.variety]] name = "red delicious" # This table conflicts with the previous table. [fruit.variety] name = "granny smith" toml-0.1.1/testdata/unmarshal-arraytable-conflict-2.toml000066400000000000000000000003021310060323300232300ustar00rootroot00000000000000# unmarshal-arraytable-conflict-2.toml [[fruit]] name = "apple" [fruit.variety] name = "granny smith" # This table conflicts with the previous table. [[fruit.variety]] name = "red delicious" toml-0.1.1/testdata/unmarshal-arraytable-conflict-3.toml000066400000000000000000000002341310060323300232350ustar00rootroot00000000000000# unmarshal-arraytable-conflict-3.toml [[fruit]] name = "apple" variety = { name = "granny smith" } # conflicts with inline table above [[fruit.variety]] toml-0.1.1/testdata/unmarshal-arraytable-inline.toml000066400000000000000000000002131310060323300225470ustar00rootroot00000000000000# unmarshal-arraytable-inline.toml products = [{name = "Hammer", sku = 738594937}, {}, {name = "Nail", sku = 284758393, color = "gray"}]toml-0.1.1/testdata/unmarshal-arraytable-nested-1.toml000066400000000000000000000005141310060323300227150ustar00rootroot00000000000000# unmarshal-arraytable-nested-1.toml [[fruit]] name = "apple" [fruit.physical] color = "red" shape = "round" [[fruit.variety]] name = "red delicious" [[fruit.variety]] name = "granny smith" [[fruit]] name = "banana" [fruit.physical] color = "yellow" shape = "lune" [[fruit.variety]] name = "plantain" toml-0.1.1/testdata/unmarshal-arraytable-nested-2.toml000066400000000000000000000003511310060323300227150ustar00rootroot00000000000000# unmarshal-arraytable-nested-2.toml [[fruit]] [[fruit.variety]] name = "red delicious" [[fruit.variety]] name = "granny smith" [[fruit]] [[fruit.variety]] name = "plantain" [[fruit.area]] name = "phillippines" toml-0.1.1/testdata/unmarshal-arraytable-nested-3.toml000066400000000000000000000002721310060323300227200ustar00rootroot00000000000000# unmarshal-arraytable-nested-3.toml [[fruit]] variety = [{name = "red delicious"}, {name = "granny smith"}] [[fruit]] variety = [{name = "plantain"}] area = [{name = "phillippines"}] toml-0.1.1/testdata/unmarshal-arraytable.toml000066400000000000000000000002231310060323300212740ustar00rootroot00000000000000# unmarshal-arraytable.toml [[products]] name = "Hammer" sku = 738594937 [[products]] [[products]] name = "Nail" sku = 284758393 color = "gray" toml-0.1.1/testdata/unmarshal-interface.toml000066400000000000000000000003751310060323300211160ustar00rootroot00000000000000# unmarshal-interface.toml string = "string" int = 3 float = 4.0 boolean = true datetime = 1979-05-27T00:32:00.999999-07:00 array = [1, 2, 3] inline = { key = "value" } [table] key = "value" [[arraytable]] key = "value" [[arraytable]] key = "value" toml-0.1.1/testdata/unmarshal-pointer.toml000066400000000000000000000002471310060323300206340ustar00rootroot00000000000000# unmarshal-pointer.toml inline = { key1 = "test", key2 = "a", key3 = "b" } [[tables]] key1 = "a" key2 = "a" key3 = "a" [[tables]] key1 = "b" key2 = "b" key3 = "b" toml-0.1.1/testdata/unmarshal-string-1.toml000066400000000000000000000001311310060323300206100ustar00rootroot00000000000000# unmarshal-string-1.toml key1 = "One\nTwo" key2 = """One\nTwo""" key3 = """ One Two""" toml-0.1.1/testdata/unmarshal-string-2.toml000066400000000000000000000004541310060323300206210ustar00rootroot00000000000000# unmarshal-string-2.toml # The following strings are byte-for-byte equivalent: key1 = "The quick brown fox jumps over the lazy dog." key2 = """ The quick brown \ fox jumps over \ the lazy dog.""" key3 = """\ The quick brown \ fox jumps over \ the lazy dog.\ """ toml-0.1.1/testdata/unmarshal-string-3.toml000066400000000000000000000002511310060323300206150ustar00rootroot00000000000000# unmarshal-string-3.toml winpath = 'C:\Users\nodejs\templates' winpath2 = '\\ServerX\admin$\system32\' quoted = 'Tom "Dubs" Preston-Werner' regex = '<\i\c*\s*>' toml-0.1.1/testdata/unmarshal-string-4.toml000066400000000000000000000002551310060323300206220ustar00rootroot00000000000000# unmarshal-string-2.toml regex2 = '''I [dw]on't need \d{2} apples''' lines = ''' The first newline is trimmed in raw strings. All other whitespace is preserved. '''toml-0.1.1/testdata/unmarshal-table-conflict-1.toml000066400000000000000000000001241310060323300221720ustar00rootroot00000000000000# unmarshal-table-conflict-1.toml # Table a is defined twice. [a] b = 1 [a] c = 2 toml-0.1.1/testdata/unmarshal-table-conflict-2.toml000066400000000000000000000001341310060323300221740ustar00rootroot00000000000000# unmarshal-table-conflict-2.toml # Key b conflicts with table a.b. [a] b = 1 [a.b] c = 2 toml-0.1.1/testdata/unmarshal-table-conflict-3.toml000066400000000000000000000001331310060323300221740ustar00rootroot00000000000000# unmarshal-table-conflict-3.toml # Key b conflicts with table a.b [a.b] c = 2 [a] b = 1 toml-0.1.1/testdata/unmarshal-table-withinline.toml000066400000000000000000000001441310060323300224070ustar00rootroot00000000000000# unmarshal-table-withinline.toml [tab1] tabarray = [{key = "1"}] [tab2] tabarray = [{key = "2"}] toml-0.1.1/testdata/unmarshal-table-withmap.toml000066400000000000000000000002051310060323300217040ustar00rootroot00000000000000# unmarshal-table-withmap.toml [servers] [servers.alpha] ip = "10.0.0.1" dc = "eqdc10" [servers.beta] ip = "10.0.0.2" dc = "eqdc10" toml-0.1.1/testdata/unmarshal-textunmarshaler.toml000066400000000000000000000001701310060323300223750ustar00rootroot00000000000000# unmarshal-textunmarshaler.toml str = "str" int = 11 float = 12.0 [[arraytable]] str = "str2" int = 22 float = 23.0 toml-0.1.1/testdata/unmarshal-unmarshaler.toml000066400000000000000000000004341310060323300214730ustar00rootroot00000000000000# unmarshal-unmarshaler.toml title = "testtitle" max_conn = 777 ports = [8080, 8081, 8082] servers = [1, 2, 3] [table] name = "alice" [[arraytable]] name = "alice" [[arraytable]] name = "bob" [[array_of_struct]] title = "Alice's Adventures in Wonderland" author = "Lewis Carroll"toml-0.1.1/testdata/unmarshal-unmarshalerrec.toml000066400000000000000000000002071310060323300221630ustar00rootroot00000000000000# unmarshal-unmarshalerrec.toml string = "str1" [struct] a = 1 b = 2 [[arraytable]] string = "str2" [arraytable.struct] a = 3 b = 4toml-0.1.1/util.go000066400000000000000000000034341310060323300137630ustar00rootroot00000000000000package toml import ( "fmt" "reflect" "strings" ) const fieldTagName = "toml" // fieldCache maps normalized field names to their position in a struct. type fieldCache struct { named map[string]fieldInfo // fields with an explicit name in tag auto map[string]fieldInfo // fields with auto-assigned normalized names } type fieldInfo struct { index []int name string ignored bool } func makeFieldCache(cfg *Config, rt reflect.Type) fieldCache { named, auto := make(map[string]fieldInfo), make(map[string]fieldInfo) for i := 0; i < rt.NumField(); i++ { ft := rt.Field(i) // skip unexported fields if ft.PkgPath != "" && !ft.Anonymous { continue } col, _ := extractTag(ft.Tag.Get(fieldTagName)) info := fieldInfo{index: ft.Index, name: ft.Name, ignored: col == "-"} if col == "" || col == "-" { auto[cfg.NormFieldName(rt, ft.Name)] = info } else { named[col] = info } } return fieldCache{named, auto} } func (fc fieldCache) findField(cfg *Config, rv reflect.Value, name string) (reflect.Value, string, error) { info, found := fc.named[name] if !found { info, found = fc.auto[cfg.NormFieldName(rv.Type(), name)] } if !found { if cfg.MissingField == nil { return reflect.Value{}, "", fmt.Errorf("field corresponding to `%s' is not defined in %v", name, rv.Type()) } else { return reflect.Value{}, "", cfg.MissingField(rv.Type(), name) } } else if info.ignored { return reflect.Value{}, "", fmt.Errorf("field corresponding to `%s' in %v cannot be set through TOML", name, rv.Type()) } return rv.FieldByIndex(info.index), info.name, nil } func extractTag(tag string) (col, rest string) { tags := strings.SplitN(tag, ",", 2) if len(tags) == 2 { return strings.TrimSpace(tags[0]), strings.TrimSpace(tags[1]) } return strings.TrimSpace(tags[0]), "" }