11
"github.com/naoina/toml/ast"
19
escapeReplacer = strings.NewReplacer(
26
underscoreReplacer = strings.NewReplacer(
31
// Unmarshal parses the TOML data and stores the result in the value pointed to by v.
33
// Unmarshal will mapped to v that according to following rules:
35
// TOML strings to string
36
// TOML integers to any int type
37
// TOML floats to float32 or float64
38
// TOML booleans to bool
39
// TOML datetimes to time.Time
40
// TOML arrays to any type of slice or []interface{}
41
// TOML tables to struct
42
// TOML array of tables to slice of struct
43
func Unmarshal(data []byte, v interface{}) error {
44
table, err := Parse(data)
48
if err := UnmarshalTable(table, v); err != nil {
49
return fmt.Errorf("toml: unmarshal: %v", err)
54
// A Decoder reads and decodes TOML from an input stream.
59
// NewDecoder returns a new Decoder that reads from r.
60
// Note that it reads all from r before parsing it.
61
func NewDecoder(r io.Reader) *Decoder {
67
// Decode parses the TOML data from its input and stores it in the value pointed to by v.
68
// See the documentation for Unmarshal for details about the conversion of TOML into a Go value.
69
func (d *Decoder) Decode(v interface{}) error {
70
b, err := ioutil.ReadAll(d.r)
74
return Unmarshal(b, v)
77
// Unmarshaler is the interface implemented by objects that can unmarshal a
78
// TOML description of themselves.
79
// The input can be assumed to be a valid encoding of a TOML value.
80
// UnmarshalJSON must copy the TOML data if it wishes to retain the data after
82
type Unmarshaler interface {
83
UnmarshalTOML([]byte) error
86
// UnmarshalTable applies the contents of an ast.Table to the value pointed at by v.
88
// UnmarshalTable will mapped to v that according to following rules:
90
// TOML strings to string
91
// TOML integers to any int type
92
// TOML floats to float32 or float64
93
// TOML booleans to bool
94
// TOML datetimes to time.Time
95
// TOML arrays to any type of slice or []interface{}
96
// TOML tables to struct
97
// TOML array of tables to slice of struct
98
func UnmarshalTable(t *ast.Table, v interface{}) (err error) {
100
return fmt.Errorf("v must not be nil")
102
rv := reflect.ValueOf(v)
103
if kind := rv.Kind(); kind != reflect.Ptr && kind != reflect.Map {
104
return fmt.Errorf("v must be a pointer or map")
106
for rv.Kind() == reflect.Ptr {
109
if err, ok := setUnmarshaler(rv, string(t.Data)); ok {
112
for key, val := range t.Fields {
113
switch av := val.(type) {
115
fv, fieldName, found := findField(rv, key)
117
return fmt.Errorf("line %d: field corresponding to `%s' is not defined in `%T'", av.Line, key, v)
121
mv := reflect.New(fv.Type().Elem()).Elem()
122
if err := UnmarshalTable(t, mv.Addr().Interface()); err != nil {
125
fv.SetMapIndex(reflect.ValueOf(fieldName), mv)
127
if err := setValue(fv, av.Value); err != nil {
128
return fmt.Errorf("line %d: %v.%s: %v", av.Line, rv.Type(), fieldName, err)
130
if rv.Kind() == reflect.Map {
131
rv.SetMapIndex(reflect.ValueOf(fieldName), fv)
135
fv, fieldName, found := findField(rv, key)
137
return fmt.Errorf("line %d: field corresponding to `%s' is not defined in `%T'", av.Line, key, v)
139
if err, ok := setUnmarshaler(fv, string(av.Data)); ok {
145
for fv.Kind() == reflect.Ptr {
146
fv.Set(reflect.New(fv.Type().Elem()))
151
vv := reflect.New(fv.Type()).Elem()
152
if err := UnmarshalTable(av, vv.Addr().Interface()); err != nil {
156
if rv.Kind() == reflect.Map {
157
rv.SetMapIndex(reflect.ValueOf(fieldName), fv)
160
mv := reflect.MakeMap(fv.Type())
161
if err := UnmarshalTable(av, mv.Interface()); err != nil {
166
return fmt.Errorf("line %d: `%v.%s' must be struct or map, but %v given", av.Line, rv.Type(), fieldName, fv.Kind())
169
fv, fieldName, found := findField(rv, key)
171
return fmt.Errorf("line %d: field corresponding to `%s' is not defined in `%T'", av[0].Line, key, v)
173
data := make([]string, 0, len(av))
174
for _, tbl := range av {
175
data = append(data, string(tbl.Data))
177
if err, ok := setUnmarshaler(fv, strings.Join(data, "\n")); ok {
183
t := fv.Type().Elem()
185
for ; t.Kind() == reflect.Ptr; pc++ {
188
if fv.Kind() != reflect.Slice {
189
return fmt.Errorf("line %d: `%v.%s' must be slice type, but %v given", av[0].Line, rv.Type(), fieldName, fv.Kind())
191
for _, tbl := range av {
195
vv = reflect.MakeMap(t)
196
if err := UnmarshalTable(tbl, vv.Interface()); err != nil {
200
vv = reflect.New(t).Elem()
201
if err := UnmarshalTable(tbl, vv.Addr().Interface()); err != nil {
205
for i := 0; i < pc; i++ {
207
pv := reflect.New(vv.Type()).Elem()
211
fv.Set(reflect.Append(fv, vv))
213
if rv.Kind() == reflect.Map {
214
rv.SetMapIndex(reflect.ValueOf(fieldName), fv)
217
return fmt.Errorf("BUG: unknown type `%T'", t)
223
func setUnmarshaler(lhs reflect.Value, data string) (error, bool) {
224
for lhs.Kind() == reflect.Ptr {
225
lhs.Set(reflect.New(lhs.Type().Elem()))
229
if u, ok := lhs.Addr().Interface().(Unmarshaler); ok {
230
return u.UnmarshalTOML([]byte(data)), true
236
func setValue(lhs reflect.Value, val ast.Value) error {
237
for lhs.Kind() == reflect.Ptr {
238
lhs.Set(reflect.New(lhs.Type().Elem()))
241
if err, ok := setUnmarshaler(lhs, val.Source()); ok {
244
switch v := val.(type) {
246
if err := setInt(lhs, v); err != nil {
250
if err := setFloat(lhs, v); err != nil {
254
if err := setString(lhs, v); err != nil {
258
if err := setBoolean(lhs, v); err != nil {
262
if err := setDatetime(lhs, v); err != nil {
266
if err := setArray(lhs, v); err != nil {
273
func setInt(fv reflect.Value, v *ast.Integer) error {
279
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
280
if fv.OverflowInt(i) {
281
return &errorOutOfRange{fv.Kind(), i}
284
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
285
fv.SetUint(uint64(i))
286
case reflect.Interface:
287
fv.Set(reflect.ValueOf(i))
289
return fmt.Errorf("`%v' is not any types of int", fv.Type())
294
func setFloat(fv reflect.Value, v *ast.Float) error {
300
case reflect.Float32, reflect.Float64:
301
if fv.OverflowFloat(f) {
302
return &errorOutOfRange{fv.Kind(), f}
305
case reflect.Interface:
306
fv.Set(reflect.ValueOf(f))
308
return fmt.Errorf("`%v' is not float32 or float64", fv.Type())
313
func setString(fv reflect.Value, v *ast.String) error {
314
return set(fv, v.Value)
317
func setBoolean(fv reflect.Value, v *ast.Boolean) error {
318
b, err := v.Boolean()
325
func setDatetime(fv reflect.Value, v *ast.Datetime) error {
333
func setArray(fv reflect.Value, v *ast.Array) error {
334
if len(v.Value) == 0 {
337
typ := reflect.TypeOf(v.Value[0])
338
for _, vv := range v.Value[1:] {
339
if typ != reflect.TypeOf(vv) {
340
return fmt.Errorf("array cannot contain multiple types")
343
sliceType := fv.Type()
344
if fv.Kind() == reflect.Interface {
345
sliceType = reflect.SliceOf(sliceType)
347
slice := reflect.MakeSlice(sliceType, 0, len(v.Value))
348
t := sliceType.Elem()
349
for _, vv := range v.Value {
350
tmp := reflect.New(t).Elem()
351
if err := setValue(tmp, vv); err != nil {
354
slice = reflect.Append(slice, tmp)
360
func set(fv reflect.Value, v interface{}) error {
361
rhs := reflect.ValueOf(v)
362
if !rhs.Type().AssignableTo(fv.Type()) {
363
return fmt.Errorf("`%v' type is not assignable to `%v' type", rhs.Type(), fv.Type())
377
currentTable *ast.Table
382
tableMap map[string]*ast.Table
387
func (p *toml) init(data []rune) {
389
p.table = &ast.Table{
391
Type: ast.TableTypeNormal,
392
Data: data[:len(data)-1], // truncate the end_symbol added by PEG parse generator.
394
p.tableMap = map[string]*ast.Table{
397
p.currentTable = p.table
400
func (p *toml) Error(err error) {
401
panic(convertError{fmt.Errorf("toml: line %d: %v", p.line, err)})
404
func (p *tomlParser) SetTime(begin, end int) {
405
p.val = &ast.Datetime{
406
Position: ast.Position{Begin: begin, End: end},
407
Data: p.buffer[begin:end],
408
Value: string(p.buffer[begin:end]),
412
func (p *tomlParser) SetFloat64(begin, end int) {
414
Position: ast.Position{Begin: begin, End: end},
415
Data: p.buffer[begin:end],
416
Value: underscoreReplacer.Replace(string(p.buffer[begin:end])),
420
func (p *tomlParser) SetInt64(begin, end int) {
421
p.val = &ast.Integer{
422
Position: ast.Position{Begin: begin, End: end},
423
Data: p.buffer[begin:end],
424
Value: underscoreReplacer.Replace(string(p.buffer[begin:end])),
428
func (p *tomlParser) SetString(begin, end int) {
430
Position: ast.Position{Begin: begin, End: end},
431
Data: p.buffer[begin:end],
437
func (p *tomlParser) SetBool(begin, end int) {
438
p.val = &ast.Boolean{
439
Position: ast.Position{Begin: begin, End: end},
440
Data: p.buffer[begin:end],
441
Value: string(p.buffer[begin:end]),
445
func (p *tomlParser) StartArray() {
447
p.arr = &array{line: p.line, current: &ast.Array{}}
450
p.arr.child = &array{parent: p.arr, line: p.line, current: &ast.Array{}}
454
func (p *tomlParser) AddArrayVal() {
455
if p.arr.current == nil {
456
p.arr.current = &ast.Array{}
458
p.arr.current.Value = append(p.arr.current.Value, p.val)
461
func (p *tomlParser) SetArray(begin, end int) {
462
p.arr.current.Position = ast.Position{Begin: begin, End: end}
463
p.arr.current.Data = p.buffer[begin:end]
464
p.val = p.arr.current
468
func (p *toml) SetTable(buf []rune, begin, end int) {
469
p.setTable(p.table, buf, begin, end)
472
func (p *toml) setTable(t *ast.Table, buf []rune, begin, end int) {
473
name := string(buf[begin:end])
474
names := splitTableKey(name)
475
if t, exists := p.tableMap[name]; exists {
476
if lt := p.tableMap[names[len(names)-1]]; t.Type == ast.TableTypeArray || lt != nil && lt.Type == ast.TableTypeNormal {
477
p.Error(fmt.Errorf("table `%s' is in conflict with %v table in line %d", name, t.Type, t.Line))
480
t, err := p.lookupTable(t, names)
485
p.tableMap[name] = p.currentTable
488
func (p *tomlParser) SetTableString(begin, end int) {
489
p.currentTable.Data = p.buffer[begin:end]
491
p.currentTable.Position.Begin = begin
492
p.currentTable.Position.End = end
495
func (p *toml) SetArrayTable(buf []rune, begin, end int) {
496
p.setArrayTable(p.table, buf, begin, end)
499
func (p *toml) setArrayTable(t *ast.Table, buf []rune, begin, end int) {
500
name := string(buf[begin:end])
501
if t, exists := p.tableMap[name]; exists && t.Type == ast.TableTypeNormal {
502
p.Error(fmt.Errorf("table `%s' is in conflict with %v table in line %d", name, t.Type, t.Line))
504
names := splitTableKey(name)
505
t, err := p.lookupTable(t, names[:len(names)-1])
509
last := names[len(names)-1]
511
Position: ast.Position{begin, end},
514
Type: ast.TableTypeArray,
516
switch v := t.Fields[last].(type) {
519
t.Fields = make(map[string]interface{})
521
t.Fields[last] = []*ast.Table{tbl}
523
t.Fields[last] = append(v, tbl)
525
p.Error(fmt.Errorf("key `%s' is in conflict with line %d", last, v.Line))
527
p.Error(fmt.Errorf("BUG: key `%s' is in conflict but it's unknown type `%T'", last, v))
530
p.tableMap[name] = p.currentTable
533
func (p *toml) StartInlineTable() {
535
p.stack = append(p.stack, &stack{p.key, p.currentTable})
538
p.setTable(p.currentTable, buf, 0, len(buf))
540
p.setArrayTable(p.currentTable, buf, 0, len(buf))
544
func (p *toml) EndInlineTable() {
545
st := p.stack[len(p.stack)-1]
546
p.key, p.currentTable = st.key, st.table
547
p.stack[len(p.stack)-1] = nil
548
p.stack = p.stack[:len(p.stack)-1]
552
func (p *toml) AddLineCount(i int) {
556
func (p *toml) SetKey(buf []rune, begin, end int) {
557
p.key = string(buf[begin:end])
560
func (p *toml) AddKeyValue() {
565
if val, exists := p.currentTable.Fields[p.key]; exists {
566
switch v := val.(type) {
568
p.Error(fmt.Errorf("key `%s' is in conflict with %v table in line %d", p.key, v.Type, v.Line))
570
p.Error(fmt.Errorf("key `%s' is in conflict with line %d", p.key, v.Line))
572
p.Error(fmt.Errorf("BUG: key `%s' is in conflict but it's unknown type `%T'", p.key, v))
575
if p.currentTable.Fields == nil {
576
p.currentTable.Fields = make(map[string]interface{})
578
p.currentTable.Fields[p.key] = &ast.KeyValue{
585
func (p *toml) SetBasicString(buf []rune, begin, end int) {
586
p.s = p.unquote(string(buf[begin:end]))
589
func (p *toml) SetMultilineString() {
590
p.s = p.unquote(`"` + escapeReplacer.Replace(strings.TrimLeft(p.s, "\r\n")) + `"`)
593
func (p *toml) AddMultilineBasicBody(buf []rune, begin, end int) {
594
p.s += string(buf[begin:end])
597
func (p *toml) SetLiteralString(buf []rune, begin, end int) {
598
p.s = string(buf[begin:end])
601
func (p *toml) SetMultilineLiteralString(buf []rune, begin, end int) {
602
p.s = strings.TrimLeft(string(buf[begin:end]), "\r\n")
605
func (p *toml) unquote(s string) string {
606
s, err := strconv.Unquote(s)
613
func (p *toml) lookupTable(t *ast.Table, keys []string) (*ast.Table, error) {
614
for _, s := range keys {
615
val, exists := t.Fields[s]
620
Type: ast.TableTypeNormal,
623
t.Fields = make(map[string]interface{})
629
switch v := val.(type) {
635
return nil, fmt.Errorf("key `%s' is in conflict with line %d", s, v.Line)
637
return nil, fmt.Errorf("BUG: key `%s' is in conflict but it's unknown type `%T'", s, v)
643
func splitTableKey(tk string) []string {
644
key := make([]byte, 0, 1)
645
keys := make([]string, 0, 1)
647
for i := 0; i < len(tk); i++ {
650
case k == tableSeparator && !inQuote:
651
keys = append(keys, string(key))
652
key = key[:0] // reuse buffer.
655
case (k == ' ' || k == '\t') && !inQuote:
661
keys = append(keys, string(key))
665
type convertError struct {
669
func (e convertError) Error() string {