pqarrays

Paddy 2015-04-19 Child:ce9c92fc81ab

0:bfe2a4af6bdf Go to Latest

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.

History
     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 +}