Browse code

vendor: update BurntSushi/toml for MIT license

Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>

Akihiro Suda authored on 2018/02/05 13:57:49
Showing 10 changed files
... ...
@@ -44,7 +44,7 @@ github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
44 44
 github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef
45 45
 github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
46 46
 github.com/vishvananda/netlink b2de5d10e38ecce8607e6b438b6d174f389a004e
47
-github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
47
+github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
48 48
 github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
49 49
 github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
50 50
 github.com/coreos/etcd v3.2.1
... ...
@@ -1,14 +1,21 @@
1
-            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2
-                    Version 2, December 2004
1
+The MIT License (MIT)
3 2
 
4
- Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
3
+Copyright (c) 2013 TOML authors
5 4
 
6
- Everyone is permitted to copy and distribute verbatim or modified
7
- copies of this license document, and changing it is allowed as long
8
- as the name is changed.
5
+Permission is hereby granted, free of charge, to any person obtaining a copy
6
+of this software and associated documentation files (the "Software"), to deal
7
+in the Software without restriction, including without limitation the rights
8
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+copies of the Software, and to permit persons to whom the Software is
10
+furnished to do so, subject to the following conditions:
9 11
 
10
-            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11
-   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12
-
13
-  0. You just DO WHAT THE FUCK YOU WANT TO.
12
+The above copyright notice and this permission notice shall be included in
13
+all copies or substantial portions of the Software.
14 14
 
15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+THE SOFTWARE.
... ...
@@ -1,17 +1,17 @@
1 1
 ## TOML parser and encoder for Go with reflection
2 2
 
3 3
 TOML stands for Tom's Obvious, Minimal Language. This Go package provides a
4
-reflection interface similar to Go's standard library `json` and `xml` 
4
+reflection interface similar to Go's standard library `json` and `xml`
5 5
 packages. This package also supports the `encoding.TextUnmarshaler` and
6
-`encoding.TextMarshaler` interfaces so that you can define custom data 
6
+`encoding.TextMarshaler` interfaces so that you can define custom data
7 7
 representations. (There is an example of this below.)
8 8
 
9
-Spec: https://github.com/mojombo/toml
9
+Spec: https://github.com/toml-lang/toml
10 10
 
11 11
 Compatible with TOML version
12
-[v0.2.0](https://github.com/mojombo/toml/blob/master/versions/toml-v0.2.0.md)
12
+[v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md)
13 13
 
14
-Documentation: http://godoc.org/github.com/BurntSushi/toml
14
+Documentation: https://godoc.org/github.com/BurntSushi/toml
15 15
 
16 16
 Installation:
17 17
 
... ...
@@ -26,8 +26,7 @@ go get github.com/BurntSushi/toml/cmd/tomlv
26 26
 tomlv some-toml-file.toml
27 27
 ```
28 28
 
29
-[![Build status](https://api.travis-ci.org/BurntSushi/toml.png)](https://travis-ci.org/BurntSushi/toml)
30
-
29
+[![Build Status](https://travis-ci.org/BurntSushi/toml.svg?branch=master)](https://travis-ci.org/BurntSushi/toml) [![GoDoc](https://godoc.org/github.com/BurntSushi/toml?status.svg)](https://godoc.org/github.com/BurntSushi/toml)
31 30
 
32 31
 ### Testing
33 32
 
... ...
@@ -87,7 +86,7 @@ type TOML struct {
87 87
 
88 88
 ### Using the `encoding.TextUnmarshaler` interface
89 89
 
90
-Here's an example that automatically parses duration strings into 
90
+Here's an example that automatically parses duration strings into
91 91
 `time.Duration` values:
92 92
 
93 93
 ```toml
... ...
@@ -120,7 +119,7 @@ for _, s := range favorites.Song {
120 120
 }
121 121
 ```
122 122
 
123
-And you'll also need a `duration` type that satisfies the 
123
+And you'll also need a `duration` type that satisfies the
124 124
 `encoding.TextUnmarshaler` interface:
125 125
 
126 126
 ```go
... ...
@@ -217,4 +216,3 @@ Note that a case insensitive match will be tried if an exact match can't be
217 217
 found.
218 218
 
219 219
 A working example of the above can be found in `_examples/example.{go,toml}`.
220
-
... ...
@@ -10,7 +10,9 @@ import (
10 10
 	"time"
11 11
 )
12 12
 
13
-var e = fmt.Errorf
13
+func e(format string, args ...interface{}) error {
14
+	return fmt.Errorf("toml: "+format, args...)
15
+}
14 16
 
15 17
 // Unmarshaler is the interface implemented by objects that can unmarshal a
16 18
 // TOML description of themselves.
... ...
@@ -103,6 +105,13 @@ func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error {
103 103
 // This decoder will not handle cyclic types. If a cyclic type is passed,
104 104
 // `Decode` will not terminate.
105 105
 func Decode(data string, v interface{}) (MetaData, error) {
106
+	rv := reflect.ValueOf(v)
107
+	if rv.Kind() != reflect.Ptr {
108
+		return MetaData{}, e("Decode of non-pointer %s", reflect.TypeOf(v))
109
+	}
110
+	if rv.IsNil() {
111
+		return MetaData{}, e("Decode of nil %s", reflect.TypeOf(v))
112
+	}
106 113
 	p, err := parse(data)
107 114
 	if err != nil {
108 115
 		return MetaData{}, err
... ...
@@ -111,7 +120,7 @@ func Decode(data string, v interface{}) (MetaData, error) {
111 111
 		p.mapping, p.types, p.ordered,
112 112
 		make(map[string]bool, len(p.ordered)), nil,
113 113
 	}
114
-	return md, md.unify(p.mapping, rvalue(v))
114
+	return md, md.unify(p.mapping, indirect(rv))
115 115
 }
116 116
 
117 117
 // DecodeFile is just like Decode, except it will automatically read the
... ...
@@ -211,7 +220,7 @@ func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
211 211
 	case reflect.Interface:
212 212
 		// we only support empty interfaces.
213 213
 		if rv.NumMethod() > 0 {
214
-			return e("Unsupported type '%s'.", rv.Kind())
214
+			return e("unsupported type %s", rv.Type())
215 215
 		}
216 216
 		return md.unifyAnything(data, rv)
217 217
 	case reflect.Float32:
... ...
@@ -219,13 +228,17 @@ func (md *MetaData) unify(data interface{}, rv reflect.Value) error {
219 219
 	case reflect.Float64:
220 220
 		return md.unifyFloat64(data, rv)
221 221
 	}
222
-	return e("Unsupported type '%s'.", rv.Kind())
222
+	return e("unsupported type %s", rv.Kind())
223 223
 }
224 224
 
225 225
 func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
226 226
 	tmap, ok := mapping.(map[string]interface{})
227 227
 	if !ok {
228
-		return mismatch(rv, "map", mapping)
228
+		if mapping == nil {
229
+			return nil
230
+		}
231
+		return e("type mismatch for %s: expected table but found %T",
232
+			rv.Type().String(), mapping)
229 233
 	}
230 234
 
231 235
 	for key, datum := range tmap {
... ...
@@ -250,14 +263,13 @@ func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
250 250
 				md.decoded[md.context.add(key).String()] = true
251 251
 				md.context = append(md.context, key)
252 252
 				if err := md.unify(datum, subv); err != nil {
253
-					return e("Type mismatch for '%s.%s': %s",
254
-						rv.Type().String(), f.name, err)
253
+					return err
255 254
 				}
256 255
 				md.context = md.context[0 : len(md.context)-1]
257 256
 			} else if f.name != "" {
258 257
 				// Bad user! No soup for you!
259
-				return e("Field '%s.%s' is unexported, and therefore cannot "+
260
-					"be loaded with reflection.", rv.Type().String(), f.name)
258
+				return e("cannot write unexported field %s.%s",
259
+					rv.Type().String(), f.name)
261 260
 			}
262 261
 		}
263 262
 	}
