package parser import "git.makaay.nl/mauricem/go-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.Seq(c.Opt(a.Whitespace), a.Equal, c.Opt(a.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. 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. Whitespace // around dot-separated parts is ignored, however, best practice is to // not use any extraneous whitespace. keySeparatorDot = c.Seq(c.Opt(a.Whitespace), a.Dot, c.Opt(a.Whitespace)) ) func startKeyValuePair(p *parsekit.P) { switch { case p.On(a.WhitespaceAndNewlines).Skip().RouteRepeat().End(): case p.On(a.Hash).RouteTo(startComment).ThenReturnHere().End(): case p.On(startOfKey).RouteTo(startKey).End(): default: p.ExpectEndOfFile() } } func startKey(p *parsekit.P) { p.Expects("a key name") p.On(bareKeyRune).RouteTo(startBareKey) } func startBareKey(p *parsekit.P) { p.Expects("a bare key name") if p.On(bareKey).Accept().End() { p.EmitLiteral(ItemKey) p.RouteTo(endOfKeyOrDot) } } func endOfKeyOrDot(p *parsekit.P) { if p.On(keySeparatorDot).Skip().End() { p.Emit(ItemKeyDot, ".") p.RouteTo(startKey) } else { p.RouteTo(startAssignment) } } func startAssignment(p *parsekit.P) { p.Expects("a value assignment") if p.On(keyAssignment).Skip().End() { p.Emit(ItemAssignment, "=") p.RouteTo(startValue) } } // 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) { p.Expects("a value") p.On(c.Any(a.SingleQuote, a.DoubleQuote)).RouteTo(startString) }