**** Merged from MCS ****
[mono-project.git] / mcs / class / System.XML / System.Xml.Query / XQueryArithmeticOperator.cs
blob1038f45162f0c74eaa1130aaefb03e1cca410d9d
1 //
2 // XQueryArithmeticOperator.cs
3 //
4 // Author:
5 // Atsushi Enomoto <atsushi@ximian.com>
6 //
7 //
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
9 //
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:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
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.
30 #if NET_2_0
31 using System;
32 using System.Collections;
33 using System.Reflection;
34 using System.Xml;
35 using System.Xml.Schema;
36 using System.Xml.Query;
37 using System.Xml.XPath;
38 using System.Xml.Xsl;
40 namespace Mono.Xml.XPath2
42 // FIXME: Handle complete type promotion and subtype substitution.
43 // See XQuery 1.0 Appendix B.*.
44 public class XQueryArithmeticOperator
46 /// <summary>
47 /// x + y
48 /// </summary>
49 public static XPathAtomicValue Add (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
51 // numeric, date, time, dateTime, yearMonthDuration, dayTimeDuration
52 switch (lvalue.XmlType.TypeCode) {
54 // numerics
55 case XmlTypeCode.Integer:
56 switch (rvalue.XmlType.TypeCode) {
57 case XmlTypeCode.Integer:
58 return new XPathAtomicValue (lvalue.ValueAsInt64 + rvalue.ValueAsInt64, rvalue.XmlType);
59 case XmlTypeCode.Decimal:
60 return new XPathAtomicValue (lvalue.ValueAsDecimal + rvalue.ValueAsDecimal, rvalue.XmlType);
61 case XmlTypeCode.Float:
62 case XmlTypeCode.Double:
63 return new XPathAtomicValue (lvalue.ValueAsDouble + rvalue.ValueAsDouble, rvalue.XmlType);
65 break;
67 case XmlTypeCode.Decimal:
68 switch (rvalue.XmlType.TypeCode) {
69 case XmlTypeCode.Integer:
70 case XmlTypeCode.Decimal:
71 return new XPathAtomicValue (lvalue.ValueAsDecimal + rvalue.ValueAsDecimal, rvalue.XmlType);
72 case XmlTypeCode.Float:
73 case XmlTypeCode.Double:
74 return new XPathAtomicValue (lvalue.ValueAsDouble + rvalue.ValueAsDouble, rvalue.XmlType);
76 break;
78 case XmlTypeCode.Float:
79 case XmlTypeCode.Double:
80 switch (rvalue.XmlType.TypeCode) {
81 case XmlTypeCode.Integer:
82 case XmlTypeCode.Decimal:
83 case XmlTypeCode.Float:
84 case XmlTypeCode.Double:
85 return new XPathAtomicValue (lvalue.ValueAsDouble + rvalue.ValueAsDouble, rvalue.XmlType);
87 break;
89 // datetimes
90 case XmlTypeCode.Time:
91 if (rvalue.XmlType.TypeCode == XmlTypeCode.DayTimeDuration)
92 goto case XmlTypeCode.DateTime;
93 break;
94 case XmlTypeCode.DateTime:
95 case XmlTypeCode.Date:
96 switch (rvalue.XmlType.TypeCode) {
97 case XmlTypeCode.YearMonthDuration:
98 case XmlTypeCode.DayTimeDuration:
99 return new XPathAtomicValue (lvalue.ValueAsDateTime + new TimeSpan (rvalue.ValueAsDateTime.Ticks), lvalue.XmlType);
101 break;
102 // durations
103 case XmlTypeCode.YearMonthDuration:
104 switch (rvalue.XmlType.TypeCode) {
105 case XmlTypeCode.Date:
106 case XmlTypeCode.DateTime:
107 return new XPathAtomicValue (lvalue.ValueAsDateTime + new TimeSpan (rvalue.ValueAsDateTime.Ticks), rvalue.XmlType);
108 case XmlTypeCode.YearMonthDuration:
109 return new XPathAtomicValue (new DateTime (lvalue.ValueAsDateTime.Ticks + rvalue.ValueAsDateTime.Ticks), XmlSchemaSimpleType.XdtYearMonthDuration);
111 break;
112 case XmlTypeCode.DayTimeDuration:
113 switch (rvalue.XmlType.TypeCode) {
114 case XmlTypeCode.Date:
115 case XmlTypeCode.Time:
116 case XmlTypeCode.DateTime:
117 return new XPathAtomicValue (lvalue.ValueAsDateTime + new TimeSpan (rvalue.ValueAsDateTime.Ticks), rvalue.XmlType);
118 case XmlTypeCode.DayTimeDuration:
119 return new XPathAtomicValue (new DateTime (lvalue.ValueAsDateTime.Ticks + rvalue.ValueAsDateTime.Ticks), XmlSchemaSimpleType.XdtDayTimeDuration);
121 break;
124 throw new XmlQueryException (String.Format ("Not allowed arithmetic operation: {0} + {1}", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
127 /// <summary>
128 /// x - y
129 /// </summary>
130 public static XPathAtomicValue Subtract (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
132 // numeric, date, time, dateTime, yearMonthDuration, dayTimeDuration
133 switch (lvalue.XmlType.TypeCode) {
135 // numerics
136 case XmlTypeCode.Integer:
137 switch (rvalue.XmlType.TypeCode) {
138 case XmlTypeCode.Integer:
139 return new XPathAtomicValue (lvalue.ValueAsInt64 - rvalue.ValueAsInt64, rvalue.XmlType);
140 case XmlTypeCode.Decimal:
141 return new XPathAtomicValue (lvalue.ValueAsDecimal - rvalue.ValueAsDecimal, rvalue.XmlType);
142 case XmlTypeCode.Float:
143 case XmlTypeCode.Double:
144 return new XPathAtomicValue (lvalue.ValueAsDouble - rvalue.ValueAsDouble, rvalue.XmlType);
146 break;
148 case XmlTypeCode.Decimal:
149 switch (rvalue.XmlType.TypeCode) {
150 case XmlTypeCode.Integer:
151 case XmlTypeCode.Decimal:
152 return new XPathAtomicValue (lvalue.ValueAsDecimal - rvalue.ValueAsDecimal, rvalue.XmlType);
153 case XmlTypeCode.Float:
154 case XmlTypeCode.Double:
155 return new XPathAtomicValue (lvalue.ValueAsDouble - rvalue.ValueAsDouble, rvalue.XmlType);
157 break;
159 case XmlTypeCode.Float:
160 case XmlTypeCode.Double:
161 switch (rvalue.XmlType.TypeCode) {
162 case XmlTypeCode.Integer:
163 case XmlTypeCode.Decimal:
164 case XmlTypeCode.Float:
165 case XmlTypeCode.Double:
166 return new XPathAtomicValue (lvalue.ValueAsDouble - rvalue.ValueAsDouble, rvalue.XmlType);
168 break;
170 // datetimes
171 case XmlTypeCode.Time:
172 switch (rvalue.XmlType.TypeCode) {
173 case XmlTypeCode.Time:
174 return new XPathAtomicValue (lvalue.ValueAsDateTime - rvalue.ValueAsDateTime, XmlSchemaSimpleType.XdtDayTimeDuration);
175 case XmlTypeCode.DayTimeDuration:
176 return new XPathAtomicValue (lvalue.ValueAsDateTime - new TimeSpan (rvalue.ValueAsDateTime.Ticks), lvalue.XmlType);
178 break;
180 case XmlTypeCode.DateTime:
181 switch (rvalue.XmlType.TypeCode) {
182 case XmlTypeCode.DateTime:
183 // FIXME: check fn:subtract-daytimes-yielding-dayTimeDuration()
184 return new XPathAtomicValue (lvalue.ValueAsDateTime - rvalue.ValueAsDateTime, XmlSchemaSimpleType.XdtDayTimeDuration);
185 case XmlTypeCode.YearMonthDuration:
186 case XmlTypeCode.DayTimeDuration:
187 return new XPathAtomicValue (lvalue.ValueAsDateTime - new TimeSpan (rvalue.ValueAsDateTime.Ticks), lvalue.XmlType);
189 break;
191 case XmlTypeCode.Date:
192 switch (rvalue.XmlType.TypeCode) {
193 case XmlTypeCode.Date:
194 // FIXME: check fn:subtract-daytimes-yielding-dayTimeDuration()
195 return new XPathAtomicValue (lvalue.ValueAsDateTime - rvalue.ValueAsDateTime, XmlSchemaSimpleType.XdtDayTimeDuration);
196 case XmlTypeCode.YearMonthDuration:
197 case XmlTypeCode.DayTimeDuration:
198 return new XPathAtomicValue (lvalue.ValueAsDateTime - new TimeSpan (rvalue.ValueAsDateTime.Ticks), lvalue.XmlType);
200 break;
202 // durations
203 case XmlTypeCode.YearMonthDuration:
204 if (rvalue.XmlType.TypeCode == XmlTypeCode.YearMonthDuration)
205 return new XPathAtomicValue (new TimeSpan (lvalue.ValueAsDateTime.Ticks - rvalue.ValueAsDateTime.Ticks), XmlSchemaSimpleType.XdtYearMonthDuration);
206 break;
207 case XmlTypeCode.DayTimeDuration:
208 if (rvalue.XmlType.TypeCode == XmlTypeCode.DayTimeDuration)
209 return new XPathAtomicValue (new TimeSpan (lvalue.ValueAsDateTime.Ticks - rvalue.ValueAsDateTime.Ticks), XmlSchemaSimpleType.XdtDayTimeDuration);
210 break;
213 throw new XmlQueryException (String.Format ("Not allowed arithmetic operation: {0} - {1}", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
216 /// <summary>
217 /// x * y
218 /// </summary>
219 public static XPathAtomicValue Multiply (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
221 // numeric, date, time, dateTime, yearMonthDuration, dayTimeDuration
222 switch (lvalue.XmlType.TypeCode) {
224 // numerics
225 case XmlTypeCode.Integer:
226 switch (rvalue.XmlType.TypeCode) {
227 case XmlTypeCode.Integer:
228 return new XPathAtomicValue (lvalue.ValueAsInt64 * rvalue.ValueAsInt64, rvalue.XmlType);
229 case XmlTypeCode.Decimal:
230 return new XPathAtomicValue (lvalue.ValueAsDecimal * rvalue.ValueAsDecimal, rvalue.XmlType);
231 case XmlTypeCode.Float:
232 case XmlTypeCode.Double:
233 return new XPathAtomicValue (lvalue.ValueAsDouble * rvalue.ValueAsDouble, rvalue.XmlType);
235 case XmlTypeCode.DayTimeDuration:
236 case XmlTypeCode.YearMonthDuration:
237 goto case XmlTypeCode.Decimal;
239 break;
241 case XmlTypeCode.Decimal:
242 switch (rvalue.XmlType.TypeCode) {
243 case XmlTypeCode.Integer:
244 case XmlTypeCode.Decimal:
245 return new XPathAtomicValue (lvalue.ValueAsDecimal * rvalue.ValueAsDecimal, rvalue.XmlType);
246 case XmlTypeCode.Float:
247 case XmlTypeCode.Double:
248 return new XPathAtomicValue (lvalue.ValueAsDouble * rvalue.ValueAsDouble, rvalue.XmlType);
250 case XmlTypeCode.YearMonthDuration:
251 case XmlTypeCode.DayTimeDuration:
252 return new XPathAtomicValue (new TimeSpan ((long) (lvalue.ValueAsDateTime.Ticks * rvalue.ValueAsDecimal)), rvalue.XmlType);
254 break;
256 case XmlTypeCode.Float:
257 case XmlTypeCode.Double:
258 switch (rvalue.XmlType.TypeCode) {
259 case XmlTypeCode.Integer:
260 case XmlTypeCode.Decimal:
261 case XmlTypeCode.Float:
262 case XmlTypeCode.Double:
263 return new XPathAtomicValue (lvalue.ValueAsDouble * rvalue.ValueAsDouble, rvalue.XmlType);
265 case XmlTypeCode.DayTimeDuration:
266 case XmlTypeCode.YearMonthDuration:
267 goto case XmlTypeCode.Decimal;
269 break;
271 // durations
272 case XmlTypeCode.DayTimeDuration:
273 case XmlTypeCode.YearMonthDuration:
274 switch (rvalue.XmlType.TypeCode) {
275 case XmlTypeCode.Integer:
276 case XmlTypeCode.Decimal:
277 case XmlTypeCode.Float:
278 case XmlTypeCode.Double:
279 return Multiply (rvalue, lvalue);
281 break;
284 throw new XmlQueryException (String.Format ("Not allowed arithmetic operation: {0} * {1}", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
287 /// <summary>
288 /// x / y
289 /// </summary>
290 public static XPathAtomicValue Divide (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
292 // numeric, date, time, dateTime, yearMonthDuration, dayTimeDuration
293 switch (lvalue.XmlType.TypeCode) {
295 // numerics
296 case XmlTypeCode.Integer:
297 switch (rvalue.XmlType.TypeCode) {
298 case XmlTypeCode.Integer:
299 return new XPathAtomicValue (lvalue.ValueAsInt64 / rvalue.ValueAsInt64, rvalue.XmlType);
300 case XmlTypeCode.Decimal:
301 return new XPathAtomicValue (lvalue.ValueAsDecimal / rvalue.ValueAsDecimal, rvalue.XmlType);
302 case XmlTypeCode.Float:
303 case XmlTypeCode.Double:
304 return new XPathAtomicValue (lvalue.ValueAsDouble / rvalue.ValueAsDouble, rvalue.XmlType);
306 break;
308 case XmlTypeCode.Decimal:
309 switch (rvalue.XmlType.TypeCode) {
310 case XmlTypeCode.Integer:
311 case XmlTypeCode.Decimal:
312 return new XPathAtomicValue (lvalue.ValueAsDecimal / rvalue.ValueAsDecimal, rvalue.XmlType);
313 case XmlTypeCode.Float:
314 case XmlTypeCode.Double:
315 return new XPathAtomicValue (lvalue.ValueAsDouble / rvalue.ValueAsDouble, rvalue.XmlType);
317 break;
319 case XmlTypeCode.Float:
320 case XmlTypeCode.Double:
321 switch (rvalue.XmlType.TypeCode) {
322 case XmlTypeCode.Integer:
323 case XmlTypeCode.Decimal:
324 case XmlTypeCode.Float:
325 case XmlTypeCode.Double:
326 return new XPathAtomicValue (lvalue.ValueAsDouble / rvalue.ValueAsDouble, rvalue.XmlType);
328 case XmlTypeCode.DayTimeDuration:
329 case XmlTypeCode.YearMonthDuration:
330 goto case XmlTypeCode.Decimal;
332 break;
334 // durations
335 case XmlTypeCode.DayTimeDuration:
336 case XmlTypeCode.YearMonthDuration:
337 switch (rvalue.XmlType.TypeCode) {
338 case XmlTypeCode.Integer:
339 case XmlTypeCode.Decimal:
340 case XmlTypeCode.Float:
341 case XmlTypeCode.Double:
342 return new XPathAtomicValue (new DateTime ((long) (lvalue.ValueAsDateTime.Ticks / rvalue.ValueAsDouble)), rvalue.XmlType);
344 break;
347 throw new XmlQueryException (String.Format ("Not allowed arithmetic operation: {0} div {1}", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName));
350 /// <summary>
351 /// x idiv y
352 /// </summary>
353 public static XPathAtomicValue IntDivide (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
355 return new XPathAtomicValue (lvalue.ValueAsInt64 / rvalue.ValueAsInt64, XmlSchemaSimpleType.XsInteger);
358 /// <summary>
359 /// x imod y
360 /// </summary>
361 public static XPathAtomicValue Remainder (XPathAtomicValue lvalue, XPathAtomicValue rvalue)
363 return new XPathAtomicValue (lvalue.ValueAsInt64 % rvalue.ValueAsInt64, XmlSchemaSimpleType.XsInteger);
367 #endif