package parser import ( "git.makaay.nl/mauricem/go-parsekit/parse" ) // The primary building block of a TOML document is the key/value pair. var ( dropWhitespace = m.Drop(a.Whitespace.Optional()) dropBlanks = m.Drop(a.Blanks.Optional()) // 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) ) func (t *parser) startKeyValuePair(p *parse.API) { for { p.Accept(dropWhitespace) switch { case p.Peek(a.Hash): p.Handle(t.startComment) case p.Peek(startOfKey): p.Handle(t.startKey, t.startAssignment, t.startValue) default: p.ExpectEndOfFile() return } if p.IsStoppedOrInError() { return } } } func (t *parser) startKey(p *parse.API) { if p.Peek(bareKeyRune) { p.Handle(t.startBareKey) } else { p.Expected("a key name") } } func (t *parser) startBareKey(p *parse.API) { if p.Accept(bareKey) { t.emitCommand(cKey, p.Result().String()) p.Handle(t.endOfKeyOrDot) } else { p.Expected("a bare key name") } } func (t *parser) endOfKeyOrDot(p *parse.API) { if p.Accept(keySeparatorDot) { t.emitCommand(cNewKeyLvl) p.Handle(t.startKey) } } func (t *parser) startAssignment(p *parse.API) { if p.Accept(keyAssignment) { t.emitCommand(cAssign) } else { p.Expected("a value assignment") } } // Values must be of the following types: String, Integer, Float, Boolean, // Datetime, Array, or Inline Table. Unspecified values are invalid. func (t *parser) startValue(p *parse.API) { if p.Peek(c.Any(a.SingleQuote, a.DoubleQuote)) { p.Handle(t.startString) } else { p.Expected("a value") } }