Blame vendor/github.com/BurntSushi/toml/lex.go

Packit 63bb0d
package toml
Packit 63bb0d
Packit 63bb0d
import (
Packit 63bb0d
	"fmt"
Packit 63bb0d
	"strings"
Packit 63bb0d
	"unicode"
Packit 63bb0d
	"unicode/utf8"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
type itemType int
Packit 63bb0d
Packit 63bb0d
const (
Packit 63bb0d
	itemError itemType = iota
Packit 63bb0d
	itemNIL            // used in the parser to indicate no type
Packit 63bb0d
	itemEOF
Packit 63bb0d
	itemText
Packit 63bb0d
	itemString
Packit 63bb0d
	itemRawString
Packit 63bb0d
	itemMultilineString
Packit 63bb0d
	itemRawMultilineString
Packit 63bb0d
	itemBool
Packit 63bb0d
	itemInteger
Packit 63bb0d
	itemFloat
Packit 63bb0d
	itemDatetime
Packit 63bb0d
	itemArray // the start of an array
Packit 63bb0d
	itemArrayEnd
Packit 63bb0d
	itemTableStart
Packit 63bb0d
	itemTableEnd
Packit 63bb0d
	itemArrayTableStart
Packit 63bb0d
	itemArrayTableEnd
Packit 63bb0d
	itemKeyStart
Packit 63bb0d
	itemCommentStart
Packit 63bb0d
	itemInlineTableStart
Packit 63bb0d
	itemInlineTableEnd
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
const (
Packit 63bb0d
	eof              = 0
Packit 63bb0d
	comma            = ','
Packit 63bb0d
	tableStart       = '['
Packit 63bb0d
	tableEnd         = ']'
Packit 63bb0d
	arrayTableStart  = '['
Packit 63bb0d
	arrayTableEnd    = ']'
Packit 63bb0d
	tableSep         = '.'
Packit 63bb0d
	keySep           = '='
Packit 63bb0d
	arrayStart       = '['
Packit 63bb0d
	arrayEnd         = ']'
Packit 63bb0d
	commentStart     = '#'
Packit 63bb0d
	stringStart      = '"'
Packit 63bb0d
	stringEnd        = '"'
Packit 63bb0d
	rawStringStart   = '\''
Packit 63bb0d
	rawStringEnd     = '\''
Packit 63bb0d
	inlineTableStart = '{'
Packit 63bb0d
	inlineTableEnd   = '}'
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
type stateFn func(lx *lexer) stateFn
Packit 63bb0d
Packit 63bb0d
type lexer struct {
Packit 63bb0d
	input string
Packit 63bb0d
	start int
Packit 63bb0d
	pos   int
Packit 63bb0d
	line  int
Packit 63bb0d
	state stateFn
Packit 63bb0d
	items chan item
Packit 63bb0d
Packit 63bb0d
	// Allow for backing up up to three runes.
Packit 63bb0d
	// This is necessary because TOML contains 3-rune tokens (""" and ''').
Packit 63bb0d
	prevWidths [3]int
Packit 63bb0d
	nprev      int // how many of prevWidths are in use
Packit 63bb0d
	// If we emit an eof, we can still back up, but it is not OK to call
Packit 63bb0d
	// next again.
Packit 63bb0d
	atEOF bool
Packit 63bb0d
Packit 63bb0d
	// A stack of state functions used to maintain context.
Packit 63bb0d
	// The idea is to reuse parts of the state machine in various places.
Packit 63bb0d
	// For example, values can appear at the top level or within arbitrarily
Packit 63bb0d
	// nested arrays. The last state on the stack is used after a value has
Packit 63bb0d
	// been lexed. Similarly for comments.
Packit 63bb0d
	stack []stateFn
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
type item struct {
Packit 63bb0d
	typ  itemType
Packit 63bb0d
	val  string
Packit 63bb0d
	line int
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (lx *lexer) nextItem() item {
Packit 63bb0d
	for {
Packit 63bb0d
		select {
Packit 63bb0d
		case item := <-lx.items:
Packit 63bb0d
			return item
Packit 63bb0d
		default:
Packit 63bb0d
			lx.state = lx.state(lx)
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func lex(input string) *lexer {
Packit 63bb0d
	lx := &lexer{
Packit 63bb0d
		input: input,
Packit 63bb0d
		state: lexTop,
Packit 63bb0d
		line:  1,
Packit 63bb0d
		items: make(chan item, 10),
Packit 63bb0d
		stack: make([]stateFn, 0, 10),
Packit 63bb0d
	}
Packit 63bb0d
	return lx
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (lx *lexer) push(state stateFn) {
Packit 63bb0d
	lx.stack = append(lx.stack, state)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (lx *lexer) pop() stateFn {
Packit 63bb0d
	if len(lx.stack) == 0 {
Packit 63bb0d
		return lx.errorf("BUG in lexer: no states to pop")
Packit 63bb0d
	}
Packit 63bb0d
	last := lx.stack[len(lx.stack)-1]
Packit 63bb0d
	lx.stack = lx.stack[0 : len(lx.stack)-1]
Packit 63bb0d
	return last
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (lx *lexer) current() string {
Packit 63bb0d
	return lx.input[lx.start:lx.pos]
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (lx *lexer) emit(typ itemType) {
Packit 63bb0d
	lx.items <- item{typ, lx.current(), lx.line}
Packit 63bb0d
	lx.start = lx.pos
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (lx *lexer) emitTrim(typ itemType) {
Packit 63bb0d
	lx.items <- item{typ, strings.TrimSpace(lx.current()), lx.line}
Packit 63bb0d
	lx.start = lx.pos
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (lx *lexer) next() (r rune) {
Packit 63bb0d
	if lx.atEOF {
Packit 63bb0d
		panic("next called after EOF")
Packit 63bb0d
	}
Packit 63bb0d
	if lx.pos >= len(lx.input) {
Packit 63bb0d
		lx.atEOF = true
Packit 63bb0d
		return eof
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if lx.input[lx.pos] == '\n' {
Packit 63bb0d
		lx.line++
Packit 63bb0d
	}
Packit 63bb0d
	lx.prevWidths[2] = lx.prevWidths[1]
Packit 63bb0d
	lx.prevWidths[1] = lx.prevWidths[0]
Packit 63bb0d
	if lx.nprev < 3 {
Packit 63bb0d
		lx.nprev++
Packit 63bb0d
	}
Packit 63bb0d
	r, w := utf8.DecodeRuneInString(lx.input[lx.pos:])
Packit 63bb0d
	lx.prevWidths[0] = w
Packit 63bb0d
	lx.pos += w
Packit 63bb0d
	return r
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// ignore skips over the pending input before this point.
Packit 63bb0d
func (lx *lexer) ignore() {
Packit 63bb0d
	lx.start = lx.pos
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// backup steps back one rune. Can be called only twice between calls to next.
Packit 63bb0d
func (lx *lexer) backup() {
Packit 63bb0d
	if lx.atEOF {
Packit 63bb0d
		lx.atEOF = false
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
	if lx.nprev < 1 {
Packit 63bb0d
		panic("backed up too far")
Packit 63bb0d
	}
Packit 63bb0d
	w := lx.prevWidths[0]
Packit 63bb0d
	lx.prevWidths[0] = lx.prevWidths[1]
Packit 63bb0d
	lx.prevWidths[1] = lx.prevWidths[2]
Packit 63bb0d
	lx.nprev--
Packit 63bb0d
	lx.pos -= w
Packit 63bb0d
	if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' {
Packit 63bb0d
		lx.line--
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// accept consumes the next rune if it's equal to `valid`.
Packit 63bb0d
func (lx *lexer) accept(valid rune) bool {
Packit 63bb0d
	if lx.next() == valid {
Packit 63bb0d
		return true
Packit 63bb0d
	}
Packit 63bb0d
	lx.backup()
Packit 63bb0d
	return false
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// peek returns but does not consume the next rune in the input.
Packit 63bb0d
func (lx *lexer) peek() rune {
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	lx.backup()
Packit 63bb0d
	return r
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// skip ignores all input that matches the given predicate.
Packit 63bb0d
func (lx *lexer) skip(pred func(rune) bool) {
Packit 63bb0d
	for {
Packit 63bb0d
		r := lx.next()
Packit 63bb0d
		if pred(r) {
Packit 63bb0d
			continue
Packit 63bb0d
		}
Packit 63bb0d
		lx.backup()
Packit 63bb0d
		lx.ignore()
Packit 63bb0d
		return
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// errorf stops all lexing by emitting an error and returning `nil`.
Packit 63bb0d
// Note that any value that is a character is escaped if it's a special
Packit 63bb0d
// character (newlines, tabs, etc.).
Packit 63bb0d
func (lx *lexer) errorf(format string, values ...interface{}) stateFn {
Packit 63bb0d
	lx.items <- item{
Packit 63bb0d
		itemError,
Packit 63bb0d
		fmt.Sprintf(format, values...),
Packit 63bb0d
		lx.line,
Packit 63bb0d
	}
Packit 63bb0d
	return nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexTop consumes elements at the top level of TOML data.
Packit 63bb0d
func lexTop(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	if isWhitespace(r) || isNL(r) {
Packit 63bb0d
		return lexSkip(lx, lexTop)
Packit 63bb0d
	}
Packit 63bb0d
	switch r {
Packit 63bb0d
	case commentStart:
Packit 63bb0d
		lx.push(lexTop)
Packit 63bb0d
		return lexCommentStart
Packit 63bb0d
	case tableStart:
Packit 63bb0d
		return lexTableStart
Packit 63bb0d
	case eof:
Packit 63bb0d
		if lx.pos > lx.start {
Packit 63bb0d
			return lx.errorf("unexpected EOF")
Packit 63bb0d
		}
Packit 63bb0d
		lx.emit(itemEOF)
Packit 63bb0d
		return nil
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	// At this point, the only valid item can be a key, so we back up
Packit 63bb0d
	// and let the key lexer do the rest.
Packit 63bb0d
	lx.backup()
Packit 63bb0d
	lx.push(lexTopEnd)
Packit 63bb0d
	return lexKeyStart
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexTopEnd is entered whenever a top-level item has been consumed. (A value
Packit 63bb0d
// or a table.) It must see only whitespace, and will turn back to lexTop
Packit 63bb0d
// upon a newline. If it sees EOF, it will quit the lexer successfully.
Packit 63bb0d
func lexTopEnd(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	switch {
Packit 63bb0d
	case r == commentStart:
Packit 63bb0d
		// a comment will read to a newline for us.
Packit 63bb0d
		lx.push(lexTop)
Packit 63bb0d
		return lexCommentStart
Packit 63bb0d
	case isWhitespace(r):
Packit 63bb0d
		return lexTopEnd
Packit 63bb0d
	case isNL(r):
Packit 63bb0d
		lx.ignore()
Packit 63bb0d
		return lexTop
Packit 63bb0d
	case r == eof:
Packit 63bb0d
		lx.emit(itemEOF)
Packit 63bb0d
		return nil
Packit 63bb0d
	}
Packit 63bb0d
	return lx.errorf("expected a top-level item to end with a newline, "+
Packit 63bb0d
		"comment, or EOF, but got %q instead", r)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexTable lexes the beginning of a table. Namely, it makes sure that
Packit 63bb0d
// it starts with a character other than '.' and ']'.
Packit 63bb0d
// It assumes that '[' has already been consumed.
Packit 63bb0d
// It also handles the case that this is an item in an array of tables.
Packit 63bb0d
// e.g., '[[name]]'.
Packit 63bb0d
func lexTableStart(lx *lexer) stateFn {
Packit 63bb0d
	if lx.peek() == arrayTableStart {
Packit 63bb0d
		lx.next()
Packit 63bb0d
		lx.emit(itemArrayTableStart)
Packit 63bb0d
		lx.push(lexArrayTableEnd)
Packit 63bb0d
	} else {
Packit 63bb0d
		lx.emit(itemTableStart)
Packit 63bb0d
		lx.push(lexTableEnd)
Packit 63bb0d
	}
Packit 63bb0d
	return lexTableNameStart
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func lexTableEnd(lx *lexer) stateFn {
Packit 63bb0d
	lx.emit(itemTableEnd)
Packit 63bb0d
	return lexTopEnd
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func lexArrayTableEnd(lx *lexer) stateFn {
Packit 63bb0d
	if r := lx.next(); r != arrayTableEnd {
Packit 63bb0d
		return lx.errorf("expected end of table array name delimiter %q, "+
Packit 63bb0d
			"but got %q instead", arrayTableEnd, r)
Packit 63bb0d
	}
Packit 63bb0d
	lx.emit(itemArrayTableEnd)
Packit 63bb0d
	return lexTopEnd
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func lexTableNameStart(lx *lexer) stateFn {
Packit 63bb0d
	lx.skip(isWhitespace)
Packit 63bb0d
	switch r := lx.peek(); {
Packit 63bb0d
	case r == tableEnd || r == eof:
Packit 63bb0d
		return lx.errorf("unexpected end of table name " +
Packit 63bb0d
			"(table names cannot be empty)")
Packit 63bb0d
	case r == tableSep:
Packit 63bb0d
		return lx.errorf("unexpected table separator " +
Packit 63bb0d
			"(table names cannot be empty)")
Packit 63bb0d
	case r == stringStart || r == rawStringStart:
Packit 63bb0d
		lx.ignore()
Packit 63bb0d
		lx.push(lexTableNameEnd)
Packit 63bb0d
		return lexValue // reuse string lexing
Packit 63bb0d
	default:
Packit 63bb0d
		return lexBareTableName
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexBareTableName lexes the name of a table. It assumes that at least one
Packit 63bb0d
// valid character for the table has already been read.
Packit 63bb0d
func lexBareTableName(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	if isBareKeyChar(r) {
Packit 63bb0d
		return lexBareTableName
Packit 63bb0d
	}
Packit 63bb0d
	lx.backup()
Packit 63bb0d
	lx.emit(itemText)
Packit 63bb0d
	return lexTableNameEnd
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexTableNameEnd reads the end of a piece of a table name, optionally
Packit 63bb0d
// consuming whitespace.
Packit 63bb0d
func lexTableNameEnd(lx *lexer) stateFn {
Packit 63bb0d
	lx.skip(isWhitespace)
Packit 63bb0d
	switch r := lx.next(); {
Packit 63bb0d
	case isWhitespace(r):
Packit 63bb0d
		return lexTableNameEnd
Packit 63bb0d
	case r == tableSep:
Packit 63bb0d
		lx.ignore()
Packit 63bb0d
		return lexTableNameStart
Packit 63bb0d
	case r == tableEnd:
Packit 63bb0d
		return lx.pop()
Packit 63bb0d
	default:
Packit 63bb0d
		return lx.errorf("expected '.' or ']' to end table name, "+
Packit 63bb0d
			"but got %q instead", r)
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexKeyStart consumes a key name up until the first non-whitespace character.
Packit 63bb0d
// lexKeyStart will ignore whitespace.
Packit 63bb0d
func lexKeyStart(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.peek()
Packit 63bb0d
	switch {
Packit 63bb0d
	case r == keySep:
Packit 63bb0d
		return lx.errorf("unexpected key separator %q", keySep)
Packit 63bb0d
	case isWhitespace(r) || isNL(r):
Packit 63bb0d
		lx.next()
Packit 63bb0d
		return lexSkip(lx, lexKeyStart)
Packit 63bb0d
	case r == stringStart || r == rawStringStart:
Packit 63bb0d
		lx.ignore()
Packit 63bb0d
		lx.emit(itemKeyStart)
Packit 63bb0d
		lx.push(lexKeyEnd)
Packit 63bb0d
		return lexValue // reuse string lexing
Packit 63bb0d
	default:
Packit 63bb0d
		lx.ignore()
Packit 63bb0d
		lx.emit(itemKeyStart)
Packit 63bb0d
		return lexBareKey
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexBareKey consumes the text of a bare key. Assumes that the first character
Packit 63bb0d
// (which is not whitespace) has not yet been consumed.
Packit 63bb0d
func lexBareKey(lx *lexer) stateFn {
Packit 63bb0d
	switch r := lx.next(); {
Packit 63bb0d
	case isBareKeyChar(r):
Packit 63bb0d
		return lexBareKey
Packit 63bb0d
	case isWhitespace(r):
Packit 63bb0d
		lx.backup()
Packit 63bb0d
		lx.emit(itemText)
Packit 63bb0d
		return lexKeyEnd
Packit 63bb0d
	case r == keySep:
Packit 63bb0d
		lx.backup()
Packit 63bb0d
		lx.emit(itemText)
Packit 63bb0d
		return lexKeyEnd
Packit 63bb0d
	default:
Packit 63bb0d
		return lx.errorf("bare keys cannot contain %q", r)
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexKeyEnd consumes the end of a key and trims whitespace (up to the key
Packit 63bb0d
// separator).
Packit 63bb0d
func lexKeyEnd(lx *lexer) stateFn {
Packit 63bb0d
	switch r := lx.next(); {
Packit 63bb0d
	case r == keySep:
Packit 63bb0d
		return lexSkip(lx, lexValue)
Packit 63bb0d
	case isWhitespace(r):
Packit 63bb0d
		return lexSkip(lx, lexKeyEnd)
Packit 63bb0d
	default:
Packit 63bb0d
		return lx.errorf("expected key separator %q, but got %q instead",
Packit 63bb0d
			keySep, r)
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexValue starts the consumption of a value anywhere a value is expected.
Packit 63bb0d
// lexValue will ignore whitespace.
Packit 63bb0d
// After a value is lexed, the last state on the next is popped and returned.
Packit 63bb0d
func lexValue(lx *lexer) stateFn {
Packit 63bb0d
	// We allow whitespace to precede a value, but NOT newlines.
Packit 63bb0d
	// In array syntax, the array states are responsible for ignoring newlines.
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	switch {
Packit 63bb0d
	case isWhitespace(r):
Packit 63bb0d
		return lexSkip(lx, lexValue)
Packit 63bb0d
	case isDigit(r):
Packit 63bb0d
		lx.backup() // avoid an extra state and use the same as above
Packit 63bb0d
		return lexNumberOrDateStart
Packit 63bb0d
	}
Packit 63bb0d
	switch r {
Packit 63bb0d
	case arrayStart:
Packit 63bb0d
		lx.ignore()
Packit 63bb0d
		lx.emit(itemArray)
Packit 63bb0d
		return lexArrayValue
Packit 63bb0d
	case inlineTableStart:
Packit 63bb0d
		lx.ignore()
Packit 63bb0d
		lx.emit(itemInlineTableStart)
Packit 63bb0d
		return lexInlineTableValue
Packit 63bb0d
	case stringStart:
Packit 63bb0d
		if lx.accept(stringStart) {
Packit 63bb0d
			if lx.accept(stringStart) {
Packit 63bb0d
				lx.ignore() // Ignore """
Packit 63bb0d
				return lexMultilineString
Packit 63bb0d
			}
Packit 63bb0d
			lx.backup()
Packit 63bb0d
		}
Packit 63bb0d
		lx.ignore() // ignore the '"'
Packit 63bb0d
		return lexString
Packit 63bb0d
	case rawStringStart:
Packit 63bb0d
		if lx.accept(rawStringStart) {
Packit 63bb0d
			if lx.accept(rawStringStart) {
Packit 63bb0d
				lx.ignore() // Ignore """
Packit 63bb0d
				return lexMultilineRawString
Packit 63bb0d
			}
Packit 63bb0d
			lx.backup()
Packit 63bb0d
		}
Packit 63bb0d
		lx.ignore() // ignore the "'"
Packit 63bb0d
		return lexRawString
Packit 63bb0d
	case '+', '-':
Packit 63bb0d
		return lexNumberStart
Packit 63bb0d
	case '.': // special error case, be kind to users
Packit 63bb0d
		return lx.errorf("floats must start with a digit, not '.'")
Packit 63bb0d
	}
Packit 63bb0d
	if unicode.IsLetter(r) {
Packit 63bb0d
		// Be permissive here; lexBool will give a nice error if the
Packit 63bb0d
		// user wrote something like
Packit 63bb0d
		//   x = foo
Packit 63bb0d
		// (i.e. not 'true' or 'false' but is something else word-like.)
Packit 63bb0d
		lx.backup()
Packit 63bb0d
		return lexBool
Packit 63bb0d
	}
Packit 63bb0d
	return lx.errorf("expected value but found %q instead", r)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexArrayValue consumes one value in an array. It assumes that '[' or ','
Packit 63bb0d
// have already been consumed. All whitespace and newlines are ignored.
Packit 63bb0d
func lexArrayValue(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	switch {
Packit 63bb0d
	case isWhitespace(r) || isNL(r):
Packit 63bb0d
		return lexSkip(lx, lexArrayValue)
Packit 63bb0d
	case r == commentStart:
Packit 63bb0d
		lx.push(lexArrayValue)
Packit 63bb0d
		return lexCommentStart
Packit 63bb0d
	case r == comma:
Packit 63bb0d
		return lx.errorf("unexpected comma")
Packit 63bb0d
	case r == arrayEnd:
Packit 63bb0d
		// NOTE(caleb): The spec isn't clear about whether you can have
Packit 63bb0d
		// a trailing comma or not, so we'll allow it.
Packit 63bb0d
		return lexArrayEnd
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	lx.backup()
Packit 63bb0d
	lx.push(lexArrayValueEnd)
Packit 63bb0d
	return lexValue
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexArrayValueEnd consumes everything between the end of an array value and
Packit 63bb0d
// the next value (or the end of the array): it ignores whitespace and newlines
Packit 63bb0d
// and expects either a ',' or a ']'.
Packit 63bb0d
func lexArrayValueEnd(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	switch {
Packit 63bb0d
	case isWhitespace(r) || isNL(r):
Packit 63bb0d
		return lexSkip(lx, lexArrayValueEnd)
Packit 63bb0d
	case r == commentStart:
Packit 63bb0d
		lx.push(lexArrayValueEnd)
Packit 63bb0d
		return lexCommentStart
Packit 63bb0d
	case r == comma:
Packit 63bb0d
		lx.ignore()
Packit 63bb0d
		return lexArrayValue // move on to the next value
Packit 63bb0d
	case r == arrayEnd:
Packit 63bb0d
		return lexArrayEnd
Packit 63bb0d
	}
Packit 63bb0d
	return lx.errorf(
Packit 63bb0d
		"expected a comma or array terminator %q, but got %q instead",
Packit 63bb0d
		arrayEnd, r,
Packit 63bb0d
	)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexArrayEnd finishes the lexing of an array.
Packit 63bb0d
// It assumes that a ']' has just been consumed.
Packit 63bb0d
func lexArrayEnd(lx *lexer) stateFn {
Packit 63bb0d
	lx.ignore()
Packit 63bb0d
	lx.emit(itemArrayEnd)
Packit 63bb0d
	return lx.pop()
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexInlineTableValue consumes one key/value pair in an inline table.
Packit 63bb0d
// It assumes that '{' or ',' have already been consumed. Whitespace is ignored.
Packit 63bb0d
func lexInlineTableValue(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	switch {
Packit 63bb0d
	case isWhitespace(r):
Packit 63bb0d
		return lexSkip(lx, lexInlineTableValue)
Packit 63bb0d
	case isNL(r):
Packit 63bb0d
		return lx.errorf("newlines not allowed within inline tables")
Packit 63bb0d
	case r == commentStart:
Packit 63bb0d
		lx.push(lexInlineTableValue)
Packit 63bb0d
		return lexCommentStart
Packit 63bb0d
	case r == comma:
Packit 63bb0d
		return lx.errorf("unexpected comma")
Packit 63bb0d
	case r == inlineTableEnd:
Packit 63bb0d
		return lexInlineTableEnd
Packit 63bb0d
	}
Packit 63bb0d
	lx.backup()
Packit 63bb0d
	lx.push(lexInlineTableValueEnd)
Packit 63bb0d
	return lexKeyStart
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexInlineTableValueEnd consumes everything between the end of an inline table
Packit 63bb0d
// key/value pair and the next pair (or the end of the table):
Packit 63bb0d
// it ignores whitespace and expects either a ',' or a '}'.
Packit 63bb0d
func lexInlineTableValueEnd(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	switch {
Packit 63bb0d
	case isWhitespace(r):
Packit 63bb0d
		return lexSkip(lx, lexInlineTableValueEnd)
Packit 63bb0d
	case isNL(r):
Packit 63bb0d
		return lx.errorf("newlines not allowed within inline tables")
Packit 63bb0d
	case r == commentStart:
Packit 63bb0d
		lx.push(lexInlineTableValueEnd)
Packit 63bb0d
		return lexCommentStart
Packit 63bb0d
	case r == comma:
Packit 63bb0d
		lx.ignore()
Packit 63bb0d
		return lexInlineTableValue
Packit 63bb0d
	case r == inlineTableEnd:
Packit 63bb0d
		return lexInlineTableEnd
Packit 63bb0d
	}
Packit 63bb0d
	return lx.errorf("expected a comma or an inline table terminator %q, "+
Packit 63bb0d
		"but got %q instead", inlineTableEnd, r)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexInlineTableEnd finishes the lexing of an inline table.
Packit 63bb0d
// It assumes that a '}' has just been consumed.
Packit 63bb0d
func lexInlineTableEnd(lx *lexer) stateFn {
Packit 63bb0d
	lx.ignore()
Packit 63bb0d
	lx.emit(itemInlineTableEnd)
Packit 63bb0d
	return lx.pop()
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexString consumes the inner contents of a string. It assumes that the
Packit 63bb0d
// beginning '"' has already been consumed and ignored.
Packit 63bb0d
func lexString(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	switch {
Packit 63bb0d
	case r == eof:
Packit 63bb0d
		return lx.errorf("unexpected EOF")
Packit 63bb0d
	case isNL(r):
Packit 63bb0d
		return lx.errorf("strings cannot contain newlines")
Packit 63bb0d
	case r == '\\':
Packit 63bb0d
		lx.push(lexString)
Packit 63bb0d
		return lexStringEscape
Packit 63bb0d
	case r == stringEnd:
Packit 63bb0d
		lx.backup()
Packit 63bb0d
		lx.emit(itemString)
Packit 63bb0d
		lx.next()
Packit 63bb0d
		lx.ignore()
Packit 63bb0d
		return lx.pop()
Packit 63bb0d
	}
Packit 63bb0d
	return lexString
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexMultilineString consumes the inner contents of a string. It assumes that
Packit 63bb0d
// the beginning '"""' has already been consumed and ignored.
Packit 63bb0d
func lexMultilineString(lx *lexer) stateFn {
Packit 63bb0d
	switch lx.next() {
Packit 63bb0d
	case eof:
Packit 63bb0d
		return lx.errorf("unexpected EOF")
Packit 63bb0d
	case '\\':
Packit 63bb0d
		return lexMultilineStringEscape
Packit 63bb0d
	case stringEnd:
Packit 63bb0d
		if lx.accept(stringEnd) {
Packit 63bb0d
			if lx.accept(stringEnd) {
Packit 63bb0d
				lx.backup()
Packit 63bb0d
				lx.backup()
Packit 63bb0d
				lx.backup()
Packit 63bb0d
				lx.emit(itemMultilineString)
Packit 63bb0d
				lx.next()
Packit 63bb0d
				lx.next()
Packit 63bb0d
				lx.next()
Packit 63bb0d
				lx.ignore()
Packit 63bb0d
				return lx.pop()
Packit 63bb0d
			}
Packit 63bb0d
			lx.backup()
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
	return lexMultilineString
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexRawString consumes a raw string. Nothing can be escaped in such a string.
Packit 63bb0d
// It assumes that the beginning "'" has already been consumed and ignored.
Packit 63bb0d
func lexRawString(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	switch {
Packit 63bb0d
	case r == eof:
Packit 63bb0d
		return lx.errorf("unexpected EOF")
Packit 63bb0d
	case isNL(r):
Packit 63bb0d
		return lx.errorf("strings cannot contain newlines")
Packit 63bb0d
	case r == rawStringEnd:
Packit 63bb0d
		lx.backup()
Packit 63bb0d
		lx.emit(itemRawString)
Packit 63bb0d
		lx.next()
Packit 63bb0d
		lx.ignore()
Packit 63bb0d
		return lx.pop()
Packit 63bb0d
	}
Packit 63bb0d
	return lexRawString
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexMultilineRawString consumes a raw string. Nothing can be escaped in such
Packit 63bb0d
// a string. It assumes that the beginning "'''" has already been consumed and
Packit 63bb0d
// ignored.
Packit 63bb0d
func lexMultilineRawString(lx *lexer) stateFn {
Packit 63bb0d
	switch lx.next() {
Packit 63bb0d
	case eof:
Packit 63bb0d
		return lx.errorf("unexpected EOF")
Packit 63bb0d
	case rawStringEnd:
Packit 63bb0d
		if lx.accept(rawStringEnd) {
Packit 63bb0d
			if lx.accept(rawStringEnd) {
Packit 63bb0d
				lx.backup()
Packit 63bb0d
				lx.backup()
Packit 63bb0d
				lx.backup()
Packit 63bb0d
				lx.emit(itemRawMultilineString)
Packit 63bb0d
				lx.next()
Packit 63bb0d
				lx.next()
Packit 63bb0d
				lx.next()
Packit 63bb0d
				lx.ignore()
Packit 63bb0d
				return lx.pop()
Packit 63bb0d
			}
Packit 63bb0d
			lx.backup()
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
	return lexMultilineRawString
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexMultilineStringEscape consumes an escaped character. It assumes that the
Packit 63bb0d
// preceding '\\' has already been consumed.
Packit 63bb0d
func lexMultilineStringEscape(lx *lexer) stateFn {
Packit 63bb0d
	// Handle the special case first:
Packit 63bb0d
	if isNL(lx.next()) {
Packit 63bb0d
		return lexMultilineString
Packit 63bb0d
	}
Packit 63bb0d
	lx.backup()
Packit 63bb0d
	lx.push(lexMultilineString)
Packit 63bb0d
	return lexStringEscape(lx)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func lexStringEscape(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	switch r {
Packit 63bb0d
	case 'b':
Packit 63bb0d
		fallthrough
Packit 63bb0d
	case 't':
Packit 63bb0d
		fallthrough
Packit 63bb0d
	case 'n':
Packit 63bb0d
		fallthrough
Packit 63bb0d
	case 'f':
Packit 63bb0d
		fallthrough
Packit 63bb0d
	case 'r':
Packit 63bb0d
		fallthrough
Packit 63bb0d
	case '"':
Packit 63bb0d
		fallthrough
Packit 63bb0d
	case '\\':
Packit 63bb0d
		return lx.pop()
Packit 63bb0d
	case 'u':
Packit 63bb0d
		return lexShortUnicodeEscape
Packit 63bb0d
	case 'U':
Packit 63bb0d
		return lexLongUnicodeEscape
Packit 63bb0d
	}
Packit 63bb0d
	return lx.errorf("invalid escape character %q; only the following "+
Packit 63bb0d
		"escape characters are allowed: "+
Packit 63bb0d
		`\b, \t, \n, \f, \r, \", \\, \uXXXX, and \UXXXXXXXX`, r)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func lexShortUnicodeEscape(lx *lexer) stateFn {
Packit 63bb0d
	var r rune
Packit 63bb0d
	for i := 0; i < 4; i++ {
Packit 63bb0d
		r = lx.next()
Packit 63bb0d
		if !isHexadecimal(r) {
Packit 63bb0d
			return lx.errorf(`expected four hexadecimal digits after '\u', `+
Packit 63bb0d
				"but got %q instead", lx.current())
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
	return lx.pop()
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func lexLongUnicodeEscape(lx *lexer) stateFn {
Packit 63bb0d
	var r rune
Packit 63bb0d
	for i := 0; i < 8; i++ {
Packit 63bb0d
		r = lx.next()
Packit 63bb0d
		if !isHexadecimal(r) {
Packit 63bb0d
			return lx.errorf(`expected eight hexadecimal digits after '\U', `+
Packit 63bb0d
				"but got %q instead", lx.current())
Packit 63bb0d
		}
Packit 63bb0d
	}
Packit 63bb0d
	return lx.pop()
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexNumberOrDateStart consumes either an integer, a float, or datetime.
Packit 63bb0d
func lexNumberOrDateStart(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	if isDigit(r) {
Packit 63bb0d
		return lexNumberOrDate
Packit 63bb0d
	}
Packit 63bb0d
	switch r {
Packit 63bb0d
	case '_':
Packit 63bb0d
		return lexNumber
Packit 63bb0d
	case 'e', 'E':
Packit 63bb0d
		return lexFloat
Packit 63bb0d
	case '.':
Packit 63bb0d
		return lx.errorf("floats must start with a digit, not '.'")
Packit 63bb0d
	}
Packit 63bb0d
	return lx.errorf("expected a digit but got %q", r)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexNumberOrDate consumes either an integer, float or datetime.
Packit 63bb0d
func lexNumberOrDate(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	if isDigit(r) {
Packit 63bb0d
		return lexNumberOrDate
Packit 63bb0d
	}
Packit 63bb0d
	switch r {
Packit 63bb0d
	case '-':
Packit 63bb0d
		return lexDatetime
Packit 63bb0d
	case '_':
Packit 63bb0d
		return lexNumber
Packit 63bb0d
	case '.', 'e', 'E':
Packit 63bb0d
		return lexFloat
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	lx.backup()
Packit 63bb0d
	lx.emit(itemInteger)
Packit 63bb0d
	return lx.pop()
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexDatetime consumes a Datetime, to a first approximation.
Packit 63bb0d
// The parser validates that it matches one of the accepted formats.
Packit 63bb0d
func lexDatetime(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	if isDigit(r) {
Packit 63bb0d
		return lexDatetime
Packit 63bb0d
	}
Packit 63bb0d
	switch r {
Packit 63bb0d
	case '-', 'T', ':', '.', 'Z', '+':
Packit 63bb0d
		return lexDatetime
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	lx.backup()
Packit 63bb0d
	lx.emit(itemDatetime)
Packit 63bb0d
	return lx.pop()
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexNumberStart consumes either an integer or a float. It assumes that a sign
Packit 63bb0d
// has already been read, but that *no* digits have been consumed.
Packit 63bb0d
// lexNumberStart will move to the appropriate integer or float states.
Packit 63bb0d
func lexNumberStart(lx *lexer) stateFn {
Packit 63bb0d
	// We MUST see a digit. Even floats have to start with a digit.
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	if !isDigit(r) {
Packit 63bb0d
		if r == '.' {
Packit 63bb0d
			return lx.errorf("floats must start with a digit, not '.'")
Packit 63bb0d
		}
Packit 63bb0d
		return lx.errorf("expected a digit but got %q", r)
Packit 63bb0d
	}
Packit 63bb0d
	return lexNumber
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexNumber consumes an integer or a float after seeing the first digit.
Packit 63bb0d
func lexNumber(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	if isDigit(r) {
Packit 63bb0d
		return lexNumber
Packit 63bb0d
	}
Packit 63bb0d
	switch r {
Packit 63bb0d
	case '_':
Packit 63bb0d
		return lexNumber
Packit 63bb0d
	case '.', 'e', 'E':
Packit 63bb0d
		return lexFloat
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	lx.backup()
Packit 63bb0d
	lx.emit(itemInteger)
Packit 63bb0d
	return lx.pop()
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexFloat consumes the elements of a float. It allows any sequence of
Packit 63bb0d
// float-like characters, so floats emitted by the lexer are only a first
Packit 63bb0d
// approximation and must be validated by the parser.
Packit 63bb0d
func lexFloat(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.next()
Packit 63bb0d
	if isDigit(r) {
Packit 63bb0d
		return lexFloat
Packit 63bb0d
	}
Packit 63bb0d
	switch r {
Packit 63bb0d
	case '_', '.', '-', '+', 'e', 'E':
Packit 63bb0d
		return lexFloat
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	lx.backup()
Packit 63bb0d
	lx.emit(itemFloat)
Packit 63bb0d
	return lx.pop()
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexBool consumes a bool string: 'true' or 'false.
Packit 63bb0d
func lexBool(lx *lexer) stateFn {
Packit 63bb0d
	var rs []rune
Packit 63bb0d
	for {
Packit 63bb0d
		r := lx.next()
Packit 63bb0d
		if !unicode.IsLetter(r) {
Packit 63bb0d
			lx.backup()
Packit 63bb0d
			break
Packit 63bb0d
		}
Packit 63bb0d
		rs = append(rs, r)
Packit 63bb0d
	}
Packit 63bb0d
	s := string(rs)
Packit 63bb0d
	switch s {
Packit 63bb0d
	case "true", "false":
Packit 63bb0d
		lx.emit(itemBool)
Packit 63bb0d
		return lx.pop()
Packit 63bb0d
	}
Packit 63bb0d
	return lx.errorf("expected value but found %q instead", s)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexCommentStart begins the lexing of a comment. It will emit
Packit 63bb0d
// itemCommentStart and consume no characters, passing control to lexComment.
Packit 63bb0d
func lexCommentStart(lx *lexer) stateFn {
Packit 63bb0d
	lx.ignore()
Packit 63bb0d
	lx.emit(itemCommentStart)
Packit 63bb0d
	return lexComment
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexComment lexes an entire comment. It assumes that '#' has been consumed.
Packit 63bb0d
// It will consume *up to* the first newline character, and pass control
Packit 63bb0d
// back to the last state on the stack.
Packit 63bb0d
func lexComment(lx *lexer) stateFn {
Packit 63bb0d
	r := lx.peek()
Packit 63bb0d
	if isNL(r) || r == eof {
Packit 63bb0d
		lx.emit(itemText)
Packit 63bb0d
		return lx.pop()
Packit 63bb0d
	}
Packit 63bb0d
	lx.next()
Packit 63bb0d
	return lexComment
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// lexSkip ignores all slurped input and moves on to the next state.
Packit 63bb0d
func lexSkip(lx *lexer, nextState stateFn) stateFn {
Packit 63bb0d
	return func(lx *lexer) stateFn {
Packit 63bb0d
		lx.ignore()
Packit 63bb0d
		return nextState
Packit 63bb0d
	}
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// isWhitespace returns true if `r` is a whitespace character according
Packit 63bb0d
// to the spec.
Packit 63bb0d
func isWhitespace(r rune) bool {
Packit 63bb0d
	return r == '\t' || r == ' '
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func isNL(r rune) bool {
Packit 63bb0d
	return r == '\n' || r == '\r'
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func isDigit(r rune) bool {
Packit 63bb0d
	return r >= '0' && r <= '9'
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func isHexadecimal(r rune) bool {
Packit 63bb0d
	return (r >= '0' && r <= '9') ||
Packit 63bb0d
		(r >= 'a' && r <= 'f') ||
Packit 63bb0d
		(r >= 'A' && r <= 'F')
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func isBareKeyChar(r rune) bool {
Packit 63bb0d
	return (r >= 'A' && r <= 'Z') ||
Packit 63bb0d
		(r >= 'a' && r <= 'z') ||
Packit 63bb0d
		(r >= '0' && r <= '9') ||
Packit 63bb0d
		r == '_' ||
Packit 63bb0d
		r == '-'
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (itype itemType) String() string {
Packit 63bb0d
	switch itype {
Packit 63bb0d
	case itemError:
Packit 63bb0d
		return "Error"
Packit 63bb0d
	case itemNIL:
Packit 63bb0d
		return "NIL"
Packit 63bb0d
	case itemEOF:
Packit 63bb0d
		return "EOF"
Packit 63bb0d
	case itemText:
Packit 63bb0d
		return "Text"
Packit 63bb0d
	case itemString, itemRawString, itemMultilineString, itemRawMultilineString:
Packit 63bb0d
		return "String"
Packit 63bb0d
	case itemBool:
Packit 63bb0d
		return "Bool"
Packit 63bb0d
	case itemInteger:
Packit 63bb0d
		return "Integer"
Packit 63bb0d
	case itemFloat:
Packit 63bb0d
		return "Float"
Packit 63bb0d
	case itemDatetime:
Packit 63bb0d
		return "DateTime"
Packit 63bb0d
	case itemTableStart:
Packit 63bb0d
		return "TableStart"
Packit 63bb0d
	case itemTableEnd:
Packit 63bb0d
		return "TableEnd"
Packit 63bb0d
	case itemKeyStart:
Packit 63bb0d
		return "KeyStart"
Packit 63bb0d
	case itemArray:
Packit 63bb0d
		return "Array"
Packit 63bb0d
	case itemArrayEnd:
Packit 63bb0d
		return "ArrayEnd"
Packit 63bb0d
	case itemCommentStart:
Packit 63bb0d
		return "CommentStart"
Packit 63bb0d
	}
Packit 63bb0d
	panic(fmt.Sprintf("BUG: Unknown type '%d'.", int(itype)))
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func (item item) String() string {
Packit 63bb0d
	return fmt.Sprintf("(%s, %s)", item.typ.String(), item.val)
Packit 63bb0d
}