1package execxp 2 3import ( 4 "fmt" 5 "math" 6 7 "github.com/ChrisTrenkamp/goxpath/tree" 8) 9 10func bothNodeOperator(left tree.NodeSet, right tree.NodeSet, f *xpFilt, op string) error { 11 var err error 12 for _, l := range left { 13 for _, r := range right { 14 lStr := l.ResValue() 15 rStr := r.ResValue() 16 17 if eqOps[op] { 18 err = equalsOperator(tree.String(lStr), tree.String(rStr), f, op) 19 if err == nil && f.ctx.String() == tree.True { 20 return nil 21 } 22 } else { 23 err = numberOperator(tree.String(lStr), tree.String(rStr), f, op) 24 if err == nil && f.ctx.String() == tree.True { 25 return nil 26 } 27 } 28 } 29 } 30 31 f.ctx = tree.Bool(false) 32 33 return nil 34} 35 36func leftNodeOperator(left tree.NodeSet, right tree.Result, f *xpFilt, op string) error { 37 var err error 38 for _, l := range left { 39 lStr := l.ResValue() 40 41 if eqOps[op] { 42 err = equalsOperator(tree.String(lStr), right, f, op) 43 if err == nil && f.ctx.String() == tree.True { 44 return nil 45 } 46 } else { 47 err = numberOperator(tree.String(lStr), right, f, op) 48 if err == nil && f.ctx.String() == tree.True { 49 return nil 50 } 51 } 52 } 53 54 f.ctx = tree.Bool(false) 55 56 return nil 57} 58 59func rightNodeOperator(left tree.Result, right tree.NodeSet, f *xpFilt, op string) error { 60 var err error 61 for _, r := range right { 62 rStr := r.ResValue() 63 64 if eqOps[op] { 65 err = equalsOperator(left, tree.String(rStr), f, op) 66 if err == nil && f.ctx.String() == "true" { 67 return nil 68 } 69 } else { 70 err = numberOperator(left, tree.String(rStr), f, op) 71 if err == nil && f.ctx.String() == "true" { 72 return nil 73 } 74 } 75 } 76 77 f.ctx = tree.Bool(false) 78 79 return nil 80} 81 82func equalsOperator(left, right tree.Result, f *xpFilt, op string) error { 83 _, lOK := left.(tree.Bool) 84 _, rOK := right.(tree.Bool) 85 86 if lOK || rOK { 87 lTest, lt := left.(tree.IsBool) 88 rTest, rt := right.(tree.IsBool) 89 if !lt || !rt { 90 return fmt.Errorf("Cannot convert argument to boolean") 91 } 92 93 if op == "=" { 94 f.ctx = tree.Bool(lTest.Bool() == rTest.Bool()) 95 } else { 96 f.ctx = tree.Bool(lTest.Bool() != rTest.Bool()) 97 } 98 99 return nil 100 } 101 102 _, lOK = left.(tree.Num) 103 _, rOK = right.(tree.Num) 104 if lOK || rOK { 105 return numberOperator(left, right, f, op) 106 } 107 108 lStr := left.String() 109 rStr := right.String() 110 111 if op == "=" { 112 f.ctx = tree.Bool(lStr == rStr) 113 } else { 114 f.ctx = tree.Bool(lStr != rStr) 115 } 116 117 return nil 118} 119 120func numberOperator(left, right tree.Result, f *xpFilt, op string) error { 121 lt, lOK := left.(tree.IsNum) 122 rt, rOK := right.(tree.IsNum) 123 if !lOK || !rOK { 124 return fmt.Errorf("Cannot convert data type to number") 125 } 126 127 ln, rn := lt.Num(), rt.Num() 128 129 switch op { 130 case "*": 131 f.ctx = ln * rn 132 case "div": 133 if rn != 0 { 134 f.ctx = ln / rn 135 } else { 136 if ln == 0 { 137 f.ctx = tree.Num(math.NaN()) 138 } else { 139 if math.Signbit(float64(ln)) == math.Signbit(float64(rn)) { 140 f.ctx = tree.Num(math.Inf(1)) 141 } else { 142 f.ctx = tree.Num(math.Inf(-1)) 143 } 144 } 145 } 146 case "mod": 147 f.ctx = tree.Num(int(ln) % int(rn)) 148 case "+": 149 f.ctx = ln + rn 150 case "-": 151 f.ctx = ln - rn 152 case "=": 153 f.ctx = tree.Bool(ln == rn) 154 case "!=": 155 f.ctx = tree.Bool(ln != rn) 156 case "<": 157 f.ctx = tree.Bool(ln < rn) 158 case "<=": 159 f.ctx = tree.Bool(ln <= rn) 160 case ">": 161 f.ctx = tree.Bool(ln > rn) 162 case ">=": 163 f.ctx = tree.Bool(ln >= rn) 164 } 165 166 return nil 167} 168 169func andOrOperator(left, right tree.Result, f *xpFilt, op string) error { 170 lt, lOK := left.(tree.IsBool) 171 rt, rOK := right.(tree.IsBool) 172 173 if !lOK || !rOK { 174 return fmt.Errorf("Cannot convert argument to boolean") 175 } 176 177 l, r := lt.Bool(), rt.Bool() 178 179 if op == "and" { 180 f.ctx = l && r 181 } else { 182 f.ctx = l || r 183 } 184 185 return nil 186} 187 188func unionOperator(left, right tree.Result, f *xpFilt, op string) error { 189 lNode, lOK := left.(tree.NodeSet) 190 rNode, rOK := right.(tree.NodeSet) 191 192 if !lOK || !rOK { 193 return fmt.Errorf("Cannot convert data type to node-set") 194 } 195 196 uniq := make(map[int]tree.Node) 197 for _, i := range lNode { 198 uniq[i.Pos()] = i 199 } 200 for _, i := range rNode { 201 uniq[i.Pos()] = i 202 } 203 204 res := make(tree.NodeSet, 0, len(uniq)) 205 for _, v := range uniq { 206 res = append(res, v) 207 } 208 209 f.ctx = res 210 211 return nil 212} 213