2 // XQueryArithmeticOperator.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System
.Collections
;
33 using System
.Reflection
;
35 using System
.Xml
.Schema
;
36 using System
.Xml
.Query
;
37 using System
.Xml
.XPath
;
41 namespace Mono
.Xml
.XPath2
43 // FIXME: Handle complete type promotion and subtype substitution.
44 // See XQuery 1.0 Appendix B.*.
45 public class XQueryArithmeticOperator
50 public static XPathAtomicValue
Add (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
52 // numeric, date, time, dateTime, yearMonthDuration, dayTimeDuration
53 switch (lvalue
.XmlType
.TypeCode
) {
56 case XmlTypeCode
.Integer
:
57 switch (rvalue
.XmlType
.TypeCode
) {
58 case XmlTypeCode
.Integer
:
59 return new XPathAtomicValue (lvalue
.ValueAsInt64
+ rvalue
.ValueAsInt64
, rvalue
.XmlType
);
60 case XmlTypeCode
.Decimal
:
61 return new XPathAtomicValue (lvalue
.ValueAsDecimal
+ rvalue
.ValueAsDecimal
, rvalue
.XmlType
);
62 case XmlTypeCode
.Float
:
63 case XmlTypeCode
.Double
:
64 return new XPathAtomicValue (lvalue
.ValueAsDouble
+ rvalue
.ValueAsDouble
, rvalue
.XmlType
);
68 case XmlTypeCode
.Decimal
:
69 switch (rvalue
.XmlType
.TypeCode
) {
70 case XmlTypeCode
.Integer
:
71 case XmlTypeCode
.Decimal
:
72 return new XPathAtomicValue (lvalue
.ValueAsDecimal
+ rvalue
.ValueAsDecimal
, rvalue
.XmlType
);
73 case XmlTypeCode
.Float
:
74 case XmlTypeCode
.Double
:
75 return new XPathAtomicValue (lvalue
.ValueAsDouble
+ rvalue
.ValueAsDouble
, rvalue
.XmlType
);
79 case XmlTypeCode
.Float
:
80 case XmlTypeCode
.Double
:
81 switch (rvalue
.XmlType
.TypeCode
) {
82 case XmlTypeCode
.Integer
:
83 case XmlTypeCode
.Decimal
:
84 case XmlTypeCode
.Float
:
85 case XmlTypeCode
.Double
:
86 return new XPathAtomicValue (lvalue
.ValueAsDouble
+ rvalue
.ValueAsDouble
, rvalue
.XmlType
);
91 case XmlTypeCode
.Time
:
92 if (rvalue
.XmlType
.TypeCode
== XmlTypeCode
.DayTimeDuration
)
93 goto case XmlTypeCode
.DateTime
;
95 case XmlTypeCode
.DateTime
:
96 case XmlTypeCode
.Date
:
97 switch (rvalue
.XmlType
.TypeCode
) {
98 case XmlTypeCode
.YearMonthDuration
:
99 case XmlTypeCode
.DayTimeDuration
:
100 return new XPathAtomicValue (lvalue
.ValueAsDateTime
+ new TimeSpan (rvalue
.ValueAsDateTime
.Ticks
), lvalue
.XmlType
);
104 case XmlTypeCode
.YearMonthDuration
:
105 switch (rvalue
.XmlType
.TypeCode
) {
106 case XmlTypeCode
.Date
:
107 case XmlTypeCode
.DateTime
:
108 return new XPathAtomicValue (lvalue
.ValueAsDateTime
+ new TimeSpan (rvalue
.ValueAsDateTime
.Ticks
), rvalue
.XmlType
);
109 case XmlTypeCode
.YearMonthDuration
:
110 return new XPathAtomicValue (new DateTime (lvalue
.ValueAsDateTime
.Ticks
+ rvalue
.ValueAsDateTime
.Ticks
), InternalPool
.XdtYearMonthDuration
);
113 case XmlTypeCode
.DayTimeDuration
:
114 switch (rvalue
.XmlType
.TypeCode
) {
115 case XmlTypeCode
.Date
:
116 case XmlTypeCode
.Time
:
117 case XmlTypeCode
.DateTime
:
118 return new XPathAtomicValue (lvalue
.ValueAsDateTime
+ new TimeSpan (rvalue
.ValueAsDateTime
.Ticks
), rvalue
.XmlType
);
119 case XmlTypeCode
.DayTimeDuration
:
120 return new XPathAtomicValue (new DateTime (lvalue
.ValueAsDateTime
.Ticks
+ rvalue
.ValueAsDateTime
.Ticks
), InternalPool
.XdtDayTimeDuration
);
125 throw new XmlQueryException (String
.Format ("Not allowed arithmetic operation: {0} + {1}", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
131 public static XPathAtomicValue
Subtract (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
133 // numeric, date, time, dateTime, yearMonthDuration, dayTimeDuration
134 switch (lvalue
.XmlType
.TypeCode
) {
137 case XmlTypeCode
.Integer
:
138 switch (rvalue
.XmlType
.TypeCode
) {
139 case XmlTypeCode
.Integer
:
140 return new XPathAtomicValue (lvalue
.ValueAsInt64
- rvalue
.ValueAsInt64
, rvalue
.XmlType
);
141 case XmlTypeCode
.Decimal
:
142 return new XPathAtomicValue (lvalue
.ValueAsDecimal
- rvalue
.ValueAsDecimal
, rvalue
.XmlType
);
143 case XmlTypeCode
.Float
:
144 case XmlTypeCode
.Double
:
145 return new XPathAtomicValue (lvalue
.ValueAsDouble
- rvalue
.ValueAsDouble
, rvalue
.XmlType
);
149 case XmlTypeCode
.Decimal
:
150 switch (rvalue
.XmlType
.TypeCode
) {
151 case XmlTypeCode
.Integer
:
152 case XmlTypeCode
.Decimal
:
153 return new XPathAtomicValue (lvalue
.ValueAsDecimal
- rvalue
.ValueAsDecimal
, rvalue
.XmlType
);
154 case XmlTypeCode
.Float
:
155 case XmlTypeCode
.Double
:
156 return new XPathAtomicValue (lvalue
.ValueAsDouble
- rvalue
.ValueAsDouble
, rvalue
.XmlType
);
160 case XmlTypeCode
.Float
:
161 case XmlTypeCode
.Double
:
162 switch (rvalue
.XmlType
.TypeCode
) {
163 case XmlTypeCode
.Integer
:
164 case XmlTypeCode
.Decimal
:
165 case XmlTypeCode
.Float
:
166 case XmlTypeCode
.Double
:
167 return new XPathAtomicValue (lvalue
.ValueAsDouble
- rvalue
.ValueAsDouble
, rvalue
.XmlType
);
172 case XmlTypeCode
.Time
:
173 switch (rvalue
.XmlType
.TypeCode
) {
174 case XmlTypeCode
.Time
:
175 return new XPathAtomicValue (lvalue
.ValueAsDateTime
- rvalue
.ValueAsDateTime
, InternalPool
.XdtDayTimeDuration
);
176 case XmlTypeCode
.DayTimeDuration
:
177 return new XPathAtomicValue (lvalue
.ValueAsDateTime
- new TimeSpan (rvalue
.ValueAsDateTime
.Ticks
), lvalue
.XmlType
);
181 case XmlTypeCode
.DateTime
:
182 switch (rvalue
.XmlType
.TypeCode
) {
183 case XmlTypeCode
.DateTime
:
184 // FIXME: check fn:subtract-daytimes-yielding-dayTimeDuration()
185 return new XPathAtomicValue (lvalue
.ValueAsDateTime
- rvalue
.ValueAsDateTime
, InternalPool
.XdtDayTimeDuration
);
186 case XmlTypeCode
.YearMonthDuration
:
187 case XmlTypeCode
.DayTimeDuration
:
188 return new XPathAtomicValue (lvalue
.ValueAsDateTime
- new TimeSpan (rvalue
.ValueAsDateTime
.Ticks
), lvalue
.XmlType
);
192 case XmlTypeCode
.Date
:
193 switch (rvalue
.XmlType
.TypeCode
) {
194 case XmlTypeCode
.Date
:
195 // FIXME: check fn:subtract-daytimes-yielding-dayTimeDuration()
196 return new XPathAtomicValue (lvalue
.ValueAsDateTime
- rvalue
.ValueAsDateTime
, InternalPool
.XdtDayTimeDuration
);
197 case XmlTypeCode
.YearMonthDuration
:
198 case XmlTypeCode
.DayTimeDuration
:
199 return new XPathAtomicValue (lvalue
.ValueAsDateTime
- new TimeSpan (rvalue
.ValueAsDateTime
.Ticks
), lvalue
.XmlType
);
204 case XmlTypeCode
.YearMonthDuration
:
205 if (rvalue
.XmlType
.TypeCode
== XmlTypeCode
.YearMonthDuration
)
206 return new XPathAtomicValue (new TimeSpan (lvalue
.ValueAsDateTime
.Ticks
- rvalue
.ValueAsDateTime
.Ticks
), InternalPool
.XdtYearMonthDuration
);
208 case XmlTypeCode
.DayTimeDuration
:
209 if (rvalue
.XmlType
.TypeCode
== XmlTypeCode
.DayTimeDuration
)
210 return new XPathAtomicValue (new TimeSpan (lvalue
.ValueAsDateTime
.Ticks
- rvalue
.ValueAsDateTime
.Ticks
), InternalPool
.XdtDayTimeDuration
);
214 throw new XmlQueryException (String
.Format ("Not allowed arithmetic operation: {0} - {1}", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
220 public static XPathAtomicValue
Multiply (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
222 // numeric, date, time, dateTime, yearMonthDuration, dayTimeDuration
223 switch (lvalue
.XmlType
.TypeCode
) {
226 case XmlTypeCode
.Integer
:
227 switch (rvalue
.XmlType
.TypeCode
) {
228 case XmlTypeCode
.Integer
:
229 return new XPathAtomicValue (lvalue
.ValueAsInt64
* rvalue
.ValueAsInt64
, rvalue
.XmlType
);
230 case XmlTypeCode
.Decimal
:
231 return new XPathAtomicValue (lvalue
.ValueAsDecimal
* rvalue
.ValueAsDecimal
, rvalue
.XmlType
);
232 case XmlTypeCode
.Float
:
233 case XmlTypeCode
.Double
:
234 return new XPathAtomicValue (lvalue
.ValueAsDouble
* rvalue
.ValueAsDouble
, rvalue
.XmlType
);
236 case XmlTypeCode
.DayTimeDuration
:
237 case XmlTypeCode
.YearMonthDuration
:
238 goto case XmlTypeCode
.Decimal
;
242 case XmlTypeCode
.Decimal
:
243 switch (rvalue
.XmlType
.TypeCode
) {
244 case XmlTypeCode
.Integer
:
245 case XmlTypeCode
.Decimal
:
246 return new XPathAtomicValue (lvalue
.ValueAsDecimal
* rvalue
.ValueAsDecimal
, rvalue
.XmlType
);
247 case XmlTypeCode
.Float
:
248 case XmlTypeCode
.Double
:
249 return new XPathAtomicValue (lvalue
.ValueAsDouble
* rvalue
.ValueAsDouble
, rvalue
.XmlType
);
251 case XmlTypeCode
.YearMonthDuration
:
252 case XmlTypeCode
.DayTimeDuration
:
253 return new XPathAtomicValue (new TimeSpan ((long) (lvalue
.ValueAsDateTime
.Ticks
* rvalue
.ValueAsDecimal
)), rvalue
.XmlType
);
257 case XmlTypeCode
.Float
:
258 case XmlTypeCode
.Double
:
259 switch (rvalue
.XmlType
.TypeCode
) {
260 case XmlTypeCode
.Integer
:
261 case XmlTypeCode
.Decimal
:
262 case XmlTypeCode
.Float
:
263 case XmlTypeCode
.Double
:
264 return new XPathAtomicValue (lvalue
.ValueAsDouble
* rvalue
.ValueAsDouble
, rvalue
.XmlType
);
266 case XmlTypeCode
.DayTimeDuration
:
267 case XmlTypeCode
.YearMonthDuration
:
268 goto case XmlTypeCode
.Decimal
;
273 case XmlTypeCode
.DayTimeDuration
:
274 case XmlTypeCode
.YearMonthDuration
:
275 switch (rvalue
.XmlType
.TypeCode
) {
276 case XmlTypeCode
.Integer
:
277 case XmlTypeCode
.Decimal
:
278 case XmlTypeCode
.Float
:
279 case XmlTypeCode
.Double
:
280 return Multiply (rvalue
, lvalue
);
285 throw new XmlQueryException (String
.Format ("Not allowed arithmetic operation: {0} * {1}", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
291 public static XPathAtomicValue
Divide (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
293 // numeric, date, time, dateTime, yearMonthDuration, dayTimeDuration
294 switch (lvalue
.XmlType
.TypeCode
) {
297 case XmlTypeCode
.Integer
:
298 switch (rvalue
.XmlType
.TypeCode
) {
299 case XmlTypeCode
.Integer
:
300 return new XPathAtomicValue (lvalue
.ValueAsInt64
/ rvalue
.ValueAsInt64
, rvalue
.XmlType
);
301 case XmlTypeCode
.Decimal
:
302 return new XPathAtomicValue (lvalue
.ValueAsDecimal
/ rvalue
.ValueAsDecimal
, rvalue
.XmlType
);
303 case XmlTypeCode
.Float
:
304 case XmlTypeCode
.Double
:
305 return new XPathAtomicValue (lvalue
.ValueAsDouble
/ rvalue
.ValueAsDouble
, rvalue
.XmlType
);
309 case XmlTypeCode
.Decimal
:
310 switch (rvalue
.XmlType
.TypeCode
) {
311 case XmlTypeCode
.Integer
:
312 case XmlTypeCode
.Decimal
:
313 return new XPathAtomicValue (lvalue
.ValueAsDecimal
/ rvalue
.ValueAsDecimal
, rvalue
.XmlType
);
314 case XmlTypeCode
.Float
:
315 case XmlTypeCode
.Double
:
316 return new XPathAtomicValue (lvalue
.ValueAsDouble
/ rvalue
.ValueAsDouble
, rvalue
.XmlType
);
320 case XmlTypeCode
.Float
:
321 case XmlTypeCode
.Double
:
322 switch (rvalue
.XmlType
.TypeCode
) {
323 case XmlTypeCode
.Integer
:
324 case XmlTypeCode
.Decimal
:
325 case XmlTypeCode
.Float
:
326 case XmlTypeCode
.Double
:
327 return new XPathAtomicValue (lvalue
.ValueAsDouble
/ rvalue
.ValueAsDouble
, rvalue
.XmlType
);
329 case XmlTypeCode
.DayTimeDuration
:
330 case XmlTypeCode
.YearMonthDuration
:
331 goto case XmlTypeCode
.Decimal
;
336 case XmlTypeCode
.DayTimeDuration
:
337 case XmlTypeCode
.YearMonthDuration
:
338 switch (rvalue
.XmlType
.TypeCode
) {
339 case XmlTypeCode
.Integer
:
340 case XmlTypeCode
.Decimal
:
341 case XmlTypeCode
.Float
:
342 case XmlTypeCode
.Double
:
343 return new XPathAtomicValue (new DateTime ((long) (lvalue
.ValueAsDateTime
.Ticks
/ rvalue
.ValueAsDouble
)), rvalue
.XmlType
);
348 throw new XmlQueryException (String
.Format ("Not allowed arithmetic operation: {0} div {1}", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
354 public static XPathAtomicValue
IntDivide (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
356 return new XPathAtomicValue (lvalue
.ValueAsInt64
/ rvalue
.ValueAsInt64
, InternalPool
.XsInteger
);
362 public static XPathAtomicValue
Remainder (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
364 return new XPathAtomicValue (lvalue
.ValueAsInt64
% rvalue
.ValueAsInt64
, InternalPool
.XsInteger
);