taldir

Directory service to resolve wallet mailboxes by messenger addresses
Log | Files | Refs | Submodules | README | LICENSE

parse.go (22213B)


      1 package toml
      2 
      3 import (
      4 	"fmt"
      5 	"math"
      6 	"strconv"
      7 	"strings"
      8 	"time"
      9 	"unicode/utf8"
     10 
     11 	"github.com/BurntSushi/toml/internal"
     12 )
     13 
     14 type parser struct {
     15 	lx         *lexer
     16 	context    Key      // Full key for the current hash in scope.
     17 	currentKey string   // Base key name for everything except hashes.
     18 	pos        Position // Current position in the TOML file.
     19 
     20 	ordered []Key // List of keys in the order that they appear in the TOML data.
     21 
     22 	keyInfo   map[string]keyInfo  // Map keyname → info about the TOML key.
     23 	mapping   map[string]any      // Map keyname → key value.
     24 	implicits map[string]struct{} // Record implicit keys (e.g. "key.group.names").
     25 }
     26 
     27 type keyInfo struct {
     28 	pos      Position
     29 	tomlType tomlType
     30 }
     31 
     32 func parse(data string) (p *parser, err error) {
     33 	defer func() {
     34 		if r := recover(); r != nil {
     35 			if pErr, ok := r.(ParseError); ok {
     36 				pErr.input = data
     37 				err = pErr
     38 				return
     39 			}
     40 			panic(r)
     41 		}
     42 	}()
     43 
     44 	// Read over BOM; do this here as the lexer calls utf8.DecodeRuneInString()
     45 	// which mangles stuff. UTF-16 BOM isn't strictly valid, but some tools add
     46 	// it anyway.
     47 	if strings.HasPrefix(data, "\xff\xfe") || strings.HasPrefix(data, "\xfe\xff") { // UTF-16
     48 		data = data[2:]
     49 	} else if strings.HasPrefix(data, "\xef\xbb\xbf") { // UTF-8
     50 		data = data[3:]
     51 	}
     52 
     53 	// Examine first few bytes for NULL bytes; this probably means it's a UTF-16
     54 	// file (second byte in surrogate pair being NULL). Again, do this here to
     55 	// avoid having to deal with UTF-8/16 stuff in the lexer.
     56 	ex := 6
     57 	if len(data) < 6 {
     58 		ex = len(data)
     59 	}
     60 	if i := strings.IndexRune(data[:ex], 0); i > -1 {
     61 		return nil, ParseError{
     62 			Message:  "files cannot contain NULL bytes; probably using UTF-16; TOML files must be UTF-8",
     63 			Position: Position{Line: 1, Col: 1, Start: i, Len: 1},
     64 			Line:     1,
     65 			input:    data,
     66 		}
     67 	}
     68 
     69 	p = &parser{
     70 		keyInfo:   make(map[string]keyInfo),
     71 		mapping:   make(map[string]any),
     72 		lx:        lex(data),
     73 		ordered:   make([]Key, 0),
     74 		implicits: make(map[string]struct{}),
     75 	}
     76 	for {
     77 		item := p.next()
     78 		if item.typ == itemEOF {
     79 			break
     80 		}
     81 		p.topLevel(item)
     82 	}
     83 
     84 	return p, nil
     85 }
     86 
     87 func (p *parser) panicErr(it item, err error) {
     88 	panic(ParseError{
     89 		Message:  err.Error(),
     90 		err:      err,
     91 		Position: it.pos.withCol(p.lx.input),
     92 		Line:     it.pos.Len,
     93 		LastKey:  p.current(),
     94 	})
     95 }
     96 
     97 func (p *parser) panicItemf(it item, format string, v ...any) {
     98 	panic(ParseError{
     99 		Message:  fmt.Sprintf(format, v...),
    100 		Position: it.pos.withCol(p.lx.input),
    101 		Line:     it.pos.Len,
    102 		LastKey:  p.current(),
    103 	})
    104 }
    105 
    106 func (p *parser) panicf(format string, v ...any) {
    107 	panic(ParseError{
    108 		Message:  fmt.Sprintf(format, v...),
    109 		Position: p.pos.withCol(p.lx.input),
    110 		Line:     p.pos.Line,
    111 		LastKey:  p.current(),
    112 	})
    113 }
    114 
    115 func (p *parser) next() item {
    116 	it := p.lx.nextItem()
    117 	//fmt.Printf("ITEM %-18s line %-3d │ %q\n", it.typ, it.pos.Line, it.val)
    118 	if it.typ == itemError {
    119 		if it.err != nil {
    120 			panic(ParseError{
    121 				Message:  it.err.Error(),
    122 				err:      it.err,
    123 				Position: it.pos.withCol(p.lx.input),
    124 				Line:     it.pos.Line,
    125 				LastKey:  p.current(),
    126 			})
    127 		}
    128 
    129 		p.panicItemf(it, "%s", it.val)
    130 	}
    131 	return it
    132 }
    133 
    134 func (p *parser) nextPos() item {
    135 	it := p.next()
    136 	p.pos = it.pos
    137 	return it
    138 }
    139 
    140 func (p *parser) bug(format string, v ...any) {
    141 	panic(fmt.Sprintf("BUG: "+format+"\n\n", v...))
    142 }
    143 
    144 func (p *parser) expect(typ itemType) item {
    145 	it := p.next()
    146 	p.assertEqual(typ, it.typ)
    147 	return it
    148 }
    149 
    150 func (p *parser) assertEqual(expected, got itemType) {
    151 	if expected != got {
    152 		p.bug("Expected '%s' but got '%s'.", expected, got)
    153 	}
    154 }
    155 
    156 func (p *parser) topLevel(item item) {
    157 	switch item.typ {
    158 	case itemCommentStart: // # ..
    159 		p.expect(itemText)
    160 	case itemTableStart: // [ .. ]
    161 		name := p.nextPos()
    162 
    163 		var key Key
    164 		for ; name.typ != itemTableEnd && name.typ != itemEOF; name = p.next() {
    165 			key = append(key, p.keyString(name))
    166 		}
    167 		p.assertEqual(itemTableEnd, name.typ)
    168 
    169 		p.addContext(key, false)
    170 		p.setType("", tomlHash, item.pos)
    171 		p.ordered = append(p.ordered, key)
    172 	case itemArrayTableStart: // [[ .. ]]
    173 		name := p.nextPos()
    174 
    175 		var key Key
    176 		for ; name.typ != itemArrayTableEnd && name.typ != itemEOF; name = p.next() {
    177 			key = append(key, p.keyString(name))
    178 		}
    179 		p.assertEqual(itemArrayTableEnd, name.typ)
    180 
    181 		p.addContext(key, true)
    182 		p.setType("", tomlArrayHash, item.pos)
    183 		p.ordered = append(p.ordered, key)
    184 	case itemKeyStart: // key = ..
    185 		outerContext := p.context
    186 		/// Read all the key parts (e.g. 'a' and 'b' in 'a.b')
    187 		k := p.nextPos()
    188 		var key Key
    189 		for ; k.typ != itemKeyEnd && k.typ != itemEOF; k = p.next() {
    190 			key = append(key, p.keyString(k))
    191 		}
    192 		p.assertEqual(itemKeyEnd, k.typ)
    193 
    194 		/// The current key is the last part.
    195 		p.currentKey = key.last()
    196 
    197 		/// All the other parts (if any) are the context; need to set each part
    198 		/// as implicit.
    199 		context := key.parent()
    200 		for i := range context {
    201 			p.addImplicitContext(append(p.context, context[i:i+1]...))
    202 		}
    203 		p.ordered = append(p.ordered, p.context.add(p.currentKey))
    204 
    205 		/// Set value.
    206 		vItem := p.next()
    207 		val, typ := p.value(vItem, false)
    208 		p.setValue(p.currentKey, val)
    209 		p.setType(p.currentKey, typ, vItem.pos)
    210 
    211 		/// Remove the context we added (preserving any context from [tbl] lines).
    212 		p.context = outerContext
    213 		p.currentKey = ""
    214 	default:
    215 		p.bug("Unexpected type at top level: %s", item.typ)
    216 	}
    217 }
    218 
    219 // Gets a string for a key (or part of a key in a table name).
    220 func (p *parser) keyString(it item) string {
    221 	switch it.typ {
    222 	case itemText:
    223 		return it.val
    224 	case itemString, itemStringEsc, itemMultilineString,
    225 		itemRawString, itemRawMultilineString:
    226 		s, _ := p.value(it, false)
    227 		return s.(string)
    228 	default:
    229 		p.bug("Unexpected key type: %s", it.typ)
    230 	}
    231 	panic("unreachable")
    232 }
    233 
    234 var datetimeRepl = strings.NewReplacer(
    235 	"z", "Z",
    236 	"t", "T",
    237 	" ", "T")
    238 
    239 // value translates an expected value from the lexer into a Go value wrapped
    240 // as an empty interface.
    241 func (p *parser) value(it item, parentIsArray bool) (any, tomlType) {
    242 	switch it.typ {
    243 	case itemString:
    244 		return it.val, p.typeOfPrimitive(it)
    245 	case itemStringEsc:
    246 		return p.replaceEscapes(it, it.val), p.typeOfPrimitive(it)
    247 	case itemMultilineString:
    248 		return p.replaceEscapes(it, p.stripEscapedNewlines(stripFirstNewline(it.val))), p.typeOfPrimitive(it)
    249 	case itemRawString:
    250 		return it.val, p.typeOfPrimitive(it)
    251 	case itemRawMultilineString:
    252 		return stripFirstNewline(it.val), p.typeOfPrimitive(it)
    253 	case itemInteger:
    254 		return p.valueInteger(it)
    255 	case itemFloat:
    256 		return p.valueFloat(it)
    257 	case itemBool:
    258 		switch it.val {
    259 		case "true":
    260 			return true, p.typeOfPrimitive(it)
    261 		case "false":
    262 			return false, p.typeOfPrimitive(it)
    263 		default:
    264 			p.bug("Expected boolean value, but got '%s'.", it.val)
    265 		}
    266 	case itemDatetime:
    267 		return p.valueDatetime(it)
    268 	case itemArray:
    269 		return p.valueArray(it)
    270 	case itemInlineTableStart:
    271 		return p.valueInlineTable(it, parentIsArray)
    272 	default:
    273 		p.bug("Unexpected value type: %s", it.typ)
    274 	}
    275 	panic("unreachable")
    276 }
    277 
    278 func (p *parser) valueInteger(it item) (any, tomlType) {
    279 	if !numUnderscoresOK(it.val) {
    280 		p.panicItemf(it, "Invalid integer %q: underscores must be surrounded by digits", it.val)
    281 	}
    282 	if numHasLeadingZero(it.val) {
    283 		p.panicItemf(it, "Invalid integer %q: cannot have leading zeroes", it.val)
    284 	}
    285 
    286 	num, err := strconv.ParseInt(it.val, 0, 64)
    287 	if err != nil {
    288 		// Distinguish integer values. Normally, it'd be a bug if the lexer
    289 		// provides an invalid integer, but it's possible that the number is
    290 		// out of range of valid values (which the lexer cannot determine).
    291 		// So mark the former as a bug but the latter as a legitimate user
    292 		// error.
    293 		if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange {
    294 			p.panicErr(it, errParseRange{i: it.val, size: "int64"})
    295 		} else {
    296 			p.bug("Expected integer value, but got '%s'.", it.val)
    297 		}
    298 	}
    299 	return num, p.typeOfPrimitive(it)
    300 }
    301 
    302 func (p *parser) valueFloat(it item) (any, tomlType) {
    303 	parts := strings.FieldsFunc(it.val, func(r rune) bool {
    304 		switch r {
    305 		case '.', 'e', 'E':
    306 			return true
    307 		}
    308 		return false
    309 	})
    310 	for _, part := range parts {
    311 		if !numUnderscoresOK(part) {
    312 			p.panicItemf(it, "Invalid float %q: underscores must be surrounded by digits", it.val)
    313 		}
    314 	}
    315 	if len(parts) > 0 && numHasLeadingZero(parts[0]) {
    316 		p.panicItemf(it, "Invalid float %q: cannot have leading zeroes", it.val)
    317 	}
    318 	if !numPeriodsOK(it.val) {
    319 		// As a special case, numbers like '123.' or '1.e2',
    320 		// which are valid as far as Go/strconv are concerned,
    321 		// must be rejected because TOML says that a fractional
    322 		// part consists of '.' followed by 1+ digits.
    323 		p.panicItemf(it, "Invalid float %q: '.' must be followed by one or more digits", it.val)
    324 	}
    325 	val := strings.Replace(it.val, "_", "", -1)
    326 	signbit := false
    327 	if val == "+nan" || val == "-nan" {
    328 		signbit = val == "-nan"
    329 		val = "nan"
    330 	}
    331 	num, err := strconv.ParseFloat(val, 64)
    332 	if err != nil {
    333 		if e, ok := err.(*strconv.NumError); ok && e.Err == strconv.ErrRange {
    334 			p.panicErr(it, errParseRange{i: it.val, size: "float64"})
    335 		} else {
    336 			p.panicItemf(it, "Invalid float value: %q", it.val)
    337 		}
    338 	}
    339 	if signbit {
    340 		num = math.Copysign(num, -1)
    341 	}
    342 	return num, p.typeOfPrimitive(it)
    343 }
    344 
    345 var dtTypes = []struct {
    346 	fmt  string
    347 	zone *time.Location
    348 }{
    349 	{time.RFC3339Nano, time.Local},
    350 	{"2006-01-02T15:04:05.999999999", internal.LocalDatetime},
    351 	{"2006-01-02", internal.LocalDate},
    352 	{"15:04:05.999999999", internal.LocalTime},
    353 	{"2006-01-02T15:04Z07:00", time.Local},
    354 	{"2006-01-02T15:04", internal.LocalDatetime},
    355 	{"15:04", internal.LocalTime},
    356 }
    357 
    358 func (p *parser) valueDatetime(it item) (any, tomlType) {
    359 	it.val = datetimeRepl.Replace(it.val)
    360 	var (
    361 		t   time.Time
    362 		ok  bool
    363 		err error
    364 	)
    365 	for _, dt := range dtTypes {
    366 		t, err = time.ParseInLocation(dt.fmt, it.val, dt.zone)
    367 		if err == nil {
    368 			if missingLeadingZero(it.val, dt.fmt) {
    369 				p.panicErr(it, errParseDate{it.val})
    370 			}
    371 			ok = true
    372 			break
    373 		}
    374 	}
    375 	if !ok {
    376 		p.panicErr(it, errParseDate{it.val})
    377 	}
    378 	return t, p.typeOfPrimitive(it)
    379 }
    380 
    381 // Go's time.Parse() will accept numbers without a leading zero; there isn't any
    382 // way to require it. https://github.com/golang/go/issues/29911
    383 //
    384 // Depend on the fact that the separators (- and :) should always be at the same
    385 // location.
    386 func missingLeadingZero(d, l string) bool {
    387 	for i, c := range []byte(l) {
    388 		if c == '.' || c == 'Z' {
    389 			return false
    390 		}
    391 		if (c < '0' || c > '9') && d[i] != c {
    392 			return true
    393 		}
    394 	}
    395 	return false
    396 }
    397 
    398 func (p *parser) valueArray(it item) (any, tomlType) {
    399 	p.setType(p.currentKey, tomlArray, it.pos)
    400 
    401 	var (
    402 		// Initialize to a non-nil slice to make it consistent with how S = []
    403 		// decodes into a non-nil slice inside something like struct { S
    404 		// []string }. See #338
    405 		array = make([]any, 0, 2)
    406 	)
    407 	for it = p.next(); it.typ != itemArrayEnd; it = p.next() {
    408 		if it.typ == itemCommentStart {
    409 			p.expect(itemText)
    410 			continue
    411 		}
    412 
    413 		val, typ := p.value(it, true)
    414 		array = append(array, val)
    415 
    416 		// XXX: type isn't used here, we need it to record the accurate type
    417 		// information.
    418 		//
    419 		// Not entirely sure how to best store this; could use "key[0]",
    420 		// "key[1]" notation, or maybe store it on the Array type?
    421 		_ = typ
    422 	}
    423 	return array, tomlArray
    424 }
    425 
    426 func (p *parser) valueInlineTable(it item, parentIsArray bool) (any, tomlType) {
    427 	var (
    428 		topHash      = make(map[string]any)
    429 		outerContext = p.context
    430 		outerKey     = p.currentKey
    431 	)
    432 
    433 	p.context = append(p.context, p.currentKey)
    434 	prevContext := p.context
    435 	p.currentKey = ""
    436 
    437 	p.addImplicit(p.context)
    438 	p.addContext(p.context, parentIsArray)
    439 
    440 	/// Loop over all table key/value pairs.
    441 	for it := p.next(); it.typ != itemInlineTableEnd; it = p.next() {
    442 		if it.typ == itemCommentStart {
    443 			p.expect(itemText)
    444 			continue
    445 		}
    446 
    447 		/// Read all key parts.
    448 		k := p.nextPos()
    449 		var key Key
    450 		for ; k.typ != itemKeyEnd && k.typ != itemEOF; k = p.next() {
    451 			key = append(key, p.keyString(k))
    452 		}
    453 		p.assertEqual(itemKeyEnd, k.typ)
    454 
    455 		/// The current key is the last part.
    456 		p.currentKey = key.last()
    457 
    458 		/// All the other parts (if any) are the context; need to set each part
    459 		/// as implicit.
    460 		context := key.parent()
    461 		for i := range context {
    462 			p.addImplicitContext(append(p.context, context[i:i+1]...))
    463 		}
    464 		p.ordered = append(p.ordered, p.context.add(p.currentKey))
    465 
    466 		/// Set the value.
    467 		val, typ := p.value(p.next(), false)
    468 		p.setValue(p.currentKey, val)
    469 		p.setType(p.currentKey, typ, it.pos)
    470 
    471 		hash := topHash
    472 		for _, c := range context {
    473 			h, ok := hash[c]
    474 			if !ok {
    475 				h = make(map[string]any)
    476 				hash[c] = h
    477 			}
    478 			hash, ok = h.(map[string]any)
    479 			if !ok {
    480 				p.panicf("%q is not a table", p.context)
    481 			}
    482 		}
    483 		hash[p.currentKey] = val
    484 
    485 		/// Restore context.
    486 		p.context = prevContext
    487 	}
    488 	p.context = outerContext
    489 	p.currentKey = outerKey
    490 	return topHash, tomlHash
    491 }
    492 
    493 // numHasLeadingZero checks if this number has leading zeroes, allowing for '0',
    494 // +/- signs, and base prefixes.
    495 func numHasLeadingZero(s string) bool {
    496 	if len(s) > 1 && s[0] == '0' && !(s[1] == 'b' || s[1] == 'o' || s[1] == 'x') { // Allow 0b, 0o, 0x
    497 		return true
    498 	}
    499 	if len(s) > 2 && (s[0] == '-' || s[0] == '+') && s[1] == '0' {
    500 		return true
    501 	}
    502 	return false
    503 }
    504 
    505 // numUnderscoresOK checks whether each underscore in s is surrounded by
    506 // characters that are not underscores.
    507 func numUnderscoresOK(s string) bool {
    508 	switch s {
    509 	case "nan", "+nan", "-nan", "inf", "-inf", "+inf":
    510 		return true
    511 	}
    512 	accept := false
    513 	for _, r := range s {
    514 		if r == '_' {
    515 			if !accept {
    516 				return false
    517 			}
    518 		}
    519 
    520 		// isHex is a superset of all the permissible characters surrounding an
    521 		// underscore.
    522 		accept = isHex(r)
    523 	}
    524 	return accept
    525 }
    526 
    527 // numPeriodsOK checks whether every period in s is followed by a digit.
    528 func numPeriodsOK(s string) bool {
    529 	period := false
    530 	for _, r := range s {
    531 		if period && !isDigit(r) {
    532 			return false
    533 		}
    534 		period = r == '.'
    535 	}
    536 	return !period
    537 }
    538 
    539 // Set the current context of the parser, where the context is either a hash or
    540 // an array of hashes, depending on the value of the `array` parameter.
    541 //
    542 // Establishing the context also makes sure that the key isn't a duplicate, and
    543 // will create implicit hashes automatically.
    544 func (p *parser) addContext(key Key, array bool) {
    545 	/// Always start at the top level and drill down for our context.
    546 	hashContext := p.mapping
    547 	keyContext := make(Key, 0, len(key)-1)
    548 
    549 	/// We only need implicit hashes for the parents.
    550 	for _, k := range key.parent() {
    551 		_, ok := hashContext[k]
    552 		keyContext = append(keyContext, k)
    553 
    554 		// No key? Make an implicit hash and move on.
    555 		if !ok {
    556 			p.addImplicit(keyContext)
    557 			hashContext[k] = make(map[string]any)
    558 		}
    559 
    560 		// If the hash context is actually an array of tables, then set
    561 		// the hash context to the last element in that array.
    562 		//
    563 		// Otherwise, it better be a table, since this MUST be a key group (by
    564 		// virtue of it not being the last element in a key).
    565 		switch t := hashContext[k].(type) {
    566 		case []map[string]any:
    567 			hashContext = t[len(t)-1]
    568 		case map[string]any:
    569 			hashContext = t
    570 		default:
    571 			p.panicf("Key '%s' was already created as a hash.", keyContext)
    572 		}
    573 	}
    574 
    575 	p.context = keyContext
    576 	if array {
    577 		// If this is the first element for this array, then allocate a new
    578 		// list of tables for it.
    579 		k := key.last()
    580 		if _, ok := hashContext[k]; !ok {
    581 			hashContext[k] = make([]map[string]any, 0, 4)
    582 		}
    583 
    584 		// Add a new table. But make sure the key hasn't already been used
    585 		// for something else.
    586 		if hash, ok := hashContext[k].([]map[string]any); ok {
    587 			hashContext[k] = append(hash, make(map[string]any))
    588 		} else {
    589 			p.panicf("Key '%s' was already created and cannot be used as an array.", key)
    590 		}
    591 	} else {
    592 		p.setValue(key.last(), make(map[string]any))
    593 	}
    594 	p.context = append(p.context, key.last())
    595 }
    596 
    597 // setValue sets the given key to the given value in the current context.
    598 // It will make sure that the key hasn't already been defined, account for
    599 // implicit key groups.
    600 func (p *parser) setValue(key string, value any) {
    601 	var (
    602 		tmpHash    any
    603 		ok         bool
    604 		hash       = p.mapping
    605 		keyContext = make(Key, 0, len(p.context)+1)
    606 	)
    607 	for _, k := range p.context {
    608 		keyContext = append(keyContext, k)
    609 		if tmpHash, ok = hash[k]; !ok {
    610 			p.bug("Context for key '%s' has not been established.", keyContext)
    611 		}
    612 		switch t := tmpHash.(type) {
    613 		case []map[string]any:
    614 			// The context is a table of hashes. Pick the most recent table
    615 			// defined as the current hash.
    616 			hash = t[len(t)-1]
    617 		case map[string]any:
    618 			hash = t
    619 		default:
    620 			p.panicf("Key '%s' has already been defined.", keyContext)
    621 		}
    622 	}
    623 	keyContext = append(keyContext, key)
    624 
    625 	if _, ok := hash[key]; ok {
    626 		// Normally redefining keys isn't allowed, but the key could have been
    627 		// defined implicitly and it's allowed to be redefined concretely. (See
    628 		// the `valid/implicit-and-explicit-after.toml` in toml-test)
    629 		//
    630 		// But we have to make sure to stop marking it as an implicit. (So that
    631 		// another redefinition provokes an error.)
    632 		//
    633 		// Note that since it has already been defined (as a hash), we don't
    634 		// want to overwrite it. So our business is done.
    635 		if p.isArray(keyContext) {
    636 			if !p.isImplicit(keyContext) {
    637 				if _, ok := hash[key]; ok {
    638 					p.panicf("Key '%s' has already been defined.", keyContext)
    639 				}
    640 			}
    641 			p.removeImplicit(keyContext)
    642 			hash[key] = value
    643 			return
    644 		}
    645 		if p.isImplicit(keyContext) {
    646 			p.removeImplicit(keyContext)
    647 			return
    648 		}
    649 		// Otherwise, we have a concrete key trying to override a previous key,
    650 		// which is *always* wrong.
    651 		p.panicf("Key '%s' has already been defined.", keyContext)
    652 	}
    653 
    654 	hash[key] = value
    655 }
    656 
    657 // setType sets the type of a particular value at a given key. It should be
    658 // called immediately AFTER setValue.
    659 //
    660 // Note that if `key` is empty, then the type given will be applied to the
    661 // current context (which is either a table or an array of tables).
    662 func (p *parser) setType(key string, typ tomlType, pos Position) {
    663 	keyContext := make(Key, 0, len(p.context)+1)
    664 	keyContext = append(keyContext, p.context...)
    665 	if len(key) > 0 { // allow type setting for hashes
    666 		keyContext = append(keyContext, key)
    667 	}
    668 	// Special case to make empty keys ("" = 1) work.
    669 	// Without it it will set "" rather than `""`.
    670 	// TODO: why is this needed? And why is this only needed here?
    671 	if len(keyContext) == 0 {
    672 		keyContext = Key{""}
    673 	}
    674 	p.keyInfo[keyContext.String()] = keyInfo{tomlType: typ, pos: pos}
    675 }
    676 
    677 // Implicit keys need to be created when tables are implied in "a.b.c.d = 1" and
    678 // "[a.b.c]" (the "a", "b", and "c" hashes are never created explicitly).
    679 func (p *parser) addImplicit(key Key)        { p.implicits[key.String()] = struct{}{} }
    680 func (p *parser) removeImplicit(key Key)     { delete(p.implicits, key.String()) }
    681 func (p *parser) isImplicit(key Key) bool    { _, ok := p.implicits[key.String()]; return ok }
    682 func (p *parser) isArray(key Key) bool       { return p.keyInfo[key.String()].tomlType == tomlArray }
    683 func (p *parser) addImplicitContext(key Key) { p.addImplicit(key); p.addContext(key, false) }
    684 
    685 // current returns the full key name of the current context.
    686 func (p *parser) current() string {
    687 	if len(p.currentKey) == 0 {
    688 		return p.context.String()
    689 	}
    690 	if len(p.context) == 0 {
    691 		return p.currentKey
    692 	}
    693 	return fmt.Sprintf("%s.%s", p.context, p.currentKey)
    694 }
    695 
    696 func stripFirstNewline(s string) string {
    697 	if len(s) > 0 && s[0] == '\n' {
    698 		return s[1:]
    699 	}
    700 	if len(s) > 1 && s[0] == '\r' && s[1] == '\n' {
    701 		return s[2:]
    702 	}
    703 	return s
    704 }
    705 
    706 // stripEscapedNewlines removes whitespace after line-ending backslashes in
    707 // multiline strings.
    708 //
    709 // A line-ending backslash is an unescaped \ followed only by whitespace until
    710 // the next newline. After a line-ending backslash, all whitespace is removed
    711 // until the next non-whitespace character.
    712 func (p *parser) stripEscapedNewlines(s string) string {
    713 	var (
    714 		b strings.Builder
    715 		i int
    716 	)
    717 	b.Grow(len(s))
    718 	for {
    719 		ix := strings.Index(s[i:], `\`)
    720 		if ix < 0 {
    721 			b.WriteString(s)
    722 			return b.String()
    723 		}
    724 		i += ix
    725 
    726 		if len(s) > i+1 && s[i+1] == '\\' {
    727 			// Escaped backslash.
    728 			i += 2
    729 			continue
    730 		}
    731 		// Scan until the next non-whitespace.
    732 		j := i + 1
    733 	whitespaceLoop:
    734 		for ; j < len(s); j++ {
    735 			switch s[j] {
    736 			case ' ', '\t', '\r', '\n':
    737 			default:
    738 				break whitespaceLoop
    739 			}
    740 		}
    741 		if j == i+1 {
    742 			// Not a whitespace escape.
    743 			i++
    744 			continue
    745 		}
    746 		if !strings.Contains(s[i:j], "\n") {
    747 			// This is not a line-ending backslash. (It's a bad escape sequence,
    748 			// but we can let replaceEscapes catch it.)
    749 			i++
    750 			continue
    751 		}
    752 		b.WriteString(s[:i])
    753 		s = s[j:]
    754 		i = 0
    755 	}
    756 }
    757 
    758 func (p *parser) replaceEscapes(it item, str string) string {
    759 	var (
    760 		b    strings.Builder
    761 		skip = 0
    762 	)
    763 	b.Grow(len(str))
    764 	for i, c := range str {
    765 		if skip > 0 {
    766 			skip--
    767 			continue
    768 		}
    769 		if c != '\\' {
    770 			b.WriteRune(c)
    771 			continue
    772 		}
    773 
    774 		if i >= len(str) {
    775 			p.bug("Escape sequence at end of string.")
    776 			return ""
    777 		}
    778 		switch str[i+1] {
    779 		default:
    780 			p.bug("Expected valid escape code after \\, but got %q.", str[i+1])
    781 		case ' ', '\t':
    782 			p.panicItemf(it, "invalid escape: '\\%c'", str[i+1])
    783 		case 'b':
    784 			b.WriteByte(0x08)
    785 			skip = 1
    786 		case 't':
    787 			b.WriteByte(0x09)
    788 			skip = 1
    789 		case 'n':
    790 			b.WriteByte(0x0a)
    791 			skip = 1
    792 		case 'f':
    793 			b.WriteByte(0x0c)
    794 			skip = 1
    795 		case 'r':
    796 			b.WriteByte(0x0d)
    797 			skip = 1
    798 		case 'e':
    799 			b.WriteByte(0x1b)
    800 			skip = 1
    801 		case '"':
    802 			b.WriteByte(0x22)
    803 			skip = 1
    804 		case '\\':
    805 			b.WriteByte(0x5c)
    806 			skip = 1
    807 		// The lexer guarantees the correct number of characters are present;
    808 		// don't need to check here.
    809 		case 'x':
    810 			escaped := p.asciiEscapeToUnicode(it, str[i+2:i+4])
    811 			b.WriteRune(escaped)
    812 			skip = 3
    813 		case 'u':
    814 			escaped := p.asciiEscapeToUnicode(it, str[i+2:i+6])
    815 			b.WriteRune(escaped)
    816 			skip = 5
    817 		case 'U':
    818 			escaped := p.asciiEscapeToUnicode(it, str[i+2:i+10])
    819 			b.WriteRune(escaped)
    820 			skip = 9
    821 		}
    822 	}
    823 	return b.String()
    824 }
    825 
    826 func (p *parser) asciiEscapeToUnicode(it item, s string) rune {
    827 	hex, err := strconv.ParseUint(strings.ToLower(s), 16, 32)
    828 	if err != nil {
    829 		p.bug("Could not parse '%s' as a hexadecimal number, but the lexer claims it's OK: %s", s, err)
    830 	}
    831 	if !utf8.ValidRune(rune(hex)) {
    832 		p.panicItemf(it, "Escaped character '\\u%s' is not valid UTF-8.", s)
    833 	}
    834 	return rune(hex)
    835 }