89 lines
2.7 KiB
Go
89 lines
2.7 KiB
Go
package parser
|
|
|
|
import "github.com/mmakaay/toml/parsekit"
|
|
|
|
// 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.
|
|
// Whitespace 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.Sequence(optionalWhitespace, equal, optionalWhitespace)
|
|
|
|
// 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.AnyOf(lower, upper, digit, underscore, dash)
|
|
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.AnyOf(bareKeyRune, anyQuote)
|
|
|
|
// 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.
|
|
keySeparatordDot = c.Sequence(optionalWhitespace, dot, optionalWhitespace)
|
|
)
|
|
|
|
func startKeyValuePair(p *parsekit.P) {
|
|
p.On(whitespaceOrNewlines).Skip()
|
|
switch {
|
|
case p.On(hash).Stay():
|
|
p.RouteTo(startComment).ThenReturnHere()
|
|
case p.On(startOfKey).RouteTo(startKey):
|
|
default:
|
|
p.RouteTo(endOfFile) // TODO Make end of file a Matcher, so this can be simpler.
|
|
}
|
|
}
|
|
|
|
func startKey(p *parsekit.P) {
|
|
switch {
|
|
case p.On(bareKeyRune).RouteTo(startBareKey):
|
|
default:
|
|
p.UnexpectedInput("a valid key name")
|
|
}
|
|
}
|
|
|
|
func startBareKey(p *parsekit.P) {
|
|
p.On(bareKey).Accept()
|
|
p.EmitLiteral(ItemKey)
|
|
p.RouteTo(endOfKeyOrDot)
|
|
}
|
|
|
|
func endOfKeyOrDot(p *parsekit.P) {
|
|
if p.On(keySeparatordDot).Skip() {
|
|
p.Emit(ItemKeyDot, ".")
|
|
p.RouteTo(startKey)
|
|
} else {
|
|
p.RouteTo(startKeyAssignment)
|
|
}
|
|
}
|
|
|
|
func startKeyAssignment(p *parsekit.P) {
|
|
if p.On(keyAssignment).Skip() {
|
|
p.Emit(ItemAssignment, "=")
|
|
p.RouteTo(startValue)
|
|
} else {
|
|
p.UnexpectedInput("a value assignment")
|
|
}
|
|
}
|
|
|
|
// Values must be of the following types: String, Integer, Float, Boolean,
|
|
// Datetime, Array, or Inline Table. Unspecified values are invalid.
|
|
func startValue(p *parsekit.P) {
|
|
switch {
|
|
case p.On(anyQuote).RouteTo(startString):
|
|
default:
|
|
p.UnexpectedInput("a value")
|
|
}
|
|
}
|