Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added not reserved keyword. Works for both not in and not like #68

Merged
merged 8 commits into from
Oct 15, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lexical/lexemes.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ const L_IN = "in"
const L_ASC = "asc"
const L_DESC = "desc"
const L_LIKE = "like"
const L_NOT = "not"
2 changes: 2 additions & 0 deletions lexical/lexical.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ func lexemeToToken(lexeme string) uint8 {
return T_DESC
case L_LIKE:
return T_LIKE
case L_NOT:
return T_NOT
}
return T_ID
}
Expand Down
5 changes: 4 additions & 1 deletion lexical/lexical_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func TestErrorUnrecognizeChar(t *testing.T) {

func TestReservedWords(t *testing.T) {
setUp()
source = "SELECT from WHEre in "
source = "SELECT from WHEre in not"
char = nextChar()

var token uint8
Expand All @@ -144,6 +144,9 @@ func TestReservedWords(t *testing.T) {
token, _ = Token()
assertToken(t, token, T_IN)

token, _ = Token()
assertToken(t, token, T_NOT)

token, _ = Token()
assertToken(t, token, T_EOF)
}
Expand Down
4 changes: 4 additions & 0 deletions lexical/tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ const T_PARENTH_R = 23
const T_IN = 24
const T_ASC = 25
const T_LIKE = 26
const T_NOT = 27
const T_NOT_OR_T_LIKE = 28
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did your Idea actually was T_IN_OR_T_LIKE, isn't? I'm not too comfortable seeing a token that is used just for error messages. I prefer to suggest just one of the options (T_NOT) and maybe we can discuss better in another thread how to improve the parser error to show more then one expected tokens. What do you think?

Copy link
Contributor Author

@frahman5 frahman5 Oct 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I wasn't too happy about that either. I didn't want to create an entirely different SyntaxError function though, so I squeezed in that token instead. I think you're right though. I'll change it to just suggest T_NOT for now, and we can leave the issue of leaving better parser errors for another day.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just letting you know I pushed another commit with this fix :)

const T_EOF = 0
const T_FUCK = 66

Expand Down Expand Up @@ -58,6 +60,8 @@ func allocMapTokenNames() {
T_IN: "T_IN",
T_EOF: "T_EOF",
T_ASC: "T_ASC",
T_NOT: "T_NOT",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these extra spaces only on github? otherwise, could you align them?

T_NOT_OR_T_LIKE: "T_NOT_OR_T_LIKE",
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions parser/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type NodeAdapterBinToConst struct {
type NodeIn struct {
leftValue NodeExpr
rightValue NodeExpr
Not bool
}

type NodeEqual struct {
Expand All @@ -73,6 +74,7 @@ type NodeLike struct {
leftValue NodeExpr
rightValue NodeExpr
Pattern *regexp.Regexp
Not bool
}

type NodeGreater struct {
Expand Down Expand Up @@ -129,6 +131,9 @@ func (e *NodeEmpty) Run() {
}

func (n *NodeIn) Assertion(lvalue string, rvalue string) bool {
if n.Not {
return !strings.Contains(rvalue, lvalue)
}
return strings.Contains(rvalue, lvalue)
}

Expand Down Expand Up @@ -210,6 +215,9 @@ func (n *NodeNotEqual) LeftValue() NodeExpr {

// LIKE
func (n *NodeLike) Assertion(lvalue string, rvalue string) bool {
if n.Not {
return !n.Pattern.MatchString(lvalue)
}
return n.Pattern.MatchString(lvalue)
}

Expand Down
17 changes: 16 additions & 1 deletion parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ func gWC3(eating bool) (NodeExpr, error) {
return expr, nil
}

// where cond 'equal', 'in', 'like' and 'not equal'
// where cond 'equal', 'in', 'not in', 'like', 'not like' and 'not equal'
func gWC4(eating bool) (NodeExpr, error) {
if eating {
token, err := lexical.Token()
Expand All @@ -355,6 +355,19 @@ func gWC4(eating bool) (NodeExpr, error) {
return nil, err
}

var notBool bool
if look_ahead == lexical.T_NOT {
notBool = true
token, err := lexical.Token()
if err != nil {
return nil, err
}
look_ahead = token
if look_ahead != lexical.T_LIKE && look_ahead != lexical.T_IN {
return nil, throwSyntaxError(lexical.T_NOT_OR_T_LIKE, look_ahead)
}
}

switch look_ahead {
case lexical.T_EQUAL:
op := new(NodeEqual)
Expand Down Expand Up @@ -387,6 +400,7 @@ func gWC4(eating bool) (NodeExpr, error) {
// we don't need to compile for every row
rx := strings.Replace(expr2.(*NodeLiteral).Value(), "%", "(.*)", -1)
op.Pattern, err2 = regexp.Compile(rx)
op.Not = notBool
return op, err2
case lexical.T_IN:
op := new(NodeIn)
Expand All @@ -396,6 +410,7 @@ func gWC4(eating bool) (NodeExpr, error) {
return nil, err2
}
op.SetRightValue(expr2)
op.Not = notBool
return op, nil
}

Expand Down
148 changes: 148 additions & 0 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,154 @@ func TestWhereWithNotEqualCompare(t *testing.T) {
}
}

func TestWhereWithIn(t *testing.T) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, thanks a lot for that ❤️

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:)

New("Select message from commits where 'react' in message")

ast, err := AST()
if err != nil {
t.Errorf(err.Error())
return
}

selectNode := ast.Child.(*NodeSelect)
w := selectNode.Where
if w == nil {
t.Errorf("should have where node")
}

if reflect.TypeOf(w) != reflect.TypeOf(new(NodeIn)) {
t.Errorf("should be a NodeIn")
}

notBool := w.(*NodeIn).Not
if notBool == true {
t.Errorf("Not bool should be set to false")
}

lValue := w.LeftValue().(*NodeLiteral)
rValue := w.RightValue().(*NodeId)
if lValue.Value() != "react" {
t.Errorf("LValue should be 'react'")
}

if rValue.Value() != "message" {
t.Errorf("RValue should be 'message'")
}



}

func TestWhereWithNotIn(t *testing.T) {
New("Select message from commits where 'react' not in message")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vue forever (?) 😆

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol


ast, err := AST()
if err != nil {
t.Errorf(err.Error())
return
}

selectNode := ast.Child.(*NodeSelect)
w := selectNode.Where
if w == nil {
t.Errorf("should have where node")
}

if reflect.TypeOf(w) != reflect.TypeOf(new(NodeIn)) {
t.Errorf("should be a NodeIn")
}

notBool := w.(*NodeIn).Not
if notBool == false {
t.Errorf("Not bool should be set to true")
}

lValue := w.LeftValue().(*NodeLiteral)
rValue := w.RightValue().(*NodeId)
if lValue.Value() != "react" {
t.Errorf("LValue should be 'react'")
}

if rValue.Value() != "message" {
t.Errorf("RValue should be 'message'")
}

}

func TestWhereWithLike(t *testing.T) {
New("Select author, message from commits where message like '%B'")

ast, err := AST()
if err != nil {
t.Errorf(err.Error())
return
}

selectNode := ast.Child.(*NodeSelect)
w := selectNode.Where
if w == nil {
t.Errorf("should have where node")
}

if reflect.TypeOf(w) != reflect.TypeOf(new(NodeLike)) {
t.Errorf("should be a NodeLike")
}

notBool := w.(*NodeLike).Not
if notBool == true {
t.Errorf("Not bool should be set to false")
}

lValue := w.LeftValue().(*NodeId)
rValue := w.RightValue().(*NodeLiteral)
if lValue.Value() != "message" {
t.Errorf("LValue should be 'message'")
}

es := `Rvalue should be &B`
if rValue.Value() != "%B" {
t.Errorf(es)
}

}

func TestWhereWithNotLike(t *testing.T) {
New("Select author, message from commits where message not like '%B'")

ast, err := AST()
if err != nil {
t.Errorf(err.Error())
return
}

selectNode := ast.Child.(*NodeSelect)
w := selectNode.Where
if w == nil {
t.Errorf("should have where node")
}

if reflect.TypeOf(w) != reflect.TypeOf(new(NodeLike)) {
t.Errorf("should be a NodeLike")
}

notBool := w.(*NodeLike).Not
if notBool == false {
t.Errorf("Not bool should be set to true")
}

lValue := w.LeftValue().(*NodeId)
rValue := w.RightValue().(*NodeLiteral)
if lValue.Value() != "message" {
t.Errorf("LValue should be 'message'")
}

es := `Rvalue should be &B`
if rValue.Value() != "%B" {
t.Errorf(es)
}

}

func TestWhereWithGreater(t *testing.T) {
New("select * from commits where date > '2014-05-12 00:00:00' ")

Expand Down