Skip to content

Commit

Permalink
Fixes #94: Remove redundant recursion that leads to stack overflow
Browse files Browse the repository at this point in the history
  • Loading branch information
nelio2k committed Feb 26, 2019
1 parent 302ae79 commit fd9673b
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 19 deletions.
15 changes: 3 additions & 12 deletions filterExprParser.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (

// FilterExpression = ( AndCondition { "OR" AndCondition } ) { "AND" FilterExpression }
// AndCondition = { OpenParens } Condition { "AND" Condition } { CloseParen }
// Condition = ( [ "NOT" ] Condition ) | Operand | FilterExpression
// Condition = ( [ "NOT" ] Condition ) | Operand
// Operand = BooleanExpr | ( LHS ( CheckOp | ( CompareOp RHS) ) )
// BooleanExpr = Boolean | BooleanFuncExpr
// LHS = ConstFuncExpr | Boolean | Field | Value
Expand Down Expand Up @@ -214,16 +214,13 @@ func (f *FEAndCondition) OutputExpression() (Expression, error) {
}

type FECondition struct {
Not *FECondition `"NOT" @@`
Operand *FEOperand `| @@`
SubExpr *FilterExpression `| @@`
Not *FECondition `"NOT" @@`
Operand *FEOperand `| @@`
}

func (f *FECondition) GetTotalOpenParens() (count int) {
if f.Not != nil {
count += f.Not.GetTotalOpenParens()
} else if f.SubExpr != nil {
count += f.SubExpr.GetTotalOpenParens()
}
// Operand has no open or close parens
return
Expand All @@ -232,8 +229,6 @@ func (f *FECondition) GetTotalOpenParens() (count int) {
func (f *FECondition) GetTotalCloseParens() (count int) {
if f.Not != nil {
count += f.Not.GetTotalCloseParens()
} else if f.SubExpr != nil {
count += f.SubExpr.GetTotalCloseParens()
}
// Operand has no open or close parens
return
Expand All @@ -246,8 +241,6 @@ func (fec *FECondition) String() string {
outputStr = append(outputStr, fmt.Sprintf("%v %v", OperatorNot, fec.Not.String()))
} else if fec.Operand != nil {
outputStr = append(outputStr, fec.Operand.String())
} else if fec.SubExpr != nil {
outputStr = append(outputStr, fec.SubExpr.String())
} else {
outputStr = append(outputStr, "?? (FECondition)")
}
Expand All @@ -261,8 +254,6 @@ func (f *FECondition) OutputExpression() (Expression, error) {
return NotExpr{subNot}, err
} else if f.Operand != nil {
return f.Operand.OutputExpression()
} else if f.SubExpr != nil {
return f.SubExpr.OutputExpression()
} else {
return nil, fmt.Errorf("Invalid FECondition %v", f.String())
}
Expand Down
31 changes: 24 additions & 7 deletions filterExprParser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,13 +93,14 @@ func TestFilterExpressionParser(t *testing.T) {
fe = &FilterExpression{}
err = parser.ParseString("TRUE AND (TRUE OR FALSE) AND FALSE", fe)
assert.Nil(err)
assert.Equal(1, len(fe.AndConditions))
assert.Equal(2, len(fe.AndConditions[0].OrConditions))
assert.Nil(fe.AndConditions[0].OrConditions[0].SubExpr) // TRUE (AND...)
assert.NotNil(fe.AndConditions[0].OrConditions[1].SubExpr)
assert.Equal(2, len(fe.AndConditions[0].OrConditions[1].SubExpr.AndConditions)) // (TRUE OR FALSE) AND FALSE
assert.Equal(1, len(fe.AndConditions[0].OrConditions[1].SubExpr.AndConditions[0].OrConditions)) // (TRUE OR FALSE)
assert.Equal(1, len(fe.AndConditions[0].OrConditions[1].SubExpr.AndConditions[1].OrConditions)) // FALSE
assert.Equal(1, len(fe.AndConditions)) // TRUE (AND...)
assert.Equal(1, len(fe.SubFilterExpr)) // (TRUE OR FALSE) AND FALSE
assert.Equal(2, len(fe.SubFilterExpr[0].AndConditions)) // (TRUE OR FALSE) (AND...)
assert.Equal(1, len(fe.SubFilterExpr[0].AndConditions[0].OrConditions))
assert.Equal(1, len(fe.SubFilterExpr[0].AndConditions[1].OrConditions))
assert.Equal(1, len(fe.SubFilterExpr[0].SubFilterExpr)) // FALSE
assert.Equal(1, len(fe.SubFilterExpr[0].SubFilterExpr[0].AndConditions))
assert.Equal(0, len(fe.SubFilterExpr[0].SubFilterExpr[0].SubFilterExpr))
expr, err = fe.OutputExpression()
assert.Nil(err)

Expand Down Expand Up @@ -581,4 +582,20 @@ func TestFilterExpressionParser(t *testing.T) {
fe = &FilterExpression{}
err = parser.ParseString("achievement * 2 +1", fe)
assert.NotNil(err)

// Typos
_, _, err = NewFilterExpressionParser("REGEX_CONTAINS(KEY, \"something\")")
assert.NotNil(err)
_, _, err = NewFilterExpressionParser("REGEXP_CONTAINS(METAS().id, \"something\")")
assert.NotNil(err)
_, _, err = NewFilterExpressionParser("REGEXP_CONTAINS(METAS().ID(), \"something\")")
assert.NotNil(err)

// Unfinished
_, _, err = NewFilterExpressionParser("REGEX_CONTAINS(KEY, \"something\") AND OR")
assert.NotNil(err)
_, _, err = NewFilterExpressionParser("REGEXP_CONTAINS(METAS().ID(), \"something)")
assert.NotNil(err)
_, _, err = NewFilterExpressionParser("`field is unfinished = \"unfinished_value")
assert.NotNil(err)
}

0 comments on commit fd9673b

Please sign in to comment.