diff --git a/scanner.go b/scanner.go index 5ffb7c4..99d9f0a 100644 --- a/scanner.go +++ b/scanner.go @@ -23,6 +23,25 @@ var scanFollowsFalse = scanFollows([]byte{'f', 'a', 'l', 's', 'e'}) var scanFollowsArrayTableBegin = scanFollows([]byte{arrayOrTableBegin, arrayOrTableBegin}) var scanFollowsArrayTableEnd = scanFollows([]byte{arrayOrTableEnd, arrayOrTableEnd}) +func scanNewline(b []byte) ([]byte, []byte, error) { + if len(b) == 0 { + return nil, nil, fmt.Errorf("not enough bytes for new line") + } + if b[0] == '\n' { + return b[:1], b[1:], nil + } + if b[0] == '\r' { + if len(b) < 2 { + return nil, nil, fmt.Errorf("not enough bytes for windows newline") + } + if b[1] == '\n' { + return b[:2], b[2:], nil + } + return nil, nil, unexpectedCharacter{r: '\n', b: b[2:]} + } + return nil, nil, unexpectedCharacter{b: b} +} + const ( dot = '.' equal = '=' @@ -94,7 +113,7 @@ func scan(b []byte) ([]byte, []byte, error) { func scanUnquotedKey(b []byte) ([]byte, []byte, error) { //unquoted-key = 1*( ALPHA / DIGIT / %x2D / %x5F ) ; A-Z / a-z / 0-9 / - / _ - for i := 1; i < len(b); i++ { + for i := 0; i < len(b); i++ { if !isUnquotedKeyChar(b[i]) { return b[:i], b[i:], nil } @@ -153,7 +172,7 @@ func scanWindowsNewline(b []byte) ([]byte, []byte, error) { } func scanWhitespace(b []byte) ([]byte, []byte) { - for i := 1; i < len(b); i++ { + for i := 0; i < len(b); i++ { switch b[i] { case ' ', '\t': continue @@ -176,7 +195,7 @@ func scanComment(b []byte) ([]byte, []byte, error) { for i := 1; i < len(b); i++ { switch b[i] { case '\n': - return b[:i+1], b[i+1:], nil + return b[:i], b[i:], nil } } return b, nil, nil diff --git a/toml.go b/toml.go index 353c8ad..6c6084d 100644 --- a/toml.go +++ b/toml.go @@ -51,12 +51,20 @@ func parseExpression(b []byte) ([]byte, error) { _, rest, err := scanComment(b) return rest, err } + if b[0] == '\n' || b[0] == '\r' { + _, rest, err := scanNewline(b) + return rest, err + } + var err error if b[0] == '[' { // TODO: parse 'table' + panic("todo") } else { - rest, err := parseKeyval(b) - return rest, err + b, err = parseKeyval(b) + } + if err != nil { + return nil, err } b = parseWhitespace(b) @@ -107,11 +115,20 @@ func parseVal(b []byte) ([]byte, error) { case '\'': if scanFollowsMultilineLiteralStringDelimiter(b) { _, b, err = parseMultilineLiteralString(b) + } else { + _, b, err = scanLiteralString(b) } - _, b, err = scanLiteralString(b) return b, err - // TODO boolean - + case 't': + if !scanFollowsTrue(b) { + return nil, fmt.Errorf("expected 'true'") + } + return b[4:], nil + case 'f': + if !scanFollowsFalse(b) { + return nil, fmt.Errorf("expected 'false'") + } + return b[5:], nil // TODO array // TODO inline-table @@ -247,8 +264,8 @@ func parseKey(b []byte) ([]byte, error) { } for { - if len(b) > 0 && (b[0] == '.' || isWhitespace(b[0])) { - b = parseWhitespace(b) + b = parseWhitespace(b) + if len(b) > 0 && b[0] == '.' { b, err = expect('.', b) if err != nil { return nil, err @@ -266,10 +283,6 @@ func parseKey(b []byte) ([]byte, error) { return b, nil } -func isWhitespace(b byte) bool { - return b == ' ' || b == '\t' -} - func parseSimpleKey(b []byte) ([]byte, error) { //simple-key = quoted-key / unquoted-key //unquoted-key = 1*( ALPHA / DIGIT / %x2D / %x5F ) ; A-Z / a-z / 0-9 / - / _ diff --git a/toml_test.go b/toml_test.go index f065c18..846e380 100644 --- a/toml_test.go +++ b/toml_test.go @@ -35,7 +35,7 @@ var inputs = []string{ `[ test ]`, `[ "hello".world ]`, `[test] -a = false`, + a = false`, `[[foo]]`, } @@ -66,27 +66,27 @@ func TestParse(t *testing.T) { } } -type noopParser struct { -} - -func (n noopParser) ArrayTableBegin() {} -func (n noopParser) ArrayTableEnd() {} -func (n noopParser) StandardTableBegin() {} -func (n noopParser) StandardTableEnd() {} -func (n noopParser) InlineTableSeparator() {} -func (n noopParser) InlineTableBegin() {} -func (n noopParser) InlineTableEnd() {} -func (n noopParser) ArraySeparator() {} -func (n noopParser) ArrayBegin() {} -func (n noopParser) ArrayEnd() {} -func (n noopParser) Whitespace(b []byte) {} -func (n noopParser) Comment(b []byte) {} -func (n noopParser) UnquotedKey(b []byte) {} -func (n noopParser) LiteralString(b []byte) {} -func (n noopParser) BasicString(b []byte) {} -func (n noopParser) Dot(b []byte) {} -func (n noopParser) Boolean(b []byte) {} -func (n noopParser) Equal(b []byte) {} +//type noopParser struct { +//} +// +//func (n noopParser) ArrayTableBegin() {} +//func (n noopParser) ArrayTableEnd() {} +//func (n noopParser) StandardTableBegin() {} +//func (n noopParser) StandardTableEnd() {} +//func (n noopParser) InlineTableSeparator() {} +//func (n noopParser) InlineTableBegin() {} +//func (n noopParser) InlineTableEnd() {} +//func (n noopParser) ArraySeparator() {} +//func (n noopParser) ArrayBegin() {} +//func (n noopParser) ArrayEnd() {} +//func (n noopParser) Whitespace(b []byte) {} +//func (n noopParser) Comment(b []byte) {} +//func (n noopParser) UnquotedKey(b []byte) {} +//func (n noopParser) LiteralString(b []byte) {} +//func (n noopParser) BasicString(b []byte) {} +//func (n noopParser) Dot(b []byte) {} +//func (n noopParser) Boolean(b []byte) {} +//func (n noopParser) Equal(b []byte) {} // //func BenchmarkParseAll(b *testing.B) {