... ...
@@ -267,6 +279,9 @@ func (md *MetaData) unifyStruct(mapping interface{}, rv reflect.Value) error {
267 267
 func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error {
268 268
 	tmap, ok := mapping.(map[string]interface{})
269 269
 	if !ok {
270
+		if tmap == nil {
271
+			return nil
272
+		}
270 273
 		return badtype("map", mapping)
271 274
 	}
272 275
 	if rv.IsNil() {
... ...
@@ -292,6 +307,9 @@ func (md *MetaData) unifyMap(mapping interface{}, rv reflect.Value) error {
292 292
 func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error {
293 293
 	datav := reflect.ValueOf(data)
294 294
 	if datav.Kind() != reflect.Slice {
295
+		if !datav.IsValid() {
296
+			return nil
297
+		}
295 298
 		return badtype("slice", data)
296 299
 	}
297 300
 	sliceLen := datav.Len()
... ...
@@ -305,12 +323,16 @@ func (md *MetaData) unifyArray(data interface{}, rv reflect.Value) error {
305 305
 func (md *MetaData) unifySlice(data interface{}, rv reflect.Value) error {
306 306
 	datav := reflect.ValueOf(data)
307 307
 	if datav.Kind() != reflect.Slice {
308
+		if !datav.IsValid() {
309
+			return nil
310
+		}
308 311
 		return badtype("slice", data)
309 312
 	}
310
-	sliceLen := datav.Len()
311
-	if rv.IsNil() {
312
-		rv.Set(reflect.MakeSlice(rv.Type(), sliceLen, sliceLen))
313
+	n := datav.Len()
314
+	if rv.IsNil() || rv.Cap() < n {
315
+		rv.Set(reflect.MakeSlice(rv.Type(), n, n))
313 316
 	}
317
+	rv.SetLen(n)
314 318
 	return md.unifySliceArray(datav, rv)
315 319
 }
316 320
 
... ...
@@ -365,15 +387,15 @@ func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error {
365 365
 				// No bounds checking necessary.
366 366
 			case reflect.Int8:
367 367
 				if num < math.MinInt8 || num > math.MaxInt8 {
368
-					return e("Value '%d' is out of range for int8.", num)
368
+					return e("value %d is out of range for int8", num)
369 369
 				}
370 370
 			case reflect.Int16:
371 371
 				if num < math.MinInt16 || num > math.MaxInt16 {
372
-					return e("Value '%d' is out of range for int16.", num)
372
+					return e("value %d is out of range for int16", num)
373 373
 				}
374 374
 			case reflect.Int32:
375 375
 				if num < math.MinInt32 || num > math.MaxInt32 {
376
-					return e("Value '%d' is out of range for int32.", num)
376
+					return e("value %d is out of range for int32", num)
377 377
 				}
378 378
 			}
379 379
 			rv.SetInt(num)
... ...
@@ -384,15 +406,15 @@ func (md *MetaData) unifyInt(data interface{}, rv reflect.Value) error {
384 384
 				// No bounds checking necessary.
385 385
 			case reflect.Uint8:
386 386
 				if num < 0 || unum > math.MaxUint8 {
387
-					return e("Value '%d' is out of range for uint8.", num)
387
+					return e("value %d is out of range for uint8", num)
388 388
 				}
389 389
 			case reflect.Uint16:
390 390
 				if num < 0 || unum > math.MaxUint16 {
391
-					return e("Value '%d' is out of range for uint16.", num)
391
+					return e("value %d is out of range for uint16", num)
392 392
 				}
393 393
 			case reflect.Uint32:
394 394
 				if num < 0 || unum > math.MaxUint32 {
395
-					return e("Value '%d' is out of range for uint32.", num)
395
+					return e("value %d is out of range for uint32", num)
396 396
 				}
397 397
 			}
398 398
 			rv.SetUint(unum)
... ...
@@ -458,7 +480,7 @@ func rvalue(v interface{}) reflect.Value {
458 458
 // interest to us (like encoding.TextUnmarshaler).
459 459
 func indirect(v reflect.Value) reflect.Value {
460 460
 	if v.Kind() != reflect.Ptr {
461
-		if v.CanAddr() {
461
+		if v.CanSet() {
462 462
 			pv := v.Addr()
463 463
 			if _, ok := pv.Interface().(TextUnmarshaler); ok {
464 464
 				return pv
... ...
@@ -483,10 +505,5 @@ func isUnifiable(rv reflect.Value) bool {
483 483
 }
484 484
 
485 485
 func badtype(expected string, data interface{}) error {
486
-	return e("Expected %s but found '%T'.", expected, data)
487
-}
488
-
489
-func mismatch(user reflect.Value, expected string, data interface{}) error {
490
-	return e("Type mismatch for %s. Expected %s but found '%T'.",
491
-		user.Type().String(), expected, data)
486
+	return e("cannot load TOML value of type %T into a Go %s", data, expected)
492 487
 }
... ...
@@ -77,9 +77,8 @@ func (k Key) maybeQuoted(i int) string {
77 77
 	}
78 78
 	if quote {
79 79
 		return "\"" + strings.Replace(k[i], "\"", "\\\"", -1) + "\""
80
-	} else {
81
-		return k[i]
82 80
 	}
81
+	return k[i]
83 82
 }
84 83
 
85 84
 func (k Key) add(piece string) Key {
... ...
@@ -4,7 +4,7 @@ files via reflection. There is also support for delaying decoding with
4 4
 the Primitive type, and querying the set of keys in a TOML document with the
5 5
 MetaData type.
6 6
 
7
-The specification implemented: https://github.com/mojombo/toml
7
+The specification implemented: https://github.com/toml-lang/toml
8 8
 
9 9
 The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify
10 10
 whether a file is a valid TOML document. It can also be used to print the
... ...
@@ -16,17 +16,17 @@ type tomlEncodeError struct{ error }
16 16
 
17 17
 var (
18 18
 	errArrayMixedElementTypes = errors.New(
19
-		"can't encode array with mixed element types")
19
+		"toml: cannot encode array with mixed element types")
20 20
 	errArrayNilElement = errors.New(
21
-		"can't encode array with nil element")
21
+		"toml: cannot encode array with nil element")
22 22
 	errNonString = errors.New(
23
-		"can't encode a map with non-string key type")
23
+		"toml: cannot encode a map with non-string key type")
24 24
 	errAnonNonStruct = errors.New(
25
-		"can't encode an anonymous field that is not a struct")
25
+		"toml: cannot encode an anonymous field that is not a struct")
26 26
 	errArrayNoTable = errors.New(
27
-		"TOML array element can't contain a table")
27
+		"toml: TOML array element cannot contain a table")
28 28
 	errNoKey = errors.New(
29
-		"top-level values must be a Go map or struct")
29
+		"toml: top-level values must be Go maps or structs")
30 30
 	errAnything = errors.New("") // used in testing
31 31
 )
32 32
 
... ...
@@ -148,7 +148,7 @@ func (enc *Encoder) encode(key Key, rv reflect.Value) {
148 148
 	case reflect.Struct:
149 149
 		enc.eTable(key, rv)
150 150
 	default:
151
-		panic(e("Unsupported type for key '%s': %s", key, k))
151
+		panic(e("unsupported type for key '%s': %s", key, k))
152 152
 	}
153 153
 }
154 154
 
... ...
@@ -160,7 +160,7 @@ func (enc *Encoder) eElement(rv reflect.Value) {
160 160
 		// Special case time.Time as a primitive. Has to come before
161 161
 		// TextMarshaler below because time.Time implements
162 162
 		// encoding.TextMarshaler, but we need to always use UTC.
163
-		enc.wf(v.In(time.FixedZone("UTC", 0)).Format("2006-01-02T15:04:05Z"))
163
+		enc.wf(v.UTC().Format("2006-01-02T15:04:05Z"))
164 164
 		return
165 165
 	case TextMarshaler:
166 166
 		// Special case. Use text marshaler if it's available for this value.
... ...
@@ -191,7 +191,7 @@ func (enc *Encoder) eElement(rv reflect.Value) {
191 191
 	case reflect.String:
192 192
 		enc.writeQuoted(rv.String())
193 193
 	default:
194
-		panic(e("Unexpected primitive type: %s", rv.Kind()))
194
+		panic(e("unexpected primitive type: %s", rv.Kind()))
195 195
 	}
196 196
 }
197 197
 
... ...
@@ -241,7 +241,7 @@ func (enc *Encoder) eArrayOfTables(key Key, rv reflect.Value) {
241 241
 func (enc *Encoder) eTable(key Key, rv reflect.Value) {
242 242
 	panicIfInvalidKey(key)
243 243
 	if len(key) == 1 {
244
-		// Output an extra new line between top-level tables.
244
+		// Output an extra newline between top-level tables.
245 245
 		// (The newline isn't written if nothing else has been written though.)
246 246
 		enc.newline()
247 247
 	}
... ...
@@ -306,19 +306,36 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value) {
306 306
 	addFields = func(rt reflect.Type, rv reflect.Value, start []int) {
307 307
 		for i := 0; i < rt.NumField(); i++ {
308 308
 			f := rt.Field(i)
309
-			// skip unexporded fields
310
-			if f.PkgPath != "" {
309
+			// skip unexported fields
310
+			if f.PkgPath != "" && !f.Anonymous {
311 311
 				continue
312 312
 			}
313 313
 			frv := rv.Field(i)
314 314
 			if f.Anonymous {
315
-				frv := eindirect(frv)
316
-				t := frv.Type()
317
-				if t.Kind() != reflect.Struct {
318
-					encPanic(errAnonNonStruct)
315
+				t := f.Type
316
+				switch t.Kind() {
317
+				case reflect.Struct:
318
+					// Treat anonymous struct fields with
319
+					// tag names as though they are not
320
+					// anonymous, like encoding/json does.
321
+					if getOptions(f.Tag).name == "" {
322
+						addFields(t, frv, f.Index)
323
+						continue
324
+					}
325
+				case reflect.Ptr:
326
+					if t.Elem().Kind() == reflect.Struct &&
327
+						getOptions(f.Tag).name == "" {
328
+						if !frv.IsNil() {
329
+							addFields(t.Elem(), frv.Elem(), f.Index)
330
+						}
331
+						continue
332
+					}
333
+					// Fall through to the normal field encoding logic below
334
+					// for non-struct anonymous fields.
319 335
 				}
320
-				addFields(t, frv, f.Index)
321
-			} else if typeIsHash(tomlTypeOfGo(frv)) {
336
+			}
337
+
338
+			if typeIsHash(tomlTypeOfGo(frv)) {
322 339
 				fieldsSub = append(fieldsSub, append(start, f.Index...))
323 340
 			} else {
324 341
 				fieldsDirect = append(fieldsDirect, append(start, f.Index...))
... ...
@@ -336,13 +353,21 @@ func (enc *Encoder) eStruct(key Key, rv reflect.Value) {
336 336
 				continue
337 337
 			}
338 338
 
339
-			keyName := sft.Tag.Get("toml")
340
-			if keyName == "-" {
339
+			opts := getOptions(sft.Tag)
340
+			if opts.skip {
341 341
 				continue
342 342
 			}
343
-			if keyName == "" {
344
-				keyName = sft.Name
343
+			keyName := sft.Name
344
+			if opts.name != "" {
345
+				keyName = opts.name
346
+			}
347
+			if opts.omitempty && isEmpty(sf) {
348
+				continue
345 349
 			}
350
+			if opts.omitzero && isZero(sf) {
351
+				continue
352
+			}
353
+
346 354
 			enc.encode(key.add(keyName), sf)
347 355
 		}
348 356
 	}
... ...
@@ -374,9 +399,8 @@ func tomlTypeOfGo(rv reflect.Value) tomlType {
374 374
 	case reflect.Array, reflect.Slice:
375 375
 		if typeEqual(tomlHash, tomlArrayType(rv)) {
376 376
 			return tomlArrayHash
377
-		} else {
378
-			return tomlArray
379 377
 		}
378
+		return tomlArray
380 379
 	case reflect.Ptr, reflect.Interface:
381 380
 		return tomlTypeOfGo(rv.Elem())
382 381
 	case reflect.String:
... ...
@@ -433,6 +457,54 @@ func tomlArrayType(rv reflect.Value) tomlType {
433 433
 	return firstType
434 434
 }
435 435
 
436
+type tagOptions struct {
437
+	skip      bool // "-"
438
+	name      string
439
+	omitempty bool
440
+	omitzero  bool
441
+}
442
+
443
+func getOptions(tag reflect.StructTag) tagOptions {
444
+	t := tag.Get("toml")
445
+	if t == "-" {
446
+		return tagOptions{skip: true}
447
+	}
448
+	var opts tagOptions
449
+	parts := strings.Split(t, ",")
450
+	opts.name = parts[0]
451
+	for _, s := range parts[1:] {
452
+		switch s {
453
+		case "omitempty":
454
+			opts.omitempty = true
455
+		case "omitzero":
456
+			opts.omitzero = true
457
+		}
458
+	}
459
+	return opts
460
+}
461
+
462
+func isZero(rv reflect.Value) bool {
463
+	switch rv.Kind() {
464
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
465
+		return rv.Int() == 0
466
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
467
+		return rv.Uint() == 0
468
+	case reflect.Float32, reflect.Float64:
469
+		return rv.Float() == 0.0
470
+	}
471
+	return false
472
+}
473
+
474
+func isEmpty(rv reflect.Value) bool {
475
+	switch rv.Kind() {
476
+	case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
477
+		return rv.Len() == 0
478
+	case reflect.Bool:
479
+		return !rv.Bool()
480
+	}
481
+	return false
482
+}
483
+
436 484
 func (enc *Encoder) newline() {
437 485
 	if enc.hasWritten {
438 486
 		enc.wf("\n")
... ...
@@ -3,6 +3,7 @@ package toml
3 3
 import (
4 4
 	"fmt"
5 5
 	"strings"
6
+	"unicode"
6 7
 	"unicode/utf8"
7 8
 )
8 9
 
... ...
@@ -29,24 +30,28 @@ const (
29 29
 	itemArrayTableEnd
30 30
 	itemKeyStart
31 31
 	itemCommentStart
32
+	itemInlineTableStart
33
+	itemInlineTableEnd
32 34
 )
33 35
 
34 36
 const (
35
-	eof             = 0
36
-	tableStart      = '['
37
-	tableEnd        = ']'
38
-	arrayTableStart = '['
39
-	arrayTableEnd   = ']'
40
-	tableSep        = '.'
41
-	keySep          = '='
42
-	arrayStart      = '['
43
-	arrayEnd        = ']'
44
-	arrayValTerm    = ','
45
-	commentStart    = '#'
46
-	stringStart     = '"'
47
-	stringEnd       = '"'
48
-	rawStringStart  = '\''
49
-	rawStringEnd    = '\''
37
+	eof              = 0
38
+	comma            = ','
39
+	tableStart       = '['
40
+	tableEnd         = ']'
41
+	arrayTableStart  = '['
42
+	arrayTableEnd    = ']'
43
+	tableSep         = '.'
44
+	keySep           = '='
45
+	arrayStart       = '['
46
+	arrayEnd         = ']'
47
+	commentStart     = '#'
48
+	stringStart      = '"'
49
+	stringEnd        = '"'
50
+	rawStringStart   = '\''
51
+	rawStringEnd     = '\''
52
+	inlineTableStart = '{'
53
+	inlineTableEnd   = '}'
50 54
 )
51 55
 
52 56
 type stateFn func(lx *lexer) stateFn
... ...
@@ -55,11 +60,18 @@ type lexer struct {
55 55
 	input string
56 56
 	start int
57 57
 	pos   int
58
-	width int
59 58
 	line  int
60 59
 	state stateFn
61 60
 	items chan item
62 61
 
62
+	// Allow for backing up up to three runes.
63
+	// This is necessary because TOML contains 3-rune tokens (""" and ''').
64
+	prevWidths [3]int
65
+	nprev      int // how many of prevWidths are in use
66
+	// If we emit an eof, we can still back up, but it is not OK to call
67
+	// next again.
68
+	atEOF bool
69
+
63 70
 	// A stack of state functions used to maintain context.
64 71
 	// The idea is to reuse parts of the state machine in various places.
65 72
 	// For example, values can appear at the top level or within arbitrarily
... ...
@@ -87,7 +99,7 @@ func (lx *lexer) nextItem() item {
87 87
 
88 88
 func lex(input string) *lexer {
89 89
 	lx := &lexer{
90
-		input: input + "\n",
90
+		input: input,
91 91
 		state: lexTop,
92 92
 		line:  1,
93 93
 		items: make(chan item, 10),
... ...
@@ -102,7 +114,7 @@ func (lx *lexer) push(state stateFn) {
102 102
 
103 103
 func (lx *lexer) pop() stateFn {
104 104
 	if len(lx.stack) == 0 {
105
-		return lx.errorf("BUG in lexer: no states to pop.")
105
+		return lx.errorf("BUG in lexer: no states to pop")
106 106
 	}
107 107
 	last := lx.stack[len(lx.stack)-1]
108 108
 	lx.stack = lx.stack[0 : len(lx.stack)-1]
... ...
@@ -124,16 +136,25 @@ func (lx *lexer) emitTrim(typ itemType) {
124 124
 }
125 125
 
126 126
 func (lx *lexer) next() (r rune) {
127
+	if lx.atEOF {
128
+		panic("next called after EOF")
129
+	}
127 130
 	if lx.pos >= len(lx.input) {
128
-		lx.width = 0
131
+		lx.atEOF = true
129 132
 		return eof
130 133
 	}
131 134
 
132 135
 	if lx.input[lx.pos] == '\n' {
133 136
 		lx.line++
134 137
 	}
135
-	r, lx.width = utf8.DecodeRuneInString(lx.input[lx.pos:])
136
-	lx.pos += lx.width
138
+	lx.prevWidths[2] = lx.prevWidths[1]
139
+	lx.prevWidths[1] = lx.prevWidths[0]
140
+	if lx.nprev < 3 {
141
+		lx.nprev++
142
+	}
143
+	r, w := utf8.DecodeRuneInString(lx.input[lx.pos:])
144
+	lx.prevWidths[0] = w
145
+	lx.pos += w
137 146
 	return r
138 147
 }
139 148
 
... ...
@@ -142,9 +163,20 @@ func (lx *lexer) ignore() {
142 142
 	lx.start = lx.pos
143 143
 }
144 144
 
145
-// backup steps back one rune. Can be called only once per call of next.
145
+// backup steps back one rune. Can be called only twice between calls to next.
146 146
 func (lx *lexer) backup() {
147
-	lx.pos -= lx.width
147
+	if lx.atEOF {
148
+		lx.atEOF = false
149
+		return
150
+	}
151
+	if lx.nprev < 1 {
152
+		panic("backed up too far")
153
+	}
154
+	w := lx.prevWidths[0]
155
+	lx.prevWidths[0] = lx.prevWidths[1]
156
+	lx.prevWidths[1] = lx.prevWidths[2]
157
+	lx.nprev--
158
+	lx.pos -= w
148 159
 	if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' {
149 160
 		lx.line--
150 161
 	}
... ...
@@ -166,9 +198,22 @@ func (lx *lexer) peek() rune {
166 166
 	return r
167 167
 }
168 168
 
169
+// skip ignores all input that matches the given predicate.
170
+func (lx *lexer) skip(pred func(rune) bool) {
171
+	for {
172
+		r := lx.next()
173
+		if pred(r) {
174
+			continue
175
+		}
176
+		lx.backup()
177
+		lx.ignore()
178
+		return
179
+	}
180
+}
181
+
169 182
 // errorf stops all lexing by emitting an error and returning `nil`.
170 183
 // Note that any value that is a character is escaped if it's a special
171
-// character (new lines, tabs, etc.).
184
+// character (newlines, tabs, etc.).
172 185
 func (lx *lexer) errorf(format string, values ...interface{}) stateFn {
173 186
 	lx.items <- item{
174 187
 		itemError,
... ...
@@ -184,7 +229,6 @@ func lexTop(lx *lexer) stateFn {
184 184
 	if isWhitespace(r) || isNL(r) {
185 185
 		return lexSkip(lx, lexTop)
186 186
 	}
187
-
188 187
 	switch r {
189 188
 	case commentStart:
190 189
 		lx.push(lexTop)
... ...
@@ -193,7 +237,7 @@ func lexTop(lx *lexer) stateFn {
193 193
 		return lexTableStart
194 194
 	case eof:
195 195
 		if lx.pos > lx.start {
196
-			return lx.errorf("Unexpected EOF.")
196
+			return lx.errorf("unexpected EOF")
197 197
 		}
198 198
 		lx.emit(itemEOF)
199 199
 		return nil
... ...
@@ -208,12 +252,12 @@ func lexTop(lx *lexer) stateFn {
208 208
 
209 209
 // lexTopEnd is entered whenever a top-level item has been consumed. (A value
210 210
 // or a table.) It must see only whitespace, and will turn back to lexTop
211
-// upon a new line. If it sees EOF, it will quit the lexer successfully.
211
+// upon a newline. If it sees EOF, it will quit the lexer successfully.
212 212
 func lexTopEnd(lx *lexer) stateFn {
213 213
 	r := lx.next()
214 214
 	switch {
215 215
 	case r == commentStart:
216
-		// a comment will read to a new line for us.
216
+		// a comment will read to a newline for us.
217 217
 		lx.push(lexTop)
218 218
 		return lexCommentStart
219 219
 	case isWhitespace(r):
... ...
@@ -222,11 +266,11 @@ func lexTopEnd(lx *lexer) stateFn {
222 222
 		lx.ignore()
223 223
 		return lexTop
224 224
 	case r == eof:
225
-		lx.ignore()
226
-		return lexTop
225
+		lx.emit(itemEOF)
226
+		return nil
227 227
 	}
228
-	return lx.errorf("Expected a top-level item to end with a new line, "+
229
-		"comment or EOF, but got %q instead.", r)
228
+	return lx.errorf("expected a top-level item to end with a newline, "+
229
+		"comment, or EOF, but got %q instead", r)
230 230
 }
231 231
 
232 232
 // lexTable lexes the beginning of a table. Namely, it makes sure that
... ...
@@ -253,50 +297,47 @@ func lexTableEnd(lx *lexer) stateFn {
253 253
 
254 254
 func lexArrayTableEnd(lx *lexer) stateFn {
255 255
 	if r := lx.next(); r != arrayTableEnd {
256
-		return lx.errorf("Expected end of table array name delimiter %q, "+
257
-			"but got %q instead.", arrayTableEnd, r)
256
+		return lx.errorf("expected end of table array name delimiter %q, "+
257
+			"but got %q instead", arrayTableEnd, r)
258 258
 	}
259 259
 	lx.emit(itemArrayTableEnd)
260 260
 	return lexTopEnd
261 261
 }
262 262
 
263 263
 func lexTableNameStart(lx *lexer) stateFn {
264
+	lx.skip(isWhitespace)
264 265
 	switch r := lx.peek(); {
265 266
 	case r == tableEnd || r == eof:
266
-		return lx.errorf("Unexpected end of table name. (Table names cannot " +
267
-			"be empty.)")
267
+		return lx.errorf("unexpected end of table name " +
268
+			"(table names cannot be empty)")
268 269
 	case r == tableSep:
269
-		return lx.errorf("Unexpected table separator. (Table names cannot " +
270
-			"be empty.)")
270
+		return lx.errorf("unexpected table separator " +
271
+			"(table names cannot be empty)")
271 272
 	case r == stringStart || r == rawStringStart:
272 273
 		lx.ignore()
273 274
 		lx.push(lexTableNameEnd)
274 275
 		return lexValue // reuse string lexing
275
-	case isWhitespace(r):
276
-		return lexTableNameStart
277 276
 	default:
278 277
 		return lexBareTableName
279 278
 	}
280 279
 }
281 280
 
282
-// lexTableName lexes the name of a table. It assumes that at least one
281
+// lexBareTableName lexes the name of a table. It assumes that at least one
283 282
 // valid character for the table has already been read.
284 283
 func lexBareTableName(lx *lexer) stateFn {
285
-	switch r := lx.next(); {
286
-	case isBareKeyChar(r):
284
+	r := lx.next()
285
+	if isBareKeyChar(r) {
287 286
 		return lexBareTableName
288
-	case r == tableSep || r == tableEnd:
289
-		lx.backup()
290
-		lx.emitTrim(itemText)
291
-		return lexTableNameEnd
292
-	default:
293
-		return lx.errorf("Bare keys cannot contain %q.", r)
294 287
 	}
288
+	lx.backup()
289
+	lx.emit(itemText)
290
+	return lexTableNameEnd
295 291
 }
296 292
 
297 293
 // lexTableNameEnd reads the end of a piece of a table name, optionally
298 294
 // consuming whitespace.
299 295
 func lexTableNameEnd(lx *lexer) stateFn {
296
+	lx.skip(isWhitespace)
300 297
 	switch r := lx.next(); {
301 298
 	case isWhitespace(r):
302 299
 		return lexTableNameEnd
... ...
@@ -306,8 +347,8 @@ func lexTableNameEnd(lx *lexer) stateFn {
306 306
 	case r == tableEnd:
307 307
 		return lx.pop()
308 308
 	default:
309
-		return lx.errorf("Expected '.' or ']' to end table name, but got %q "+
310
-			"instead.", r)
309
+		return lx.errorf("expected '.' or ']' to end table name, "+
310
+			"but got %q instead", r)
311 311
 	}
312 312
 }
313 313
 
... ...
@@ -317,7 +358,7 @@ func lexKeyStart(lx *lexer) stateFn {
317 317
 	r := lx.peek()
318 318
 	switch {
319 319
 	case r == keySep:
320
-		return lx.errorf("Unexpected key separator %q.", keySep)
320
+		return lx.errorf("unexpected key separator %q", keySep)
321 321
 	case isWhitespace(r) || isNL(r):
322 322
 		lx.next()
323 323
 		return lexSkip(lx, lexKeyStart)
... ...
@@ -340,14 +381,15 @@ func lexBareKey(lx *lexer) stateFn {
340 340
 	case isBareKeyChar(r):
341 341
 		return lexBareKey
342 342
 	case isWhitespace(r):
343
-		lx.emitTrim(itemText)
343
+		lx.backup()
344
+		lx.emit(itemText)
344 345
 		return lexKeyEnd
345 346
 	case r == keySep:
346 347
 		lx.backup()
347
-		lx.emitTrim(itemText)
348
+		lx.emit(itemText)
348 349
 		return lexKeyEnd
349 350
 	default:
350
-		return lx.errorf("Bare keys cannot contain %q.", r)
351
+		return lx.errorf("bare keys cannot contain %q", r)
351 352
 	}
352 353
 }
353 354
 
... ...
@@ -360,7 +402,7 @@ func lexKeyEnd(lx *lexer) stateFn {
360 360
 	case isWhitespace(r):
361 361
 		return lexSkip(lx, lexKeyEnd)
362 362
 	default:
363
-		return lx.errorf("Expected key separator %q, but got %q instead.",
363
+		return lx.errorf("expected key separator %q, but got %q instead",
364 364
 			keySep, r)
365 365
 	}
366 366
 }
... ...
@@ -369,20 +411,26 @@ func lexKeyEnd(lx *lexer) stateFn {
369 369
 // lexValue will ignore whitespace.
370 370
 // After a value is lexed, the last state on the next is popped and returned.
371 371
 func lexValue(lx *lexer) stateFn {
372
-	// We allow whitespace to precede a value, but NOT new lines.
373
-	// In array syntax, the array states are responsible for ignoring new
374
-	// lines.
372
+	// We allow whitespace to precede a value, but NOT newlines.
373
+	// In array syntax, the array states are responsible for ignoring newlines.
375 374
 	r := lx.next()
376
-	if isWhitespace(r) {
375
+	switch {
376
+	case isWhitespace(r):
377 377
 		return lexSkip(lx, lexValue)
378
+	case isDigit(r):
379
+		lx.backup() // avoid an extra state and use the same as above
380
+		return lexNumberOrDateStart
378 381
 	}
379
-
380
-	switch {
381
-	case r == arrayStart:
382
+	switch r {
383
+	case arrayStart:
382 384
 		lx.ignore()
383 385
 		lx.emit(itemArray)
384 386
 		return lexArrayValue
385
-	case r == stringStart:
387
+	case inlineTableStart:
388
+		lx.ignore()
389
+		lx.emit(itemInlineTableStart)
390
+		return lexInlineTableValue
391
+	case stringStart:
386 392
 		if lx.accept(stringStart) {
387 393
 			if lx.accept(stringStart) {
388 394
 				lx.ignore() // Ignore """
... ...
@@ -392,7 +440,7 @@ func lexValue(lx *lexer) stateFn {
392 392
 		}
393 393
 		lx.ignore() // ignore the '"'
394 394
 		return lexString
395
-	case r == rawStringStart:
395
+	case rawStringStart:
396 396
 		if lx.accept(rawStringStart) {
397 397
 			if lx.accept(rawStringStart) {
398 398
 				lx.ignore() // Ignore """
... ...
@@ -402,23 +450,24 @@ func lexValue(lx *lexer) stateFn {
402 402
 		}
403 403
 		lx.ignore() // ignore the "'"
404 404
 		return lexRawString
405
-	case r == 't':
406
-		return lexTrue
407
-	case r == 'f':
408
-		return lexFalse
409
-	case r == '-':
405
+	case '+', '-':
410 406
 		return lexNumberStart
411
-	case isDigit(r):
412
-		lx.backup() // avoid an extra state and use the same as above
413
-		return lexNumberOrDateStart
414
-	case r == '.': // special error case, be kind to users
415
-		return lx.errorf("Floats must start with a digit, not '.'.")
407
+	case '.': // special error case, be kind to users
408
+		return lx.errorf("floats must start with a digit, not '.'")
409
+	}
410
+	if unicode.IsLetter(r) {
411
+		// Be permissive here; lexBool will give a nice error if the
412
+		// user wrote something like
413
+		//   x = foo
414
+		// (i.e. not 'true' or 'false' but is something else word-like.)
415
+		lx.backup()
416
+		return lexBool
416 417
 	}
417
-	return lx.errorf("Expected value but found %q instead.", r)
418
+	return lx.errorf("expected value but found %q instead", r)
418 419
 }
419 420
 
420 421
 // lexArrayValue consumes one value in an array. It assumes that '[' or ','
421
-// have already been consumed. All whitespace and new lines are ignored.
422
+// have already been consumed. All whitespace and newlines are ignored.
422 423
 func lexArrayValue(lx *lexer) stateFn {
423 424
 	r := lx.next()
424 425
 	switch {
... ...
@@ -427,10 +476,11 @@ func lexArrayValue(lx *lexer) stateFn {
427 427
 	case r == commentStart:
428 428
 		lx.push(lexArrayValue)
429 429
 		return lexCommentStart
430
-	case r == arrayValTerm:
431
-		return lx.errorf("Unexpected array value terminator %q.",
432
-			arrayValTerm)
430
+	case r == comma:
431
+		return lx.errorf("unexpected comma")
433 432
 	case r == arrayEnd:
433
+		// NOTE(caleb): The spec isn't clear about whether you can have
434
+		// a trailing comma or not, so we'll allow it.
434 435
 		return lexArrayEnd
435 436
 	}
436 437
 
... ...
@@ -439,8 +489,9 @@ func lexArrayValue(lx *lexer) stateFn {
439 439
 	return lexValue
440 440
 }
441 441
 
442
-// lexArrayValueEnd consumes the cruft between values of an array. Namely,
443
-// it ignores whitespace and expects either a ',' or a ']'.
442
+// lexArrayValueEnd consumes everything between the end of an array value and
443
+// the next value (or the end of the array): it ignores whitespace and newlines
444
+// and expects either a ',' or a ']'.
444 445
 func lexArrayValueEnd(lx *lexer) stateFn {
445 446
 	r := lx.next()
446 447
 	switch {
... ...
@@ -449,31 +500,88 @@ func lexArrayValueEnd(lx *lexer) stateFn {
449 449
 	case r == commentStart:
450 450
 		lx.push(lexArrayValueEnd)
451 451
 		return lexCommentStart
452
-	case r == arrayValTerm:
452
+	case r == comma:
453 453
 		lx.ignore()
454 454
 		return lexArrayValue // move on to the next value
455 455
 	case r == arrayEnd:
456 456
 		return lexArrayEnd
457 457
 	}
458
-	return lx.errorf("Expected an array value terminator %q or an array "+
459
-		"terminator %q, but got %q instead.", arrayValTerm, arrayEnd, r)
458
+	return lx.errorf(
459
+		"expected a comma or array terminator %q, but got %q instead",
460
+		arrayEnd, r,
461
+	)
460 462
 }
461 463
 
462
-// lexArrayEnd finishes the lexing of an array. It assumes that a ']' has
463
-// just been consumed.
464
+// lexArrayEnd finishes the lexing of an array.
465
+// It assumes that a ']' has just been consumed.
464 466
 func lexArrayEnd(lx *lexer) stateFn {
465 467
 	lx.ignore()
466 468
 	lx.emit(itemArrayEnd)
467 469
 	return lx.pop()
468 470
 }
469 471
 
472
+// lexInlineTableValue consumes one key/value pair in an inline table.
473
+// It assumes that '{' or ',' have already been consumed. Whitespace is ignored.
474
+func lexInlineTableValue(lx *lexer) stateFn {
475
+	r := lx.next()
476
+	switch {
477
+	case isWhitespace(r):
478
+		return lexSkip(lx, lexInlineTableValue)
479
+	case isNL(r):
480
+		return lx.errorf("newlines not allowed within inline tables")
481
+	case r == commentStart:
482
+		lx.push(lexInlineTableValue)
483
+		return lexCommentStart
484
+	case r == comma:
485
+		return lx.errorf("unexpected comma")
486
+	case r == inlineTableEnd:
487
+		return lexInlineTableEnd
488
+	}
489
+	lx.backup()
490
+	lx.push(lexInlineTableValueEnd)
491
+	return lexKeyStart
492
+}
493
+
494
+// lexInlineTableValueEnd consumes everything between the end of an inline table
495
+// key/value pair and the next pair (or the end of the table):
496
+// it ignores whitespace and expects either a ',' or a '}'.
497
+func lexInlineTableValueEnd(lx *lexer) stateFn {
498
+	r := lx.next()
499
+	switch {
500
+	case isWhitespace(r):
501
+		return lexSkip(lx, lexInlineTableValueEnd)
502
+	case isNL(r):
503
+		return lx.errorf("newlines not allowed within inline tables")
504
+	case r == commentStart:
505
+		lx.push(lexInlineTableValueEnd)
506
+		return lexCommentStart
507
+	case r == comma:
508
+		lx.ignore()
509
+		return lexInlineTableValue
510
+	case r == inlineTableEnd:
511
+		return lexInlineTableEnd
512
+	}
513
+	return lx.errorf("expected a comma or an inline table terminator %q, "+
514
+		"but got %q instead", inlineTableEnd, r)
515
+}
516
+
517
+// lexInlineTableEnd finishes the lexing of an inline table.
518
+// It assumes that a '}' has just been consumed.
519
+func lexInlineTableEnd(lx *lexer) stateFn {
520
+	lx.ignore()
521
+	lx.emit(itemInlineTableEnd)
522
+	return lx.pop()
523
+}
524
+
470 525
 // lexString consumes the inner contents of a string. It assumes that the
471 526
 // beginning '"' has already been consumed and ignored.
472 527
 func lexString(lx *lexer) stateFn {
473 528
 	r := lx.next()
474 529
 	switch {
530
+	case r == eof:
531
+		return lx.errorf("unexpected EOF")
475 532
 	case isNL(r):
476
-		return lx.errorf("Strings cannot contain new lines.")
533
+		return lx.errorf("strings cannot contain newlines")
477 534
 	case r == '\\':
478 535
 		lx.push(lexString)
479 536
 		return lexStringEscape
... ...
@@ -490,11 +598,12 @@ func lexString(lx *lexer) stateFn {
490 490
 // lexMultilineString consumes the inner contents of a string. It assumes that
491 491
 // the beginning '"""' has already been consumed and ignored.
492 492
 func lexMultilineString(lx *lexer) stateFn {
493
-	r := lx.next()
494
-	switch {
495
-	case r == '\\':
493
+	switch lx.next() {
494
+	case eof:
495
+		return lx.errorf("unexpected EOF")
496
+	case '\\':
496 497
 		return lexMultilineStringEscape
497
-	case r == stringEnd:
498
+	case stringEnd:
498 499
 		if lx.accept(stringEnd) {
499 500
 			if lx.accept(stringEnd) {
500 501
 				lx.backup()
... ...
@@ -518,8 +627,10 @@ func lexMultilineString(lx *lexer) stateFn {
518 518
 func lexRawString(lx *lexer) stateFn {
519 519
 	r := lx.next()
520 520
 	switch {
521
+	case r == eof:
522
+		return lx.errorf("unexpected EOF")
521 523
 	case isNL(r):
522
-		return lx.errorf("Strings cannot contain new lines.")
524
+		return lx.errorf("strings cannot contain newlines")
523 525
 	case r == rawStringEnd:
524 526
 		lx.backup()
525 527
 		lx.emit(itemRawString)
... ...
@@ -531,12 +642,13 @@ func lexRawString(lx *lexer) stateFn {
531 531
 }
532 532
 
533 533
 // lexMultilineRawString consumes a raw string. Nothing can be escaped in such
534
-// a string. It assumes that the beginning "'" has already been consumed and
534
+// a string. It assumes that the beginning "'''" has already been consumed and
535 535
 // ignored.
536 536
 func lexMultilineRawString(lx *lexer) stateFn {
537
-	r := lx.next()
538
-	switch {
539
-	case r == rawStringEnd:
537
+	switch lx.next() {
538
+	case eof:
539
+		return lx.errorf("unexpected EOF")
540
+	case rawStringEnd:
540 541
 		if lx.accept(rawStringEnd) {
541 542
 			if lx.accept(rawStringEnd) {
542 543
 				lx.backup()
... ...
@@ -560,13 +672,11 @@ func lexMultilineRawString(lx *lexer) stateFn {
560 560
 func lexMultilineStringEscape(lx *lexer) stateFn {
561 561
 	// Handle the special case first:
562 562
 	if isNL(lx.next()) {
563
-		lx.next()
564 563
 		return lexMultilineString
565
-	} else {
566
-		lx.backup()
567
-		lx.push(lexMultilineString)
568
-		return lexStringEscape(lx)
569 564
 	}
565
+	lx.backup()
566
+	lx.push(lexMultilineString)
567
+	return lexStringEscape(lx)
570 568
 }
571 569
 
572 570
 func lexStringEscape(lx *lexer) stateFn {
... ...
@@ -591,10 +701,9 @@ func lexStringEscape(lx *lexer) stateFn {
591 591
 	case 'U':
592 592
 		return lexLongUnicodeEscape
593 593
 	}
594
-	return lx.errorf("Invalid escape character %q. Only the following "+
594
+	return lx.errorf("invalid escape character %q; only the following "+
595 595
 		"escape characters are allowed: "+
596
-		"\\b, \\t, \\n, \\f, \\r, \\\", \\/, \\\\, "+
597
-		"\\uXXXX and \\UXXXXXXXX.", r)
596
+		`\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX`, r)
598 597
 }
599 598
 
600 599
 func lexShortUnicodeEscape(lx *lexer) stateFn {
... ...
@@ -602,8 +711,8 @@ func lexShortUnicodeEscape(lx *lexer) stateFn {
602 602
 	for i := 0; i < 4; i++ {
603 603
 		r = lx.next()
604 604
 		if !isHexadecimal(r) {
605
-			return lx.errorf("Expected four hexadecimal digits after '\\u', "+
606
-				"but got '%s' instead.", lx.current())
605
+			return lx.errorf(`expected four hexadecimal digits after '\u', `+
606
+				"but got %q instead", lx.current())
607 607
 		}
608 608
 	}
609 609
 	return lx.pop()
... ...
@@ -614,40 +723,43 @@ func lexLongUnicodeEscape(lx *lexer) stateFn {
614 614
 	for i := 0; i < 8; i++ {
615 615
 		r = lx.next()
616 616
 		if !isHexadecimal(r) {
617
-			return lx.errorf("Expected eight hexadecimal digits after '\\U', "+
618
-				"but got '%s' instead.", lx.current())
617
+			return lx.errorf(`expected eight hexadecimal digits after '\U', `+
618
+				"but got %q instead", lx.current())
619 619
 		}
620 620
 	}
621 621
 	return lx.pop()
622 622
 }
623 623
 
624
-// lexNumberOrDateStart consumes either a (positive) integer, float or
625
-// datetime. It assumes that NO negative sign has been consumed.
624
+// lexNumberOrDateStart consumes either an integer, a float, or datetime.
626 625
 func lexNumberOrDateStart(lx *lexer) stateFn {
627 626
 	r := lx.next()
628
-	if !isDigit(r) {
629
-		if r == '.' {
630
-			return lx.errorf("Floats must start with a digit, not '.'.")
631
-		} else {
632
-			return lx.errorf("Expected a digit but got %q.", r)
633
-		}
627
+	if isDigit(r) {
628
+		return lexNumberOrDate
629
+	}
630
+	switch r {
631
+	case '_':
632
+		return lexNumber
633
+	case 'e', 'E':
634
+		return lexFloat
635
+	case '.':
636
+		return lx.errorf("floats must start with a digit, not '.'")
634 637
 	}
635
-	return lexNumberOrDate
638
+	return lx.errorf("expected a digit but got %q", r)
636 639
 }
637 640
 
638
-// lexNumberOrDate consumes either a (positive) integer, float or datetime.
641
+// lexNumberOrDate consumes either an integer, float or datetime.
639 642
 func lexNumberOrDate(lx *lexer) stateFn {
640 643
 	r := lx.next()
641
-	switch {
642
-	case r == '-':
643
-		if lx.pos-lx.start != 5 {
644
-			return lx.errorf("All ISO8601 dates must be in full Zulu form.")
645
-		}
646
-		return lexDateAfterYear
647
-	case isDigit(r):
644
+	if isDigit(r) {
648 645
 		return lexNumberOrDate
649
-	case r == '.':
650
-		return lexFloatStart
646
+	}
647
+	switch r {
648
+	case '-':
649
+		return lexDatetime
650
+	case '_':
651
+		return lexNumber
652
+	case '.', 'e', 'E':
653
+		return lexFloat
651 654
 	}
652 655
 
653 656
 	lx.backup()
... ...
@@ -655,46 +767,34 @@ func lexNumberOrDate(lx *lexer) stateFn {
655 655
 	return lx.pop()
656 656
 }
657 657
 
658
-// lexDateAfterYear consumes a full Zulu Datetime in ISO8601 format.
659
-// It assumes that "YYYY-" has already been consumed.
660
-func lexDateAfterYear(lx *lexer) stateFn {
661
-	formats := []rune{
662
-		// digits are '0'.
663
-		// everything else is direct equality.
664
-		'0', '0', '-', '0', '0',
665
-		'T',
666
-		'0', '0', ':', '0', '0', ':', '0', '0',
667
-		'Z',
658
+// lexDatetime consumes a Datetime, to a first approximation.
659
+// The parser validates that it matches one of the accepted formats.
660
+func lexDatetime(lx *lexer) stateFn {
661
+	r := lx.next()
662
+	if isDigit(r) {
663
+		return lexDatetime
668 664
 	}
669
-	for _, f := range formats {
670
-		r := lx.next()
671
-		if f == '0' {
672
-			if !isDigit(r) {
673
-				return lx.errorf("Expected digit in ISO8601 datetime, "+
674
-					"but found %q instead.", r)
675
-			}
676
-		} else if f != r {
677
-			return lx.errorf("Expected %q in ISO8601 datetime, "+
678
-				"but found %q instead.", f, r)
679
-		}
665
+	switch r {
666
+	case '-', 'T', ':', '.', 'Z', '+':
667
+		return lexDatetime
680 668
 	}
669
+
670
+	lx.backup()
681 671
 	lx.emit(itemDatetime)
682 672
 	return lx.pop()
683 673
 }
684 674
 
685
-// lexNumberStart consumes either an integer or a float. It assumes that
686
-// a negative sign has already been read, but that *no* digits have been
687
-// consumed. lexNumberStart will move to the appropriate integer or float
688
-// states.
675
+// lexNumberStart consumes either an integer or a float. It assumes that a sign
676
+// has already been read, but that *no* digits have been consumed.
677
+// lexNumberStart will move to the appropriate integer or float states.
689 678
 func lexNumberStart(lx *lexer) stateFn {
690
-	// we MUST see a digit. Even floats have to start with a digit.
679
+	// We MUST see a digit. Even floats have to start with a digit.
691 680
 	r := lx.next()
692 681
 	if !isDigit(r) {
693 682
 		if r == '.' {
694
-			return lx.errorf("Floats must start with a digit, not '.'.")
695
-		} else {
696
-			return lx.errorf("Expected a digit but got %q.", r)
683
+			return lx.errorf("floats must start with a digit, not '.'")
697 684
 		}
685
+		return lx.errorf("expected a digit but got %q", r)
698 686
 	}
699 687
 	return lexNumber
700 688
 }
... ...
@@ -702,11 +802,14 @@ func lexNumberStart(lx *lexer) stateFn {
702 702
 // lexNumber consumes an integer or a float after seeing the first digit.
703 703
 func lexNumber(lx *lexer) stateFn {
704 704
 	r := lx.next()
705
-	switch {
706
-	case isDigit(r):
705
+	if isDigit(r) {
707 706
 		return lexNumber
708
-	case r == '.':
709
-		return lexFloatStart
707
+	}
708
+	switch r {
709
+	case '_':
710
+		return lexNumber
711
+	case '.', 'e', 'E':
712
+		return lexFloat
710 713
 	}
711 714
 
712 715
 	lx.backup()
... ...
@@ -714,60 +817,42 @@ func lexNumber(lx *lexer) stateFn {
714 714
 	return lx.pop()
715 715
 }
716 716
 
717
-// lexFloatStart starts the consumption of digits of a float after a '.'.
718
-// Namely, at least one digit is required.
719
-func lexFloatStart(lx *lexer) stateFn {
720
-	r := lx.next()
721
-	if !isDigit(r) {
722
-		return lx.errorf("Floats must have a digit after the '.', but got "+
723
-			"%q instead.", r)
724
-	}
725
-	return lexFloat
726
-}
727
-
728
-// lexFloat consumes the digits of a float after a '.'.
729
-// Assumes that one digit has been consumed after a '.' already.
717
+// lexFloat consumes the elements of a float. It allows any sequence of
718
+// float-like characters, so floats emitted by the lexer are only a first
719
+// approximation and must be validated by the parser.
730 720
 func lexFloat(lx *lexer) stateFn {
731 721
 	r := lx.next()
732 722
 	if isDigit(r) {
733 723
 		return lexFloat
734 724
 	}
725
+	switch r {
726
+	case '_', '.', '-', '+', 'e', 'E':
727
+		return lexFloat
728
+	}
735 729
 
736 730
 	lx.backup()
737 731
 	lx.emit(itemFloat)
738 732
 	return lx.pop()
739 733
 }
740 734
 
741
-// lexConst consumes the s[1:] in s. It assumes that s[0] has already been
742
-// consumed.
743
-func lexConst(lx *lexer, s string) stateFn {
744
-	for i := range s[1:] {
745
-		if r := lx.next(); r != rune(s[i+1]) {
746
-			return lx.errorf("Expected %q, but found %q instead.", s[:i+1],
747
-				s[:i]+string(r))
735
+// lexBool consumes a bool string: 'true' or 'false.
736
+func lexBool(lx *lexer) stateFn {
737
+	var rs []rune
738
+	for {
739
+		r := lx.next()
740
+		if !unicode.IsLetter(r) {
741
+			lx.backup()
742
+			break
748 743
 		}
744
+		rs = append(rs, r)
749 745
 	}
750
-	return nil
751
-}
752
-
753
-// lexTrue consumes the "rue" in "true". It assumes that 't' has already
754
-// been consumed.
755
-func lexTrue(lx *lexer) stateFn {
756
-	if fn := lexConst(lx, "true"); fn != nil {
757
-		return fn
758
-	}
759
-	lx.emit(itemBool)
760
-	return lx.pop()
761
-}
762
-
763
-// lexFalse consumes the "alse" in "false". It assumes that 'f' has already
764
-// been consumed.
765
-func lexFalse(lx *lexer) stateFn {
766
-	if fn := lexConst(lx, "false"); fn != nil {
767
-		return fn
746
+	s := string(rs)
747
+	switch s {
748
+	case "true", "false":
749
+		lx.emit(itemBool)
750
+		return lx.pop()
768 751
 	}
769
-	lx.emit(itemBool)
770
-	return lx.pop()
752
+	return lx.errorf("expected value but found %q instead", s)
771 753
 }
772 754
 
773 755
 // lexCommentStart begins the lexing of a comment. It will emit
... ...
@@ -779,7 +864,7 @@ func lexCommentStart(lx *lexer) stateFn {
779 779
 }
780 780
 
781 781
 // lexComment lexes an entire comment. It assumes that '#' has been consumed.
782
-// It will consume *up to* the first new line character, and pass control
782
+// It will consume *up to* the first newline character, and pass control
783 783
 // back to the last state on the stack.
784 784
 func lexComment(lx *lexer) stateFn {
785 785
 	r := lx.peek()
... ...
@@ -837,13 +922,7 @@ func (itype itemType) String() string {
837 837
 		return "EOF"
838 838
 	case itemText:
839 839
 		return "Text"
840
-	case itemString:
841
-		return "String"
842
-	case itemRawString:
843
-		return "String"
844
-	case itemMultilineString:
845
-		return "String"
846
-	case itemRawMultilineString:
840
+	case itemString, itemRawString, itemMultilineString, itemRawMultilineString:
847 841
 		return "String"
848 842
 	case itemBool:
849 843
 		return "Bool"
... ...
@@ -2,7 +2,6 @@ package toml
2 2
 
3 3
 import (
4 4
 	"fmt"
5
-	"log"
6 5
 	"strconv"
7 6
 	"strings"
8 7
 	"time"
... ...
@@ -81,7 +80,7 @@ func (p *parser) next() item {
81 81
 }
82 82
 
83 83
 func (p *parser) bug(format string, v ...interface{}) {
84
-	log.Fatalf("BUG: %s\n\n", fmt.Sprintf(format, v...))
84
+	panic(fmt.Sprintf("BUG: "+format+"\n\n", v...))
85 85
 }
86 86
 
87 87
 func (p *parser) expect(typ itemType) item {
... ...
@@ -179,10 +178,18 @@ func (p *parser) value(it item) (interface{}, tomlType) {
179 179
 		}
180 180
 		p.bug("Expected boolean value, but got '%s'.", it.val)
181 181
 	case itemInteger:
182
-		num, err := strconv.ParseInt(it.val, 10, 64)
182
+		if !numUnderscoresOK(it.val) {
183
+			p.panicf("Invalid integer %q: underscores must be surrounded by digits",
184
+				it.val)
185
+		}
186
+		val := strings.Replace(it.val, "_", "", -1)
187
+		num, err := strconv.ParseInt(val, 10, 64)
183 188
 		if err != nil {
184
-			// See comment below for floats describing why we make a
185
-			// distinction between a bug and a user error.
189
+			// Distinguish integer values. Normally, it'd be a bug if the lexer
190
+			// provides an invalid integer, but it's possible that the number is
191
+			// out of range of valid values (which the lexer cannot determine).
192
+			// So mark the former as a bug but the latter as a legitimate user
193
+			// error.
186 194
 			if e, ok := err.(*strconv.NumError); ok &&
187 195
 				e.Err == strconv.ErrRange {
188 196
 
... ...
@@ -194,29 +201,57 @@ func (p *parser) value(it item) (interface{}, tomlType) {
194 194
 		}
195 195
 		return num, p.typeOfPrimitive(it)
196 196
 	case itemFloat:
197
-		num, err := strconv.ParseFloat(it.val, 64)
197
+		parts := strings.FieldsFunc(it.val, func(r rune) bool {
198
+			switch r {
199
+			case '.', 'e', 'E':
200
+				return true
201
+			}
202
+			return false
203
+		})
204
+		for _, part := range parts {
205
+			if !numUnderscoresOK(part) {
206
+				p.panicf("Invalid float %q: underscores must be "+
207
+					"surrounded by digits", it.val)
208
+			}
209
+		}
210
+		if !numPeriodsOK(it.val) {
211
+			// As a special case, numbers like '123.' or '1.e2',
212
+			// which are valid as far as Go/strconv are concerned,
213
+			// must be rejected because TOML says that a fractional
214
+			// part consists of '.' followed by 1+ digits.
215
+			p.panicf("Invalid float %q: '.' must be followed "+
216
+				"by one or more digits", it.val)
217
+		}
218
+		val := strings.Replace(it.val, "_", "", -1)
219
+		num, err := strconv.ParseFloat(val, 64)
198 220
 		if err != nil {
199
-			// Distinguish float values. Normally, it'd be a bug if the lexer
200
-			// provides an invalid float, but it's possible that the float is
201
-			// out of range of valid values (which the lexer cannot determine).
202
-			// So mark the former as a bug but the latter as a legitimate user
203
-			// error.
204
-			//
205
-			// This is also true for integers.
206 221
 			if e, ok := err.(*strconv.NumError); ok &&
207 222
 				e.Err == strconv.ErrRange {
208 223
 
209 224
 				p.panicf("Float '%s' is out of the range of 64-bit "+
210 225
 					"IEEE-754 floating-point numbers.", it.val)
211 226
 			} else {
212
-				p.bug("Expected float value, but got '%s'.", it.val)
227
+				p.panicf("Invalid float value: %q", it.val)
213 228
 			}
214 229
 		}
215 230
 		return num, p.typeOfPrimitive(it)
216 231
 	case itemDatetime:
217
-		t, err := time.Parse("2006-01-02T15:04:05Z", it.val)
218
-		if err != nil {
219
-			p.bug("Expected Zulu formatted DateTime, but got '%s'.", it.val)
232
+		var t time.Time
233
+		var ok bool
234
+		var err error
235
+		for _, format := range []string{
236
+			"2006-01-02T15:04:05Z07:00",
237
+			"2006-01-02T15:04:05",
238
+			"2006-01-02",
239
+		} {
240
+			t, err = time.ParseInLocation(format, it.val, time.Local)
241
+			if err == nil {
242
+				ok = true
243
+				break
244
+			}
245
+		}
246
+		if !ok {
247
+			p.panicf("Invalid TOML Datetime: %q.", it.val)
220 248
 		}
221 249
 		return t, p.typeOfPrimitive(it)
222 250
 	case itemArray:
... ...
@@ -234,11 +269,75 @@ func (p *parser) value(it item) (interface{}, tomlType) {
234 234
 			types = append(types, typ)
235 235
 		}
236 236
 		return array, p.typeOfArray(types)
237
+	case itemInlineTableStart:
238
+		var (
239
+			hash         = make(map[string]interface{})
240
+			outerContext = p.context
241
+			outerKey     = p.currentKey
242
+		)
243
+
244
+		p.context = append(p.context, p.currentKey)
245
+		p.currentKey = ""
246
+		for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() {
247
+			if it.typ != itemKeyStart {
248
+				p.bug("Expected key start but instead found %q, around line %d",
249
+					it.val, p.approxLine)
250
+			}
251
+			if it.typ == itemCommentStart {
252
+				p.expect(itemText)
253
+				continue
254
+			}
255
+
256
+			// retrieve key
257
+			k := p.next()
258
+			p.approxLine = k.line
259
+			kname := p.keyString(k)
260
+
261
+			// retrieve value
262
+			p.currentKey = kname
263
+			val, typ := p.value(p.next())
264
+			// make sure we keep metadata up to date
265
+			p.setType(kname, typ)
266
+			p.ordered = append(p.ordered, p.context.add(p.currentKey))
267
+			hash[kname] = val
268
+		}
269
+		p.context = outerContext
270
+		p.currentKey = outerKey
271
+		return hash, tomlHash
237 272
 	}
238 273
 	p.bug("Unexpected value type: %s", it.typ)
239 274
 	panic("unreachable")
240 275
 }
241 276
 
277
+// numUnderscoresOK checks whether each underscore in s is surrounded by
278
+// characters that are not underscores.
279
+func numUnderscoresOK(s string) bool {
280
+	accept := false
281
+	for _, r := range s {
282
+		if r == '_' {
283
+			if !accept {
284
+				return false
285
+			}
286
+			accept = false
287
+			continue
288
+		}
289
+		accept = true
290
+	}
291
+	return accept
292
+}
293
+
294
+// numPeriodsOK checks whether every period in s is followed by a digit.
295
+func numPeriodsOK(s string) bool {
296
+	period := false
297
+	for _, r := range s {
298
+		if period && !isDigit(r) {
299
+			return false
300
+		}
301
+		period = r == '.'
302
+	}
303
+	return !period
304
+}
305
+
242 306
 // establishContext sets the current context of the parser,
243 307
 // where the context is either a hash or an array of hashes. Which one is
244 308
 // set depends on the value of the `array` parameter.
... ...
@@ -401,7 +500,7 @@ func stripFirstNewline(s string) string {
401 401
 	if len(s) == 0 || s[0] != '\n' {
402 402
 		return s
403 403
 	}
404
-	return s[1:len(s)]
404
+	return s[1:]
405 405
 }
406 406
 
407 407
 func stripEscapedWhitespace(s string) string {
... ...
@@ -481,12 +580,7 @@ func (p *parser) asciiEscapeToUnicode(bs []byte) rune {
481 481
 		p.bug("Could not parse '%s' as a hexadecimal number, but the "+
482 482
 			"lexer claims it's OK: %s", s, err)
483 483
 	}
484
-
485
-	// BUG(burntsushi)
486
-	// I honestly don't understand how this works. I can't seem
487
-	// to find a way to make this fail. I figured this would fail on invalid
488
-	// UTF-8 characters like U+DCFF, but it doesn't.
489
-	if !utf8.ValidString(string(rune(hex))) {
484
+	if !utf8.ValidRune(rune(hex)) {
490 485
 		p.panicf("Escaped character '\\u%s' is not valid UTF-8.", s)
491 486
 	}
492 487
 	return rune(hex)
... ...
@@ -92,11 +92,11 @@ func typeFields(t reflect.Type) []field {
92 92
 			// Scan f.typ for fields to include.
93 93
 			for i := 0; i < f.typ.NumField(); i++ {
94 94
 				sf := f.typ.Field(i)
95
-				if sf.PkgPath != "" { // unexported
95
+				if sf.PkgPath != "" && !sf.Anonymous { // unexported
96 96
 					continue
97 97
 				}
98
-				name := sf.Tag.Get("toml")
99
-				if name == "-" {
98
+				opts := getOptions(sf.Tag)
99
+				if opts.skip {
100 100
 					continue
101 101
 				}
102 102
 				index := make([]int, len(f.index)+1)
... ...
@@ -110,8 +110,9 @@ func typeFields(t reflect.Type) []field {
110 110
 				}
111 111
 
112 112
 				// Record found field and index sequence.
113
-				if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
114
-					tagged := name != ""
113
+				if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
114
+					tagged := opts.name != ""
115
+					name := opts.name
115 116
 					if name == "" {
116 117
 						name = sf.Name
117 118
 					}