diff --git a/toml.go b/toml.go index 177e111..1e9aec2 100644 --- a/toml.go +++ b/toml.go @@ -27,6 +27,9 @@ type builder interface { Dot(b []byte) Boolean(b []byte) Equal(b []byte) + ArrayBegin() + ArrayEnd() + ArraySeparator() } type position struct { @@ -38,6 +41,18 @@ type documentBuilder struct { document Document } +func (d *documentBuilder) ArraySeparator() { + fmt.Println(", ARRAY SEPARATOR") +} + +func (d *documentBuilder) ArrayBegin() { + fmt.Println("[ ARRAY BEGIN") +} + +func (d *documentBuilder) ArrayEnd() { + fmt.Println("] ARRAY END") +} + func (d *documentBuilder) Equal(b []byte) { s := string(b) fmt.Printf("EQUAL: '%s'\n", s) @@ -243,6 +258,22 @@ func (p *parser) parse() error { } } +func (p *parser) parseRequiredNewline() error { + r := p.next() + switch r { + case '\n': + p.ignore() + return nil + case '\r': + r = p.next() + if r == '\n' { + p.ignore() + return nil + } + } + return &InvalidCharacter{r: r} +} + func (p *parser) parseExpression() error { err := p.parseWhitespace() if err != nil { @@ -325,11 +356,104 @@ func (p *parser) parseVal() error { return p.parseBool() case '\'', '"': return p.parseString() + case '[': + return p.parseArray() // TODO default: return &InvalidCharacter{r: r} } } + +func (p *parser) parseArray() error { + //array = array-open [ array-values ] ws-comment-newline array-close + + err := p.expect('[') + if err != nil { + panic("arrays should start with [") + } + + p.builder.ArrayBegin() + + err = p.parseWhitespaceCommentNewline() + if err != nil { + return err + } + + r := p.peek() + + if r == ']' { + p.next() + p.ignore() + p.builder.ArrayEnd() + return nil + } + + err = p.parseVal() + if err != nil { + return err + } + + for { + err = p.parseWhitespaceCommentNewline() + if err != nil { + return err + } + + r := p.peek() + + if r == ']' { + p.next() + p.ignore() + p.builder.ArrayEnd() + return nil + } + + err := p.expect(',') + if err != nil { + return err + } + p.builder.ArraySeparator() + p.ignore() + + err = p.parseWhitespaceCommentNewline() + if err != nil { + return err + } + + err = p.parseVal() + if err != nil { + return err + } + } +} + +func (p *parser) parseWhitespaceCommentNewline() error { + // ws-comment-newline = *( wschar / ([ comment ] newline) ) + + for { + if isWhitespace(p.peek()) { + err := p.parseWhitespace() + if err != nil { + return err + } + } + if p.peek() == '#' { + err := p.parseComment() + if err != nil { + return err + } + } + r := p.peek() + if r != '\n' && r != '\r' { + return nil + } + err := p.parseRequiredNewline() + if err != nil { + return err + } + } +} + func (p *parser) parseString() error { r := p.peek() diff --git a/toml_test.go b/toml_test.go index 3491e6a..1563fce 100644 --- a/toml_test.go +++ b/toml_test.go @@ -24,6 +24,11 @@ var inputs = []string{ `a."b".c = true`, `a = "foo"`, `b = 'sample thingy'`, + `a = []`, + `b = ["foo"]`, + `c = [[[]]]`, + `d = ["foo","bar"]`, + `d = ["foo", "test"]`, } func TestParse(t *testing.T) { @@ -40,29 +45,17 @@ func TestParse(t *testing.T) { type noopBuilder struct { } -func (n noopBuilder) Whitespace(b []byte) { -} - -func (n noopBuilder) Comment(b []byte) { -} - -func (n noopBuilder) UnquotedKey(b []byte) { -} - -func (n noopBuilder) LiteralString(b []byte) { -} - -func (n noopBuilder) BasicString(b []byte) { -} - -func (n noopBuilder) Dot(b []byte) { -} - -func (n noopBuilder) Boolean(b []byte) { -} - -func (n noopBuilder) Equal(b []byte) { -} +func (n noopBuilder) ArraySeparator() {} +func (n noopBuilder) ArrayBegin() {} +func (n noopBuilder) ArrayEnd() {} +func (n noopBuilder) Whitespace(b []byte) {} +func (n noopBuilder) Comment(b []byte) {} +func (n noopBuilder) UnquotedKey(b []byte) {} +func (n noopBuilder) LiteralString(b []byte) {} +func (n noopBuilder) BasicString(b []byte) {} +func (n noopBuilder) Dot(b []byte) {} +func (n noopBuilder) Boolean(b []byte) {} +func (n noopBuilder) Equal(b []byte) {} func BenchmarkParseAll(b *testing.B) { b.ReportAllocs()