213 lines
4.0 KiB
Go
213 lines
4.0 KiB
Go
package execxp
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
|
|
"github.com/ChrisTrenkamp/goxpath/tree"
|
|
)
|
|
|
|
func bothNodeOperator(left tree.NodeSet, right tree.NodeSet, f *xpFilt, op string) error {
|
|
var err error
|
|
for _, l := range left {
|
|
for _, r := range right {
|
|
lStr := l.ResValue()
|
|
rStr := r.ResValue()
|
|
|
|
if eqOps[op] {
|
|
err = equalsOperator(tree.String(lStr), tree.String(rStr), f, op)
|
|
if err == nil && f.ctx.String() == tree.True {
|
|
return nil
|
|
}
|
|
} else {
|
|
err = numberOperator(tree.String(lStr), tree.String(rStr), f, op)
|
|
if err == nil && f.ctx.String() == tree.True {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
f.ctx = tree.Bool(false)
|
|
|
|
return nil
|
|
}
|
|
|
|
func leftNodeOperator(left tree.NodeSet, right tree.Result, f *xpFilt, op string) error {
|
|
var err error
|
|
for _, l := range left {
|
|
lStr := l.ResValue()
|
|
|
|
if eqOps[op] {
|
|
err = equalsOperator(tree.String(lStr), right, f, op)
|
|
if err == nil && f.ctx.String() == tree.True {
|
|
return nil
|
|
}
|
|
} else {
|
|
err = numberOperator(tree.String(lStr), right, f, op)
|
|
if err == nil && f.ctx.String() == tree.True {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
f.ctx = tree.Bool(false)
|
|
|
|
return nil
|
|
}
|
|
|
|
func rightNodeOperator(left tree.Result, right tree.NodeSet, f *xpFilt, op string) error {
|
|
var err error
|
|
for _, r := range right {
|
|
rStr := r.ResValue()
|
|
|
|
if eqOps[op] {
|
|
err = equalsOperator(left, tree.String(rStr), f, op)
|
|
if err == nil && f.ctx.String() == "true" {
|
|
return nil
|
|
}
|
|
} else {
|
|
err = numberOperator(left, tree.String(rStr), f, op)
|
|
if err == nil && f.ctx.String() == "true" {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
f.ctx = tree.Bool(false)
|
|
|
|
return nil
|
|
}
|
|
|
|
func equalsOperator(left, right tree.Result, f *xpFilt, op string) error {
|
|
_, lOK := left.(tree.Bool)
|
|
_, rOK := right.(tree.Bool)
|
|
|
|
if lOK || rOK {
|
|
lTest, lt := left.(tree.IsBool)
|
|
rTest, rt := right.(tree.IsBool)
|
|
if !lt || !rt {
|
|
return fmt.Errorf("Cannot convert argument to boolean")
|
|
}
|
|
|
|
if op == "=" {
|
|
f.ctx = tree.Bool(lTest.Bool() == rTest.Bool())
|
|
} else {
|
|
f.ctx = tree.Bool(lTest.Bool() != rTest.Bool())
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
_, lOK = left.(tree.Num)
|
|
_, rOK = right.(tree.Num)
|
|
if lOK || rOK {
|
|
return numberOperator(left, right, f, op)
|
|
}
|
|
|
|
lStr := left.String()
|
|
rStr := right.String()
|
|
|
|
if op == "=" {
|
|
f.ctx = tree.Bool(lStr == rStr)
|
|
} else {
|
|
f.ctx = tree.Bool(lStr != rStr)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func numberOperator(left, right tree.Result, f *xpFilt, op string) error {
|
|
lt, lOK := left.(tree.IsNum)
|
|
rt, rOK := right.(tree.IsNum)
|
|
if !lOK || !rOK {
|
|
return fmt.Errorf("Cannot convert data type to number")
|
|
}
|
|
|
|
ln, rn := lt.Num(), rt.Num()
|
|
|
|
switch op {
|
|
case "*":
|
|
f.ctx = ln * rn
|
|
case "div":
|
|
if rn != 0 {
|
|
f.ctx = ln / rn
|
|
} else {
|
|
if ln == 0 {
|
|
f.ctx = tree.Num(math.NaN())
|
|
} else {
|
|
if math.Signbit(float64(ln)) == math.Signbit(float64(rn)) {
|
|
f.ctx = tree.Num(math.Inf(1))
|
|
} else {
|
|
f.ctx = tree.Num(math.Inf(-1))
|
|
}
|
|
}
|
|
}
|
|
case "mod":
|
|
f.ctx = tree.Num(int(ln) % int(rn))
|
|
case "+":
|
|
f.ctx = ln + rn
|
|
case "-":
|
|
f.ctx = ln - rn
|
|
case "=":
|
|
f.ctx = tree.Bool(ln == rn)
|
|
case "!=":
|
|
f.ctx = tree.Bool(ln != rn)
|
|
case "<":
|
|
f.ctx = tree.Bool(ln < rn)
|
|
case "<=":
|
|
f.ctx = tree.Bool(ln <= rn)
|
|
case ">":
|
|
f.ctx = tree.Bool(ln > rn)
|
|
case ">=":
|
|
f.ctx = tree.Bool(ln >= rn)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func andOrOperator(left, right tree.Result, f *xpFilt, op string) error {
|
|
lt, lOK := left.(tree.IsBool)
|
|
rt, rOK := right.(tree.IsBool)
|
|
|
|
if !lOK || !rOK {
|
|
return fmt.Errorf("Cannot convert argument to boolean")
|
|
}
|
|
|
|
l, r := lt.Bool(), rt.Bool()
|
|
|
|
if op == "and" {
|
|
f.ctx = l && r
|
|
} else {
|
|
f.ctx = l || r
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func unionOperator(left, right tree.Result, f *xpFilt, op string) error {
|
|
lNode, lOK := left.(tree.NodeSet)
|
|
rNode, rOK := right.(tree.NodeSet)
|
|
|
|
if !lOK || !rOK {
|
|
return fmt.Errorf("Cannot convert data type to node-set")
|
|
}
|
|
|
|
uniq := make(map[int]tree.Node)
|
|
for _, i := range lNode {
|
|
uniq[i.Pos()] = i
|
|
}
|
|
for _, i := range rNode {
|
|
uniq[i.Pos()] = i
|
|
}
|
|
|
|
res := make(tree.NodeSet, 0, len(uniq))
|
|
for _, v := range uniq {
|
|
res = append(res, v)
|
|
}
|
|
|
|
f.ctx = res
|
|
|
|
return nil
|
|
}
|