82 lines
2.3 KiB
Go
82 lines
2.3 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 (
|
|
arrayWhitespaceComment = c.OneOrMore(whitespaceInclNewlines.Or(comment))
|
|
arrayOpen = a.SquareOpen.Then(arrayWhitespaceComment.Optional())
|
|
arraySeparator = c.Seq(whitespace, a.Comma, arrayWhitespaceComment.Optional())
|
|
arrayClose = c.Seq(whitespace, a.Comma.Optional(), arrayWhitespaceComment.Optional(), a.SquareClose)
|
|
)
|
|
|
|
func (t *parser) parseArray(p *parse.API) (*ast.Value, bool) {
|
|
// Check for the start of the array.
|
|
if !p.Skip(arrayOpen) {
|
|
p.Expected("an array")
|
|
return nil, false
|
|
}
|
|
|
|
a := ast.NewArray()
|
|
|
|
// Check for an empty array.
|
|
if p.Skip(arrayClose) {
|
|
return ast.NewValue(ast.TypeArray, a), true
|
|
}
|
|
|
|
// Not an empty array, parse the array values.
|
|
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).
|
|
// This constraint is checked by ast.Array.Append().
|
|
if err := a.Append(value); err != nil {
|
|
p.SetError(err.Error())
|
|
return nil, false
|
|
}
|
|
|
|
// Check for the end of the array.
|
|
if p.Skip(arrayClose) {
|
|
return ast.NewValue(ast.TypeArray, a), true
|
|
}
|
|
|
|
// Not the end of the array? Then we should find an array separator.
|
|
if !p.Skip(arraySeparator) {
|
|
p.Expected("an array separator")
|
|
return nil, false
|
|
}
|
|
}
|
|
}
|