terraform/vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/operators.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
}