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