go-toml/parse/keyvaluepair.go

107 lines
3.5 KiB
Go

package parse
import (
"git.makaay.nl/mauricem/go-parsekit/parse"
"git.makaay.nl/mauricem/go-toml/ast"
)
// The primary building block of a TOML document is the table.
// Tables are filled with key/value pairs.
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(whitespace, a.Equal, whitespace)
// 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.
//
// 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).
isBareKeyRune = func(b byte) bool {
return ((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') ||
(b >= '0' && b <= '9') || b == '_' || b == '-')
}
bareKeyRune = a.ByteByCallback(isBareKeyRune)
bareKey = c.OneOrMore(bareKeyRune)
// 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.
keySeparatorDot = c.Seq(whitespace, a.Dot, whitespace)
)
func (t *parser) startKeyValuePair(p *parse.API) {
key, ok := t.parseKey(p, ast.NewKey())
if ok && p.Handle(t.startAssignment) {
if value, ok := t.parseValue(p); ok {
err := t.doc.SetKeyValuePair(key, value)
if err != nil {
p.SetError("%s", err)
} else if !p.Accept(endOfLineOrComment) {
p.Expected("end of line")
}
}
}
}
// 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 ast.Key) (ast.Key, 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 ast.Key) (ast.Key, 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")
}
}