14 mapping map[string]interface{}
15 types map[string]tomlType
18 // A list of keys in the order that they appear in the TOML data.
21 // the full key for the current hash in scope
24 // the base key name for everything except hashes
27 // rough approximation of line number
30 // A map of 'key.group.names' to whether they were created implicitly.
31 implicits map[string]bool
34 type parseError string
36 func (pe parseError) Error() string {
40 func parse(data string) (p *parser, err error) {
42 if r := recover(); r != nil {
44 if err, ok = r.(parseError); ok {
52 mapping: make(map[string]interface{}),
53 types: make(map[string]tomlType),
55 ordered: make([]Key, 0),
56 implicits: make(map[string]bool),
60 if item.typ == itemEOF {
69 func (p *parser) panicf(format string, v ...interface{}) {
70 msg := fmt.Sprintf("Near line %d (last key parsed '%s'): %s",
71 p.approxLine, p.current(), fmt.Sprintf(format, v...))
72 panic(parseError(msg))
75 func (p *parser) next() item {
77 if it.typ == itemError {
78 p.panicf("%s", it.val)
83 func (p *parser) bug(format string, v ...interface{}) {
84 log.Fatalf("BUG: %s\n\n", fmt.Sprintf(format, v...))
87 func (p *parser) expect(typ itemType) item {
89 p.assertEqual(typ, it.typ)
93 func (p *parser) assertEqual(expected, got itemType) {
95 p.bug("Expected '%s' but got '%s'.", expected, got)
99 func (p *parser) topLevel(item item) {
101 case itemCommentStart:
102 p.approxLine = item.line
106 p.approxLine = kg.line
109 for ; kg.typ != itemTableEnd && kg.typ != itemEOF; kg = p.next() {
110 key = append(key, p.keyString(kg))
112 p.assertEqual(itemTableEnd, kg.typ)
114 p.establishContext(key, false)
115 p.setType("", tomlHash)
116 p.ordered = append(p.ordered, key)
117 case itemArrayTableStart:
119 p.approxLine = kg.line
122 for ; kg.typ != itemArrayTableEnd && kg.typ != itemEOF; kg = p.next() {
123 key = append(key, p.keyString(kg))
125 p.assertEqual(itemArrayTableEnd, kg.typ)
127 p.establishContext(key, true)
128 p.setType("", tomlArrayHash)
129 p.ordered = append(p.ordered, key)
132 p.approxLine = kname.line
133 p.currentKey = p.keyString(kname)
135 val, typ := p.value(p.next())
136 p.setValue(p.currentKey, val)
137 p.setType(p.currentKey, typ)
138 p.ordered = append(p.ordered, p.context.add(p.currentKey))
141 p.bug("Unexpected type at top level: %s", item.typ)
145 // Gets a string for a key (or part of a key in a table name).
146 func (p *parser) keyString(it item) string {
150 case itemString, itemMultilineString,
151 itemRawString, itemRawMultilineString:
155 p.bug("Unexpected key type: %s", it.typ)
160 // value translates an expected value from the lexer into a Go value wrapped
161 // as an empty interface.
162 func (p *parser) value(it item) (interface{}, tomlType) {
165 return p.replaceEscapes(it.val), p.typeOfPrimitive(it)
166 case itemMultilineString:
167 trimmed := stripFirstNewline(stripEscapedWhitespace(it.val))
168 return p.replaceEscapes(trimmed), p.typeOfPrimitive(it)
170 return it.val, p.typeOfPrimitive(it)
171 case itemRawMultilineString:
172 return stripFirstNewline(it.val), p.typeOfPrimitive(it)
176 return true, p.typeOfPrimitive(it)
178 return false, p.typeOfPrimitive(it)
180 p.bug("Expected boolean value, but got '%s'.", it.val)
182 num, err := strconv.ParseInt(it.val, 10, 64)
184 // See comment below for floats describing why we make a
185 // distinction between a bug and a user error.
186 if e, ok := err.(*strconv.NumError); ok &&
187 e.Err == strconv.ErrRange {
189 p.panicf("Integer '%s' is out of the range of 64-bit "+
190 "signed integers.", it.val)
192 p.bug("Expected integer value, but got '%s'.", it.val)
195 return num, p.typeOfPrimitive(it)
197 num, err := strconv.ParseFloat(it.val, 64)
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
205 // This is also true for integers.
206 if e, ok := err.(*strconv.NumError); ok &&
207 e.Err == strconv.ErrRange {
209 p.panicf("Float '%s' is out of the range of 64-bit "+
210 "IEEE-754 floating-point numbers.", it.val)
212 p.bug("Expected float value, but got '%s'.", it.val)
215 return num, p.typeOfPrimitive(it)
217 t, err := time.Parse("2006-01-02T15:04:05Z", it.val)
219 p.bug("Expected Zulu formatted DateTime, but got '%s'.", it.val)
221 return t, p.typeOfPrimitive(it)
223 array := make([]interface{}, 0)
224 types := make([]tomlType, 0)
226 for it = p.next(); it.typ != itemArrayEnd; it = p.next() {
227 if it.typ == itemCommentStart {
232 val, typ := p.value(it)
233 array = append(array, val)
234 types = append(types, typ)
236 return array, p.typeOfArray(types)
238 p.bug("Unexpected value type: %s", it.typ)
242 // establishContext sets the current context of the parser,
243 // where the context is either a hash or an array of hashes. Which one is
244 // set depends on the value of the `array` parameter.
246 // Establishing the context also makes sure that the key isn't a duplicate, and
247 // will create implicit hashes automatically.
248 func (p *parser) establishContext(key Key, array bool) {
251 // Always start at the top level and drill down for our context.
252 hashContext := p.mapping
253 keyContext := make(Key, 0)
255 // We only need implicit hashes for key[0:-1]
256 for _, k := range key[0 : len(key)-1] {
257 _, ok = hashContext[k]
258 keyContext = append(keyContext, k)
260 // No key? Make an implicit hash and move on.
262 p.addImplicit(keyContext)
263 hashContext[k] = make(map[string]interface{})
266 // If the hash context is actually an array of tables, then set
267 // the hash context to the last element in that array.
269 // Otherwise, it better be a table, since this MUST be a key group (by
270 // virtue of it not being the last element in a key).
271 switch t := hashContext[k].(type) {
272 case []map[string]interface{}:
273 hashContext = t[len(t)-1]
274 case map[string]interface{}:
277 p.panicf("Key '%s' was already created as a hash.", keyContext)
281 p.context = keyContext
283 // If this is the first element for this array, then allocate a new
284 // list of tables for it.
286 if _, ok := hashContext[k]; !ok {
287 hashContext[k] = make([]map[string]interface{}, 0, 5)
290 // Add a new table. But make sure the key hasn't already been used
291 // for something else.
292 if hash, ok := hashContext[k].([]map[string]interface{}); ok {
293 hashContext[k] = append(hash, make(map[string]interface{}))
295 p.panicf("Key '%s' was already created and cannot be used as "+
296 "an array.", keyContext)
299 p.setValue(key[len(key)-1], make(map[string]interface{}))
301 p.context = append(p.context, key[len(key)-1])
304 // setValue sets the given key to the given value in the current context.
305 // It will make sure that the key hasn't already been defined, account for
306 // implicit key groups.
307 func (p *parser) setValue(key string, value interface{}) {
308 var tmpHash interface{}
312 keyContext := make(Key, 0)
313 for _, k := range p.context {
314 keyContext = append(keyContext, k)
315 if tmpHash, ok = hash[k]; !ok {
316 p.bug("Context for key '%s' has not been established.", keyContext)
318 switch t := tmpHash.(type) {
319 case []map[string]interface{}:
320 // The context is a table of hashes. Pick the most recent table
321 // defined as the current hash.
323 case map[string]interface{}:
326 p.bug("Expected hash to have type 'map[string]interface{}', but "+
327 "it has '%T' instead.", tmpHash)
330 keyContext = append(keyContext, key)
332 if _, ok := hash[key]; ok {
333 // Typically, if the given key has already been set, then we have
334 // to raise an error since duplicate keys are disallowed. However,
335 // it's possible that a key was previously defined implicitly. In this
336 // case, it is allowed to be redefined concretely. (See the
337 // `tests/valid/implicit-and-explicit-after.toml` test in `toml-test`.)
339 // But we have to make sure to stop marking it as an implicit. (So that
340 // another redefinition provokes an error.)
342 // Note that since it has already been defined (as a hash), we don't
343 // want to overwrite it. So our business is done.
344 if p.isImplicit(keyContext) {
345 p.removeImplicit(keyContext)
349 // Otherwise, we have a concrete key trying to override a previous
350 // key, which is *always* wrong.
351 p.panicf("Key '%s' has already been defined.", keyContext)
356 // setType sets the type of a particular value at a given key.
357 // It should be called immediately AFTER setValue.
359 // Note that if `key` is empty, then the type given will be applied to the
360 // current context (which is either a table or an array of tables).
361 func (p *parser) setType(key string, typ tomlType) {
362 keyContext := make(Key, 0, len(p.context)+1)
363 for _, k := range p.context {
364 keyContext = append(keyContext, k)
366 if len(key) > 0 { // allow type setting for hashes
367 keyContext = append(keyContext, key)
369 p.types[keyContext.String()] = typ
372 // addImplicit sets the given Key as having been created implicitly.
373 func (p *parser) addImplicit(key Key) {
374 p.implicits[key.String()] = true
377 // removeImplicit stops tagging the given key as having been implicitly
379 func (p *parser) removeImplicit(key Key) {
380 p.implicits[key.String()] = false
383 // isImplicit returns true if the key group pointed to by the key was created
385 func (p *parser) isImplicit(key Key) bool {
386 return p.implicits[key.String()]
389 // current returns the full key name of the current context.
390 func (p *parser) current() string {
391 if len(p.currentKey) == 0 {
392 return p.context.String()
394 if len(p.context) == 0 {
397 return fmt.Sprintf("%s.%s", p.context, p.currentKey)
400 func stripFirstNewline(s string) string {
401 if len(s) == 0 || s[0] != '\n' {
407 func stripEscapedWhitespace(s string) string {
408 esc := strings.Split(s, "\\\n")
410 for i := 1; i < len(esc); i++ {
411 esc[i] = strings.TrimLeftFunc(esc[i], unicode.IsSpace)
414 return strings.Join(esc, "")
417 func (p *parser) replaceEscapes(str string) string {
423 c, size := utf8.DecodeRune(s[r:])
425 replaced = append(replaced, c)
430 p.bug("Escape sequence at end of string.")
435 p.bug("Expected valid escape code after \\, but got %q.", s[r])
438 replaced = append(replaced, rune(0x0008))
441 replaced = append(replaced, rune(0x0009))
444 replaced = append(replaced, rune(0x000A))
447 replaced = append(replaced, rune(0x000C))
450 replaced = append(replaced, rune(0x000D))
453 replaced = append(replaced, rune(0x0022))
456 replaced = append(replaced, rune(0x005C))
459 // At this point, we know we have a Unicode escape of the form
460 // `uXXXX` at [r, r+5). (Because the lexer guarantees this
462 escaped := p.asciiEscapeToUnicode(s[r+1 : r+5])
463 replaced = append(replaced, escaped)
466 // At this point, we know we have a Unicode escape of the form
467 // `uXXXX` at [r, r+9). (Because the lexer guarantees this
469 escaped := p.asciiEscapeToUnicode(s[r+1 : r+9])
470 replaced = append(replaced, escaped)
474 return string(replaced)
477 func (p *parser) asciiEscapeToUnicode(bs []byte) rune {
479 hex, err := strconv.ParseUint(strings.ToLower(s), 16, 32)
481 p.bug("Could not parse '%s' as a hexadecimal number, but the "+
482 "lexer claims it's OK: %s", s, err)
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))) {
490 p.panicf("Escaped character '\\u%s' is not valid UTF-8.", s)
495 func isStringType(ty itemType) bool {
496 return ty == itemString || ty == itemMultilineString ||
497 ty == itemRawString || ty == itemRawMultilineString