pqarrays
pqarrays/parser.go
Fix bug parsing empty arrays, make golint and go vet happy. Add comments to make golint happy. Also, because comments are a good thing to have. Turn += 1 and -= 1 into ++ and --, respectively, so golint will be happy. Fix an improperly formated errorf, where a rune was being treated as a string. Thanks, go vet! Fix whitespace parsing, returning the parse functions again instead of just skipping the one character. Now if we have more than one whitespace character in a row, they'll all be skipped. Add a parseStringOrNullOrEnd parse function that will be called after the tokenArrayStart character, to fix a bug where empty arrays were expecting a string or null and getting the array end character. This is only valid after tokenArrayStart, however; in other places where parseSeparatorOrDelim is used, it wouldn't be appropriate. Add a parser test for an empty array.
| paddy@0 | 1 package pqarrays |
| paddy@0 | 2 |
| paddy@0 | 3 import ( |
| paddy@0 | 4 "errors" |
| paddy@0 | 5 ) |
| paddy@0 | 6 |
| paddy@0 | 7 func parse(l *lexer) ([]*string, error) { |
| paddy@0 | 8 var parsed []*string |
| paddy@0 | 9 pchan := make(chan *string) |
| paddy@0 | 10 errchan := make(chan error) |
| paddy@0 | 11 done := make(chan struct{}) |
| paddy@0 | 12 go runParse(l, pchan, errchan, done) |
| paddy@0 | 13 for { |
| paddy@0 | 14 select { |
| paddy@0 | 15 case err := <-errchan: |
| paddy@0 | 16 return parsed, err |
| paddy@0 | 17 case item := <-pchan: |
| paddy@0 | 18 parsed = append(parsed, item) |
| paddy@0 | 19 case <-done: |
| paddy@0 | 20 return parsed, nil |
| paddy@0 | 21 } |
| paddy@0 | 22 } |
| paddy@0 | 23 } |
| paddy@0 | 24 |
| paddy@0 | 25 func runParse(l *lexer, parsed chan *string, err chan error, done chan struct{}) { |
| paddy@0 | 26 var state parseFunc = parseStart |
| paddy@0 | 27 for { |
| paddy@0 | 28 var e error |
| paddy@0 | 29 state, e = state(l, parsed) |
| paddy@0 | 30 if e != nil { |
| paddy@0 | 31 err <- e |
| paddy@0 | 32 break |
| paddy@0 | 33 } |
| paddy@0 | 34 if state == nil { |
| paddy@0 | 35 break |
| paddy@0 | 36 } |
| paddy@0 | 37 } |
| paddy@0 | 38 close(done) |
| paddy@0 | 39 } |
| paddy@0 | 40 |
| paddy@0 | 41 type parseFunc func(*lexer, chan *string) (parseFunc, error) |
| paddy@0 | 42 |
| paddy@0 | 43 func parseEOF(l *lexer, parsed chan *string) (parseFunc, error) { |
| paddy@0 | 44 tok := l.nextToken() |
| paddy@0 | 45 if tok.typ == tokenWhitespace { |
| paddy@1 | 46 return parseEOF, nil |
| paddy@0 | 47 } |
| paddy@0 | 48 if tok.typ != tokenEOF { |
| paddy@0 | 49 return nil, errors.New("expected EOF, got " + tok.typ.String()) |
| paddy@0 | 50 } |
| paddy@0 | 51 return nil, nil |
| paddy@0 | 52 } |
| paddy@0 | 53 |
| paddy@0 | 54 func parseStringOrNull(l *lexer, parsed chan *string) (parseFunc, error) { |
| paddy@0 | 55 tok := l.nextToken() |
| paddy@0 | 56 if tok.typ == tokenWhitespace { |
| paddy@1 | 57 return parseStringOrNull, nil |
| paddy@0 | 58 } else if tok.typ == tokenString { |
| paddy@0 | 59 parsed <- &tok.val |
| paddy@0 | 60 return parseSeparatorOrDelim, nil |
| paddy@0 | 61 } else if tok.typ == tokenNull { |
| paddy@0 | 62 parsed <- nil |
| paddy@0 | 63 return parseSeparatorOrDelim, nil |
| paddy@0 | 64 } |
| paddy@0 | 65 return nil, errors.New("expected string, got " + tok.typ.String()) |
| paddy@0 | 66 } |
| paddy@0 | 67 |
| paddy@1 | 68 func parseStringOrNullOrEnd(l *lexer, parsed chan *string) (parseFunc, error) { |
| paddy@1 | 69 tok := l.nextToken() |
| paddy@1 | 70 if tok.typ == tokenWhitespace { |
| paddy@1 | 71 return parseStringOrNullOrEnd, nil |
| paddy@1 | 72 } else if tok.typ == tokenString { |
| paddy@1 | 73 parsed <- &tok.val |
| paddy@1 | 74 return parseSeparatorOrDelim, nil |
| paddy@1 | 75 } else if tok.typ == tokenNull { |
| paddy@1 | 76 parsed <- nil |
| paddy@1 | 77 return parseSeparatorOrDelim, nil |
| paddy@1 | 78 } else if tok.typ == tokenArrayEnd { |
| paddy@1 | 79 return parseEOF, nil |
| paddy@1 | 80 } |
| paddy@1 | 81 return nil, errors.New("Expected string or end, got " + tok.typ.String()) |
| paddy@1 | 82 } |
| paddy@1 | 83 |
| paddy@0 | 84 func parseSeparatorOrDelim(l *lexer, parsed chan *string) (parseFunc, error) { |
| paddy@0 | 85 tok := l.nextToken() |
| paddy@0 | 86 if tok.typ == tokenWhitespace { |
| paddy@0 | 87 return parseSeparatorOrDelim, nil |
| paddy@0 | 88 } else if tok.typ == tokenSeparator { |
| paddy@0 | 89 return parseStringOrNull, nil |
| paddy@0 | 90 } else if tok.typ == tokenArrayEnd { |
| paddy@0 | 91 return parseEOF, nil |
| paddy@0 | 92 } |
| paddy@0 | 93 return nil, errors.New("expected separator or delim, got " + tok.typ.String()) |
| paddy@0 | 94 } |
| paddy@0 | 95 |
| paddy@0 | 96 func parseStart(l *lexer, parsed chan *string) (parseFunc, error) { |
| paddy@0 | 97 tok := l.nextToken() |
| paddy@0 | 98 if tok.typ == tokenWhitespace { |
| paddy@0 | 99 return parseStart, nil |
| paddy@0 | 100 } else if tok.typ == tokenArrayStart { |
| paddy@1 | 101 return parseStringOrNullOrEnd, nil |
| paddy@0 | 102 } |
| paddy@0 | 103 return nil, errors.New("expected separator or delim, got " + tok.typ.String()) |
| paddy@0 | 104 } |