go-toml/keyvaluepair.go

115 lines
3.7 KiB
Go

package toml
import (
"git.makaay.nl/mauricem/go-parsekit/parse"
)
// The primary building block of a TOML document is the key/value pair.
var (
// Keys are on the left of the equals sign and values are on the right.
// Blank is ignored around key names and values. The key, equals
// sign, and value must be on the same line (though some values can be
// broken over multiple lines).
keyAssignment = c.Seq(dropBlanks, a.Equal, dropBlanks)
// A key may be either bare, quoted or dotted. Bare keys may only
// contain ASCII letters, ASCII digits, underscores, and dashes
// (A-Za-z0-9_-). Note that bare keys are allowed to be composed of only
// ASCII digits, e.g. 1234, but are always interpreted as strings.
bareKeyRune = c.Any(a.ASCIILower, a.ASCIIUpper, a.Digit, a.Underscore, a.Minus)
bareKey = c.OneOrMore(bareKeyRune)
// Quoted keys follow the exact same rules as either basic strings or
// literal strings and allow you to use a much broader set of key names.
// Best practice is to use bare keys except when absolutely necessary.
// A bare key must be non-empty, but an empty quoted key is allowed
// (though discouraged).
startOfKey = c.Any(bareKeyRune, a.SingleQuote, a.DoubleQuote)
// Dotted keys are a sequence of bare or quoted keys joined with a dot.
// This allows for grouping similar properties together. Blanks
// around dot-separated parts are ignored, however, best practice is to
// not use any extraneous blanks.
keySeparatorDot = c.Seq(dropBlanks, a.Dot, dropBlanks)
// Both [tables] and [[arrays of tables]] start with a square open bracket.
startOfTableOrArrayOfTables = a.SquareOpen
)
func (t *parser) startKeyValuePair(p *parse.API) {
for {
p.Accept(dropWhitespace)
switch {
case p.Peek(a.Hash):
p.Handle(t.startComment)
case p.Peek(startOfTableOrArrayOfTables):
p.Handle(t.startTable)
case p.Peek(startOfKey):
key, ok := t.parseKey(p, []string{})
if ok && p.Handle(t.startAssignment) {
if value, ok := t.parseValue(p); ok {
err := t.setKeyValuePair(key, value)
if err != nil {
p.Error("%s", err)
return
}
}
}
default:
p.ExpectEndOfFile()
return
}
if p.IsStoppedOrInError() {
return
}
}
}
// Bare keys may only contain ASCII letters, ASCII digits, underscores, and
// dashes (A-Za-z0-9_-). Note that bare keys are allowed to be composed of only
// ASCII digits, e.g. 1234, but are always interpreted as strings.
//
// Quoted keys follow the exact same rules as either basic strings or literal
// strings and allow you to use a much broader set of key names. Best practice
// is to use bare keys except when absolutely necessary.
// A bare key must be non-empty, but an empty quoted key is allowed (though
// discouraged).
func (t *parser) parseKey(p *parse.API, key []string) ([]string, bool) {
var keyPart string
var ok bool
switch {
case p.Accept(bareKey):
keyPart, ok = p.Result().String(), true
case p.Peek(a.SingleQuote):
keyPart, ok = t.parseLiteralString("key", p)
case p.Peek(a.DoubleQuote):
keyPart, ok = t.parseBasicString("key", p)
default:
p.Expected("a key name")
return nil, false
}
if !ok {
return nil, false
}
key = append(key, keyPart)
return t.parseEndOfKeyOrDot(p, key)
}
// Dotted keys are a sequence of bare or quoted keys joined with a dot.
// This allows for grouping similar properties together.
// Whitespace around dot-separated parts is ignored, however, best
// practice is to not use any extraneous whitespace.
func (t *parser) parseEndOfKeyOrDot(p *parse.API, key []string) ([]string, bool) {
if p.Accept(keySeparatorDot) {
return t.parseKey(p, key)
}
return key, true
}
func (t *parser) startAssignment(p *parse.API) {
if !p.Accept(keyAssignment) {
p.Expected("a value assignment")
}
}