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
;
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
49 public static XPathAtomicValue
Add (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
51 // numeric, date, time, dateTime, yearMonthDuration, dayTimeDuration
52 switch (lvalue
.XmlType
.TypeCode
) {
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
);
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
);
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
);
90 case XmlTypeCode
.Time
:
91 if (rvalue
.XmlType
.TypeCode
== XmlTypeCode
.DayTimeDuration
)
92 goto case XmlTypeCode
.DateTime
;
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
);
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
);
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
);
124 throw new XmlQueryException (String
.Format ("Not allowed arithmetic operation: {0} + {1}", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
130 public static XPathAtomicValue
Subtract (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
132 // numeric, date, time, dateTime, yearMonthDuration, dayTimeDuration
133 switch (lvalue
.XmlType
.TypeCode
) {
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
213 throw new XmlQueryException (String
.Format ("Not allowed arithmetic operation: {0} - {1}", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
219 public static XPathAtomicValue
Multiply (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
221 // numeric, date, time, dateTime, yearMonthDuration, dayTimeDuration
222 switch (lvalue
.XmlType
.TypeCode
) {
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
;
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
);
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
;
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
);
284 throw new XmlQueryException (String
.Format ("Not allowed arithmetic operation: {0} * {1}", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
290 public static XPathAtomicValue
Divide (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
292 // numeric, date, time, dateTime, yearMonthDuration, dayTimeDuration
293 switch (lvalue
.XmlType
.TypeCode
) {
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
);
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
);
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
;
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
);
347 throw new XmlQueryException (String
.Format ("Not allowed arithmetic operation: {0} div {1}", lvalue
.XmlType
.QualifiedName
, rvalue
.XmlType
.QualifiedName
));
353 public static XPathAtomicValue
IntDivide (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
355 return new XPathAtomicValue (lvalue
.ValueAsInt64
/ rvalue
.ValueAsInt64
, XmlSchemaSimpleType
.XsInteger
);
361 public static XPathAtomicValue
Remainder (XPathAtomicValue lvalue
, XPathAtomicValue rvalue
)
363 return new XPathAtomicValue (lvalue
.ValueAsInt64
% rvalue
.ValueAsInt64
, XmlSchemaSimpleType
.XsInteger
);