100 lines
3.5 KiB
Go
100 lines
3.5 KiB
Go
package parse
|
|
|
|
import (
|
|
"git.makaay.nl/mauricem/go-parsekit/parse"
|
|
)
|
|
|
|
// 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(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.
|
|
//
|
|
// 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).
|
|
bareKeyRune = c.Any(a.ASCIILower, a.ASCIIUpper, a.Digit, a.Underscore, a.Minus)
|
|
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. Blanks
|
|
// around dot-separated parts are ignored, however, best practice is to
|
|
// not use any extraneous blanks.
|
|
keySeparatorDot = c.Seq(dropBlanks, a.Dot, dropBlanks)
|
|
|
|
// After a value, the line must end. There can be an optional comment.
|
|
endOfLineAfterValue = c.Seq(dropBlanks, a.EndOfLine.Or(dropComment))
|
|
)
|
|
|
|
func (t *parser) startKeyValuePair(p *parse.API) {
|
|
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)
|
|
} else if !p.Accept(endOfLineAfterValue) {
|
|
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 []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")
|
|
}
|
|
}
|