mirror of
https://github.com/hanzoai/expr.git
synced 2026-09-24 16:58:58 +00:00
filter query grammar parity for expr
This commit is contained in:
+1777
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user