go-toml/value_table.go

149 lines
4.6 KiB
Go

package toml
import (
"git.makaay.nl/mauricem/go-parsekit/parse"
)
var (
// Tables (also known as hash tables or dictionaries) are collections of
// key/value pairs. They appear in square brackets on a line by themselves.
// You can tell them apart from arrays because arrays are only ever values.
//
// Under that, and until the next table or EOF are the key/values of that
// table. Key/value pairs within tables are not guaranteed to be in any
// specific order.
//
// [table-1]
// key1 = "some string"
// key2 = 123
//
// [table-2]
// key1 = "another string"
// key2 = 456
//
// Naming rules for tables are the same as for keys.
//
// [dog."tater.man"]
// type.name = "pug"
//
// Whitespace around the key is ignored, however, best practice is to not
// use any extraneous whitespace.
//
// [a.b.c] # this is best practice
// [ d.e.f ] # same as [d.e.f]
// [ g . h . i ] # same as [g.h.i]
// [ j . "ʞ" . 'l' ] # same as [j."ʞ".'l']
//
// You don't need to specify all the super-tables if you don't want to.
// TOML knows how to do it for you.
//
// # [x] you
// # [x.y] don't
// # [x.y.z] need these
// [x.y.z.w] # for this to work
//
// Empty tables are allowed and simply have no key/value pairs within them.
//
tableOpen = c.Seq(dropBlanks, a.SquareOpen, dropBlanks)
tableClose = c.Seq(dropBlanks, a.SquareClose, dropBlanks, a.EndOfLine.Or(comment))
// Arrays of tables can be expressed by using a table name in double brackets.
// Each table with the same double bracketed name will be an element in the
// array. The tables are inserted in the order encountered. A double bracketed
// table without any key/value pairs will be considered an empty table.
//
// [[products]]
// name = "Hammer"
// sku = 738594937
//
// [[products]]
//
// [[products]]
// name = "Nail"
// sku = 284758393
// color = "gray"
//
// You can create nested arrays of tables as well. Just use the same double
// bracket syntax on sub-tables. Each double-bracketed sub-table will belong
// to the most recently defined table element above it.
//
// [[fruit]]
// name = "apple"
//
// [fruit.physical]
// color = "red"
// shape = "round"
//
// [[fruit.variety]]
// name = "red delicious"
//
// [[fruit.variety]]
// name = "granny smith"
//
// [[fruit]]
// name = "banana"
//
// [[fruit.variety]]
// name = "plantain"
tableArrayOpen = c.Seq(dropBlanks, a.SquareOpen, a.SquareOpen, dropBlanks)
tableArrayClose = c.Seq(dropBlanks, a.SquareClose, a.SquareClose, dropBlanks, a.EndOfLine.Or(comment))
// Inline tables provide a more compact syntax for expressing tables.
// They are especially useful for grouped data that can otherwise quickly
// become verbose. Inline tables are enclosed in curly braces { and }.
// Within the braces, zero or more comma separated key/value pairs may appear.
// Key/value pairs take the same form as key/value pairs in standard tables.
// All value types are allowed, including inline tables.
//
// Inline tables are intended to appear on a single line. No newlines are
// allowed between the curly braces unless they are valid within a value.
// Even so, it is strongly discouraged to break an inline table onto multiple
// lines. If you find yourself gripped with this desire, it means you should
// be using standard tables.
//
// name = { first = "Tom", last = "Preston-Werner" }
// point = { x = 1, y = 2 }
// animal = { type.name = "pug" }
inlineTableOpen = c.Seq(dropBlanks, a.CurlyOpen, dropBlanks)
inlineTableClose = c.Seq(dropBlanks, a.CurlyClose, dropBlanks, a.EndOfLine.Or(comment))
)
func (t *parser) startTable(p *parse.API) {
switch {
case p.Accept(tableArrayOpen):
p.Handle(t.startArrayOfTables)
case p.Accept(tableOpen):
p.Handle(t.startPlainTable)
default:
p.Expected("a table")
}
}
func (t *parser) startArrayOfTables(p *parse.API) {
if key, ok := t.parseKey(p, []string{}); ok {
if !p.Accept(tableArrayClose) {
p.Expected("closing ']]' for array of tables name")
return
}
if err := t.openArrayOfTables(key); err != nil {
p.Error("%s", err)
return
}
p.Handle(t.startKeyValuePair)
}
}
func (t *parser) startPlainTable(p *parse.API) {
if key, ok := t.parseKey(p, []string{}); ok {
if !p.Accept(tableClose) {
p.Expected("closing ']' for table name")
return
}
if err := t.openTable(key); err != nil {
p.Error("%s", err)
return
}
p.Handle(t.startKeyValuePair)
}
}