diff --git a/deps.json b/deps.json index 1001f0137..b06dac335 100644 --- a/deps.json +++ b/deps.json @@ -9,6 +9,11 @@ "version": "8a44ce0c654efd505418bb2c341cb9b797020583", "type": "git" }, + "goconvey": { + "repo": "github.com/smartystreets/goconvey/convey", + "version": "master", + "type": "git" + }, "gocql": { "repo": "tux21b.org/v1/gocql", "version": "44eda643c1ae69e866e491b1c935c5b22e42350e", diff --git a/query/parser.go b/query/parser.go index ad77d8b5c..130b48bba 100644 --- a/query/parser.go +++ b/query/parser.go @@ -3,9 +3,104 @@ package query import ( "encoding/json" "errors" + "log" "pilosa/db" + "github.com/davecgh/go-spew/spew" ) +const ( + TYPE_FUNC = iota + TYPE_LP = iota + TYPE_RP = iota + TYPE_ID = iota +) + +type Token struct { + Text string + Type int +} + +type statefn func(lexer *Lexer) statefn + +type Lexer struct { + text string + pos int + start int + state int + ch chan Token +} + +func (lexer *Lexer) emit(typ int) { + lexer.ch <- Token{lexer.text[lexer.start:lexer.pos], typ} + lexer.start = lexer.pos +} + +func (lexer *Lexer) accept(char uint8) error { + for { + if lexer.text[lexer.pos] == char { + return nil + } + lexer.pos += 1 + if lexer.pos > len(lexer.text) { + return errors.New("Parse error, expecting " + string(char)) + } + } +} + +func stateFunc(lexer *Lexer) statefn { + err := lexer.accept('(') + if err != nil { + log.Fatal(err) + } + lexer.emit(TYPE_FUNC) + return stateLP +} + +func stateLP(lexer *Lexer) statefn { + lexer.pos += 1 + lexer.emit(TYPE_LP) + return stateID +} + +func stateID(lexer *Lexer) statefn { + err := lexer.accept(')') + if err != nil { + log.Fatal(err) + } + lexer.emit(TYPE_ID) + return stateRP +} + +func stateRP(lexer *Lexer) statefn { + lexer.pos += 1 + lexer.emit(TYPE_RP) + close(lexer.ch) + return nil +} + +func (lexer *Lexer) Lex() []Token{ + tokens := make([]Token, 0) + state := stateFunc + go func () { + for { + state = state(lexer) + if state == nil { + return + } + } + }() + for t := range lexer.ch { + spew.Dump(t) + tokens = append(tokens, t) + } + return tokens +} + +func Lex(input string) []Token { + lexer := Lexer{input, 0, 0, TYPE_FUNC, make(chan Token)} + return lexer.Lex() +} + var InvalidQueryError = errors.New("Invalid query format.") type QueryParser struct { diff --git a/query/parser_test.go b/query/parser_test.go new file mode 100644 index 000000000..772aab41c --- /dev/null +++ b/query/parser_test.go @@ -0,0 +1,21 @@ +package query + +import ( + "testing" + . "github.com/smartystreets/goconvey/convey" +) + +func TestParser(t *testing.T) { + Convey("Basic parsing", t, func() { + tokens := Lex("get(10)") + So(len(tokens), ShouldEqual, 4) + So(tokens[0].Text, ShouldEqual, "get") + So(tokens[0].Type, ShouldEqual, TYPE_FUNC) + So(tokens[1].Text, ShouldEqual, "(") + So(tokens[1].Type, ShouldEqual, TYPE_LP) + So(tokens[2].Text, ShouldEqual, "10") + So(tokens[2].Type, ShouldEqual, TYPE_ID) + So(tokens[3].Text, ShouldEqual, ")") + So(tokens[3].Type, ShouldEqual, TYPE_RP) + }) +}