filter query grammar parity for expr

This commit is contained in:
srikanthccv
2025-10-03 07:34:13 +05:30
parent 6b6df6494c
commit 0319ec768c
13 changed files with 1830 additions and 31 deletions
+1777
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -46,7 +46,7 @@ func (n *ConstantNode) String() string {
func (n *UnaryNode) String() string {
op := n.Operator
if n.Operator == "not" {
if n.Operator == "not" || n.Operator == "NOT" {
op = fmt.Sprintf("%s ", n.Operator)
}
wrap := false
+6 -6
View File
@@ -291,7 +291,7 @@ func (v *Checker) unaryNode(node *ast.UnaryNode) Nature {
switch node.Operator {
case "!", "not":
case "!", "not", "NOT":
if nt.IsBool() {
return v.config.NtCache.FromType(boolType)
}
@@ -322,12 +322,12 @@ func (v *Checker) binaryNode(node *ast.BinaryNode) Nature {
r = r.Deref(&v.config.NtCache)
switch node.Operator {
case "==", "!=":
case "==", "!=", "=":
if l.ComparableTo(&v.config.NtCache, r) {
return v.config.NtCache.FromType(boolType)
}
case "or", "||", "and", "&&":
case "or", "||", "and", "&&", "OR", "AND":
if l.IsBool() && r.IsBool() {
return v.config.NtCache.FromType(boolType)
}
@@ -430,7 +430,7 @@ func (v *Checker) binaryNode(node *ast.BinaryNode) Nature {
return Nature{}
}
case "in":
case "in", "IN":
if (l.IsString() || l.IsUnknown(&v.config.NtCache)) && r.IsStruct() {
return v.config.NtCache.FromType(boolType)
}
@@ -455,7 +455,7 @@ func (v *Checker) binaryNode(node *ast.BinaryNode) Nature {
return v.config.NtCache.FromType(boolType)
}
case "matches":
case "matches", "regexp", "REGEXP":
if s, ok := node.Right.(*ast.StringNode); ok {
_, err := regexp.Compile(s.Value)
if err != nil {
@@ -469,7 +469,7 @@ func (v *Checker) binaryNode(node *ast.BinaryNode) Nature {
return v.config.NtCache.FromType(boolType)
}
case "contains", "startsWith", "endsWith":
case "contains", "startsWith", "endsWith", "CONTAINS":
if l.IsString() && r.IsString() {
return v.config.NtCache.FromType(boolType)
}
+7 -7
View File
@@ -422,7 +422,7 @@ func (c *compiler) UnaryNode(node *ast.UnaryNode) {
switch node.Operator {
case "!", "not":
case "!", "not", "NOT":
c.emit(OpNot)
case "+":
@@ -438,14 +438,14 @@ func (c *compiler) UnaryNode(node *ast.UnaryNode) {
func (c *compiler) BinaryNode(node *ast.BinaryNode) {
switch node.Operator {
case "==":
case "==", "=":
c.equalBinaryNode(node)
case "!=":
c.equalBinaryNode(node)
c.emit(OpNot)
case "or", "||":
case "or", "||", "OR":
c.compile(node.Left)
c.derefInNeeded(node.Left)
end := c.emit(OpJumpIfTrue, placeholder)
@@ -454,7 +454,7 @@ func (c *compiler) BinaryNode(node *ast.BinaryNode) {
c.derefInNeeded(node.Right)
c.patchJump(end)
case "and", "&&":
case "and", "&&", "AND":
c.compile(node.Left)
c.derefInNeeded(node.Left)
end := c.emit(OpJumpIfFalse, placeholder)
@@ -533,14 +533,14 @@ func (c *compiler) BinaryNode(node *ast.BinaryNode) {
c.derefInNeeded(node.Right)
c.emit(OpExponent)
case "in":
case "in", "IN":
c.compile(node.Left)
c.derefInNeeded(node.Left)
c.compile(node.Right)
c.derefInNeeded(node.Right)
c.emit(OpIn)
case "matches":
case "matches", "regexp", "REGEXP":
if str, ok := node.Right.(*ast.StringNode); ok {
re, err := regexp.Compile(str.Value)
if err != nil {
@@ -557,7 +557,7 @@ func (c *compiler) BinaryNode(node *ast.BinaryNode) {
c.emit(OpMatches)
}
case "contains":
case "contains", "CONTAINS":
c.compile(node.Left)
c.derefInNeeded(node.Left)
c.compile(node.Right)
+1 -1
View File
@@ -36,7 +36,7 @@ type Type struct {
}
var (
Operators = []string{"matches", "contains", "startsWith", "endsWith"}
Operators = []string{"matches", "regexp", "REGEXP", "contains", "CONTAINS", "startsWith", "endsWith"}
Builtins = map[Identifier]*Type{
"true": {Kind: "bool"},
"false": {Kind: "bool"},
+4 -4
View File
@@ -39,7 +39,7 @@ func (fold *fold) Visit(node *Node) {
if i, ok := n.Node.(*FloatNode); ok {
patch(&FloatNode{Value: i.Value})
}
case "!", "not":
case "!", "not", "NOT":
if a := toBool(n.Node); a != nil {
patch(&BoolNode{Value: !a.Value})
}
@@ -212,7 +212,7 @@ func (fold *fold) Visit(node *Node) {
patch(&FloatNode{Value: math.Pow(a.Value, b.Value)})
}
}
case "and", "&&":
case "and", "&&", "AND":
a := toBool(n.Left)
b := toBool(n.Right)
@@ -223,7 +223,7 @@ func (fold *fold) Visit(node *Node) {
} else if (a != nil && !a.Value) || (b != nil && !b.Value) { // "x and false" or "false and x"
patch(&BoolNode{Value: false})
}
case "or", "||":
case "or", "||", "OR":
a := toBool(n.Left)
b := toBool(n.Right)
@@ -234,7 +234,7 @@ func (fold *fold) Visit(node *Node) {
} else if (a != nil && a.Value) || (b != nil && b.Value) { // "x or true" or "true or x"
patch(&BoolNode{Value: true})
}
case "==":
case "==", "=":
{
a := toInteger(n.Left)
b := toInteger(n.Right)
+1 -1
View File
@@ -11,7 +11,7 @@ type inArray struct{}
func (*inArray) Visit(node *Node) {
switch n := (*node).(type) {
case *BinaryNode:
if n.Operator == "in" {
if n.Operator == "in" || n.Operator == "IN" {
if array, ok := n.Right.(*ArrayNode); ok {
if len(array.Nodes) > 0 {
t := n.Left.Type()
+1 -1
View File
@@ -11,7 +11,7 @@ type inRange struct{}
func (*inRange) Visit(node *Node) {
switch n := (*node).(type) {
case *BinaryNode:
if n.Operator == "in" {
if n.Operator == "in" || n.Operator == "IN" {
t := n.Left.Type()
if t == nil {
return
+5 -3
View File
@@ -45,16 +45,18 @@ func (v *predicateCombination) Visit(node *Node) {
func combinedOperator(fn, op string) (string, bool) {
switch {
case fn == "all" && (op == "and" || op == "&&"):
case fn == "all" && (op == "and" || op == "&&" || op == "AND"):
return op, true
case fn == "any" && (op == "or" || op == "||"):
case fn == "any" && (op == "or" || op == "||" || op == "OR"):
return op, true
case fn == "none" && (op == "and" || op == "&&"):
case fn == "none" && (op == "and" || op == "&&" || op == "AND"):
switch op {
case "and":
return "or", true
case "&&":
return "||", true
case "AND":
return "OR", true
}
}
return "", false
+3 -3
View File
@@ -127,9 +127,9 @@ loop:
default:
l.backup()
switch l.word() {
case "not":
case "not", "NOT":
return not
case "in", "or", "and", "matches", "contains", "startsWith", "endsWith", "let", "if", "else":
case "in", "IN", "or", "OR", "and", "AND", "matches", "regexp", "REGEXP", "contains", "CONTAINS", "startsWith", "endsWith", "let", "if", "else":
l.emit(Operator)
default:
l.emit(Identifier)
@@ -159,7 +159,7 @@ func not(l *Lexer) stateFn {
}
switch l.word() {
case "in", "matches", "contains", "startsWith", "endsWith":
case "in", "IN", "matches", "regexp", "REGEXP", "contains", "CONTAINS", "startsWith", "endsWith":
l.emit(Operator)
default:
l.end = end
+10 -2
View File
@@ -17,12 +17,12 @@ func Less(a, b string) bool {
}
func IsBoolean(op string) bool {
return op == "and" || op == "or" || op == "&&" || op == "||"
return op == "and" || op == "or" || op == "&&" || op == "||" || op == "AND" || op == "OR"
}
func AllowedNegateSuffix(op string) bool {
switch op {
case "contains", "matches", "startsWith", "endsWith", "in":
case "contains", "matches", "startsWith", "endsWith", "in", "IN", "regexp", "REGEXP", "CONTAINS":
return true
default:
return false
@@ -31,6 +31,7 @@ func AllowedNegateSuffix(op string) bool {
var Unary = map[string]Operator{
"not": {50, Left},
"NOT": {50, Left},
"!": {50, Left},
"-": {90, Left},
"+": {90, Left},
@@ -39,18 +40,25 @@ var Unary = map[string]Operator{
var Binary = map[string]Operator{
"|": {0, Left},
"or": {10, Left},
"OR": {10, Left},
"||": {10, Left},
"and": {15, Left},
"AND": {15, Left},
"&&": {15, Left},
"==": {20, Left},
"=": {20, Left},
"!=": {20, Left},
"<": {20, Left},
">": {20, Left},
">=": {20, Left},
"<=": {20, Left},
"in": {20, Left},
"IN": {20, Left},
"matches": {20, Left},
"regexp": {20, Left},
"REGEXP": {20, Left},
"contains": {20, Left},
"CONTAINS": {20, Left},
"startsWith": {20, Left},
"endsWith": {20, Left},
"..": {25, Left},
+1 -1
View File
@@ -227,7 +227,7 @@ func (p *Parser) parseExpression(precedence int) Node {
prevOperator := ""
opToken := p.current
for opToken.Is(Operator) && p.err == nil {
negate := opToken.Is(Operator, "not")
negate := opToken.Is(Operator, "not") || opToken.Is(Operator, "NOT")
var notToken Token
// Handle "not *" operator, like "not in" or "not contains".
+13 -1
View File
@@ -18,11 +18,15 @@ var (
builtins []string
operators = []string{
"or",
"OR",
"||",
"and",
"AND",
"&&",
"==",
"=",
"!=",
"<>",
"<",
">",
">=",
@@ -36,13 +40,21 @@ var (
"**",
"^",
"in",
"IN",
"matches",
"regexp",
"REGEXP",
"contains",
"CONTAINS",
"startsWith",
"endsWith",
"not in",
"NOT IN",
"not matches",
"not regexp",
"NOT REGEXP",
"not contains",
"NOT CONTAINS",
"not startsWith",
"not endsWith",
}
@@ -218,7 +230,7 @@ func memberNode(depth int) string {
}
func unaryNode(depth int) string {
return random([]string{"-", "!", "not"})
return random([]string{"-", "!", "not", "NOT"})
}
func binaryNode(depth int) string {