go-toml/parse/value_array.go

81 lines
2.4 KiB
Go

package parse
import (
"git.makaay.nl/mauricem/go-parsekit/parse"
"git.makaay.nl/mauricem/go-toml/ast"
)
// Arrays are square brackets with values inside. Whitespace is ignored.
// Elements are separated by commas. Data types may not be mixed (different
// ways to define strings should be considered the same type, and so should
// arrays with different element types).
//
// arr1 = [ 1, 2, 3 ]
// arr2 = [ "red", "yellow", "green" ]
// arr3 = [ [ 1, 2 ], [3, 4, 5] ]
// arr4 = [ "all", 'strings', """are the same""", '''type''']
// arr5 = [ [ 1, 2 ], ["a", "b", "c"] ]
//
// arr6 = [ 1, 2.0 ] # INVALID
//
// Arrays can also be multiline. A terminating comma (also called trailing
// comma) is ok after the last value of the array. There can be an arbitrary
// number of newlines and comments before a value and before the closing bracket.
//
// arr7 = [
// 1, 2, 3
// ]
//
// arr8 = [
// 1,
// 2, # this is ok
// ]
var (
arrayOpen = a.SquareOpen.Then(optionalWhitespaceOrComment)
arraySeparator = c.Seq(optionalWhitespaceOrComment, a.Comma, optionalWhitespaceOrComment)
arrayClose = c.Seq(c.Optional(optionalWhitespaceOrComment.Then(a.Comma)), optionalWhitespaceOrComment, a.SquareClose)
)
func (t *parser) parseArray(p *parse.API) (*ast.Value, bool) {
// Check for the start of the array.
if !p.Accept(arrayOpen) {
p.Expected("an array")
return nil, false
}
// Check for an empty array.
if p.Accept(arrayClose) {
return ast.NewValue(ast.TypeArray), true
}
// Not an empty array, parse the array values.
values := []interface{}{}
for {
// Check for a value item.
value, ok := t.parseValue(p)
if !ok {
return nil, false
}
// Data types may not be mixed (different ways to define strings should be
// considered the same type, and so should arrays with different element types).
if len(values) > 0 && value.Type != values[0].(*ast.Value).Type {
p.Error("type mismatch in array of %ss: found an item of type %s", values[0].(*ast.Value).Type, value.Type)
return nil, false
}
values = append(values, value)
// Check for the end of the array.
if p.Accept(arrayClose) {
return ast.NewValue(ast.TypeArray, values...), true
}
// Not the end of the array? Then we should find an array separator.
if !p.Accept(arraySeparator) {
p.Expected("an array separator")
return nil, false
}
}
}