diff --git a/config/config_test.go b/config/config_test.go index 12bb08d4e..9357d3bcc 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -15,15 +15,15 @@ func TestConfig(t *testing.T) { So(Get("port_tcp").(int), ShouldEqual, 12000) So(Get("port_http").(int), ShouldEqual, 15000) So(Get("temp").(string), ShouldEqual, "/tmp") - So(Get("notfound"), ShouldEqual, nil) + So(Get("notfound"), ShouldBeNil) }) Convey("config.GetSafe()", t, func() { val, ok := GetSafe("port_tcp") - So(ok, ShouldEqual, true) + So(ok, ShouldBeTrue) So(val.(int), ShouldEqual, 12000) val, ok = GetSafe("derp") - So(ok, ShouldEqual, false) - So(val, ShouldEqual, nil) + So(ok, ShouldBeFalse) + So(val, ShouldBeNil) }) Convey("config.GetInt()", t, func() { So(GetInt("port_tcp"), ShouldEqual, 12000) diff --git a/deps.json b/deps.json index 1001f0137..73952003b 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", @@ -33,5 +38,10 @@ "repo": "github.com/yasushi-saito/rbtree", "version": "571e2538414bf914c7e2909b61217b4e3e5508f4", "type": "git" + }, + "spew": { + "repo": "github.com/davecgh/go-spew/spew", + "version": "e762b3d1320b76030bd7f6cc2bfc3d9acce874c0", + "type": "git" } } 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) + }) +}