pqarrays
2015-04-19
Child:ce9c92fc81ab
pqarrays/parser.go
First pass implementation. Use a lexer to generate tokens out of the Array type responses that PostgreSQL will send. Write a parser for string[] array types. Create a StringArray type that fulfills the driver.Valuer and sql.Scanner interfaces using the parser and lexer.
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/parser.go Sun Apr 19 23:47:36 2015 -0400 1.3 @@ -0,0 +1,88 @@ 1.4 +package pqarrays 1.5 + 1.6 +import ( 1.7 + "errors" 1.8 +) 1.9 + 1.10 +func parse(l *lexer) ([]*string, error) { 1.11 + var parsed []*string 1.12 + pchan := make(chan *string) 1.13 + errchan := make(chan error) 1.14 + done := make(chan struct{}) 1.15 + go runParse(l, pchan, errchan, done) 1.16 + for { 1.17 + select { 1.18 + case err := <-errchan: 1.19 + return parsed, err 1.20 + case item := <-pchan: 1.21 + parsed = append(parsed, item) 1.22 + case <-done: 1.23 + return parsed, nil 1.24 + } 1.25 + } 1.26 +} 1.27 + 1.28 +func runParse(l *lexer, parsed chan *string, err chan error, done chan struct{}) { 1.29 + var state parseFunc = parseStart 1.30 + for { 1.31 + var e error 1.32 + state, e = state(l, parsed) 1.33 + if e != nil { 1.34 + err <- e 1.35 + break 1.36 + } 1.37 + if state == nil { 1.38 + break 1.39 + } 1.40 + } 1.41 + close(done) 1.42 +} 1.43 + 1.44 +type parseFunc func(*lexer, chan *string) (parseFunc, error) 1.45 + 1.46 +func parseEOF(l *lexer, parsed chan *string) (parseFunc, error) { 1.47 + tok := l.nextToken() 1.48 + if tok.typ == tokenWhitespace { 1.49 + tok = l.nextToken() 1.50 + } 1.51 + if tok.typ != tokenEOF { 1.52 + return nil, errors.New("expected EOF, got " + tok.typ.String()) 1.53 + } 1.54 + return nil, nil 1.55 +} 1.56 + 1.57 +func parseStringOrNull(l *lexer, parsed chan *string) (parseFunc, error) { 1.58 + tok := l.nextToken() 1.59 + if tok.typ == tokenWhitespace { 1.60 + tok = l.nextToken() 1.61 + } else if tok.typ == tokenString { 1.62 + parsed <- &tok.val 1.63 + return parseSeparatorOrDelim, nil 1.64 + } else if tok.typ == tokenNull { 1.65 + parsed <- nil 1.66 + return parseSeparatorOrDelim, nil 1.67 + } 1.68 + return nil, errors.New("expected string, got " + tok.typ.String()) 1.69 +} 1.70 + 1.71 +func parseSeparatorOrDelim(l *lexer, parsed chan *string) (parseFunc, error) { 1.72 + tok := l.nextToken() 1.73 + if tok.typ == tokenWhitespace { 1.74 + return parseSeparatorOrDelim, nil 1.75 + } else if tok.typ == tokenSeparator { 1.76 + return parseStringOrNull, nil 1.77 + } else if tok.typ == tokenArrayEnd { 1.78 + return parseEOF, nil 1.79 + } 1.80 + return nil, errors.New("expected separator or delim, got " + tok.typ.String()) 1.81 +} 1.82 + 1.83 +func parseStart(l *lexer, parsed chan *string) (parseFunc, error) { 1.84 + tok := l.nextToken() 1.85 + if tok.typ == tokenWhitespace { 1.86 + return parseStart, nil 1.87 + } else if tok.typ == tokenArrayStart { 1.88 + return parseStringOrNull, nil 1.89 + } 1.90 + return nil, errors.New("expected separator or delim, got " + tok.typ.String()) 1.91 +}