Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Xml / System / Xml / XPath / Internal / LogicalExpr.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="LogicalExpr.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7
8 namespace MS.Internal.Xml.XPath {
9     using System;
10     using System.Xml;
11     using System.Xml.XPath;
12     using System.Diagnostics;
13     using System.Globalization;
14     using System.Xml.Xsl;
15
16     internal sealed class LogicalExpr : ValueQuery {
17         Operator.Op op;
18         Query opnd1;
19         Query opnd2;
20         
21         public LogicalExpr(Operator.Op op, Query  opnd1, Query  opnd2) {
22             Debug.Assert(
23                 Operator.Op.LT == op || Operator.Op.GT == op ||
24                 Operator.Op.LE == op || Operator.Op.GE == op ||
25                 Operator.Op.EQ == op || Operator.Op.NE == op
26             );
27             this.op    = op;
28             this.opnd1 = opnd1;
29             this.opnd2 = opnd2;
30         }
31         private LogicalExpr(LogicalExpr other) : base (other) {
32             this.op    = other.op;
33             this.opnd1 = Clone(other.opnd1);
34             this.opnd2 = Clone(other.opnd2);
35         }
36
37         public override void SetXsltContext(XsltContext context){
38             opnd1.SetXsltContext(context);
39             opnd2.SetXsltContext(context);
40         }
41
42         public override object Evaluate(XPathNodeIterator nodeIterator) {
43             Operator.Op op = this.op;
44             object val1 = this.opnd1.Evaluate(nodeIterator);
45             object val2 = this.opnd2.Evaluate(nodeIterator);
46             int type1 = (int)GetXPathType(val1);
47             int type2 = (int)GetXPathType(val2);
48             if (type1 < type2) {
49                 op = Operator.InvertOperator(op);
50                 object valTemp = val1;
51                 val1 = val2;
52                 val2 = valTemp;
53                 int typeTmp = type1;
54                 type1 = type2;
55                 type2 = typeTmp;
56             }
57
58             if (op == Operator.Op.EQ || op == Operator.Op.NE) {
59                 return CompXsltE[type1][type2](op, val1, val2);
60             } else {
61                 return CompXsltO[type1][type2](op, val1, val2);
62             }
63         }
64
65         delegate bool cmpXslt(Operator.Op op, object val1, object val2);
66
67         //                              Number,                       String,                        Boolean,                     NodeSet,                      Navigator
68         private static readonly cmpXslt[][] CompXsltE = {                                                                                         
69             new cmpXslt[] { new cmpXslt(cmpNumberNumber), null                         , null                       , null                        , null                    }, 
70             new cmpXslt[] { new cmpXslt(cmpStringNumber), new cmpXslt(cmpStringStringE), null                       , null                        , null                    }, 
71             new cmpXslt[] { new cmpXslt(cmpBoolNumberE ), new cmpXslt(cmpBoolStringE  ), new cmpXslt(cmpBoolBoolE  ), null                        , null                    }, 
72             new cmpXslt[] { new cmpXslt(cmpQueryNumber ), new cmpXslt(cmpQueryStringE ), new cmpXslt(cmpQueryBoolE ), new cmpXslt(cmpQueryQueryE ), null                    },
73             new cmpXslt[] { new cmpXslt(cmpRtfNumber   ), new cmpXslt(cmpRtfStringE   ), new cmpXslt(cmpRtfBoolE   ), new cmpXslt(cmpRtfQueryE   ), new cmpXslt(cmpRtfRtfE) },
74         };
75         private static readonly cmpXslt[][] CompXsltO = {                                                                                         
76             new cmpXslt[] { new cmpXslt(cmpNumberNumber), null                         , null                       , null                        , null                    }, 
77             new cmpXslt[] { new cmpXslt(cmpStringNumber), new cmpXslt(cmpStringStringO), null                       , null                        , null                    }, 
78             new cmpXslt[] { new cmpXslt(cmpBoolNumberO ), new cmpXslt(cmpBoolStringO  ), new cmpXslt(cmpBoolBoolO  ), null                        , null                    }, 
79             new cmpXslt[] { new cmpXslt(cmpQueryNumber ), new cmpXslt(cmpQueryStringO ), new cmpXslt(cmpQueryBoolO ), new cmpXslt(cmpQueryQueryO ), null                    },
80             new cmpXslt[] { new cmpXslt(cmpRtfNumber   ), new cmpXslt(cmpRtfStringO   ), new cmpXslt(cmpRtfBoolO   ), new cmpXslt(cmpRtfQueryO   ), new cmpXslt(cmpRtfRtfO) },
81         };
82         
83         /*cmpXslt:*/
84         static bool cmpQueryQueryE(Operator.Op op, object val1, object val2) {
85             Debug.Assert(op == Operator.Op.EQ || op == Operator.Op.NE);
86             bool isEQ = (op == Operator.Op.EQ);
87
88             NodeSet n1 = new NodeSet(val1);
89             NodeSet n2 = new NodeSet(val2);
90
91             while (true) {
92                 if (! n1.MoveNext()) {
93                     return false;
94                 }
95                 if (! n2.MoveNext()) {
96                     return false;
97                 }
98
99                 string str1 = n1.Value;
100
101                 do {
102                     if ((str1 == n2.Value) == isEQ) {
103                         return true;
104                     }
105                 }while (n2.MoveNext());
106                 n2.Reset();    
107             }
108         }
109         
110         /*cmpXslt:*/
111         static bool cmpQueryQueryO(Operator.Op op, object val1, object val2) {
112             Debug.Assert(
113                 op == Operator.Op.LT || op == Operator.Op.GT ||
114                 op == Operator.Op.LE || op == Operator.Op.GE
115             );
116
117             NodeSet n1 = new NodeSet(val1);
118             NodeSet n2 = new NodeSet(val2);
119
120             while (true) {
121                 if (!n1.MoveNext()) {
122                     return false;
123                 }
124                 if (!n2.MoveNext()) {
125                     return false;
126                 }
127
128                 double num1 = NumberFunctions.Number(n1.Value);
129
130                 do {
131                     if (cmpNumberNumber(op, num1, NumberFunctions.Number(n2.Value))) {
132                         return true;
133                     }
134                 } while (n2.MoveNext());
135                 n2.Reset();
136             }
137         }        
138         static bool cmpQueryNumber(Operator.Op op, object val1, object val2) {
139             NodeSet n1 = new NodeSet(val1);
140             double n2 = (double) val2;
141
142             while (n1.MoveNext()) {
143                 if (cmpNumberNumber(op, NumberFunctions.Number(n1.Value), n2)) {
144                     return true;
145                 }
146             }
147             return false;
148         }
149         
150         static bool cmpQueryStringE(Operator.Op op, object val1, object val2) {
151             NodeSet n1 = new NodeSet(val1);
152             string n2 = (string) val2;
153
154             while (n1.MoveNext()) {
155                 if (cmpStringStringE(op, n1.Value, n2)) {
156                     return true;
157                 }
158             }
159             return false;
160         }
161
162         static bool cmpQueryStringO(Operator.Op op, object val1, object val2) {
163             NodeSet n1 = new NodeSet(val1); 
164             double n2 = NumberFunctions.Number((string) val2);
165
166             while (n1.MoveNext()) {
167                 if (cmpNumberNumberO(op, NumberFunctions.Number(n1.Value), n2)) {
168                     return true;
169                 }
170             }
171             return false;
172         }
173
174         static bool cmpRtfQueryE(Operator.Op op, object val1, object val2) {
175             string n1 = Rtf(val1);
176             NodeSet n2 = new NodeSet(val2);
177
178             while (n2.MoveNext()) {
179                 if (cmpStringStringE(op, n1, n2.Value)) {
180                     return true;
181                 }
182             }
183             return false;
184         }
185
186         static bool cmpRtfQueryO(Operator.Op op, object val1, object val2) {
187             double n1 = NumberFunctions.Number(Rtf(val1));
188             NodeSet n2 = new NodeSet(val2);
189
190             while (n2.MoveNext()) {
191                 if (cmpNumberNumberO(op, n1, NumberFunctions.Number(n2.Value))) {
192                     return true;
193                 }
194             }
195             return false;
196         }
197
198         static bool cmpQueryBoolE(Operator.Op op, object val1, object val2) {
199             NodeSet n1 = new NodeSet(val1);
200             bool b1 = n1.MoveNext();
201             bool b2 = (bool)val2;
202             return cmpBoolBoolE(op, b1, b2);
203         }
204         
205         static bool cmpQueryBoolO(Operator.Op op, object val1, object val2) {
206             NodeSet n1 = new NodeSet(val1);
207             double d1 = n1.MoveNext() ? 1.0 : 0;
208             double d2 = NumberFunctions.Number((bool)val2);
209             return cmpNumberNumberO(op, d1, d2);
210         }
211
212         static bool cmpBoolBoolE(Operator.Op op, bool n1, bool n2) {
213             Debug.Assert( op == Operator.Op.EQ || op == Operator.Op.NE, 
214                 "Unexpected Operator.op code in cmpBoolBoolE()"
215             );
216             return (op == Operator.Op.EQ) == (n1 == n2);
217         }
218         static bool cmpBoolBoolE(Operator.Op op, object val1, object val2) {
219             bool n1 = (bool)val1;
220             bool n2 = (bool)val2;
221             return cmpBoolBoolE(op, n1, n2);
222         }
223
224         static bool cmpBoolBoolO(Operator.Op op, object val1, object val2) {
225             double n1 = NumberFunctions.Number((bool)val1);
226             double n2 = NumberFunctions.Number((bool)val2);
227             return cmpNumberNumberO(op, n1, n2);
228         }
229
230         static bool cmpBoolNumberE(Operator.Op op, object val1, object val2) {
231             bool n1 = (bool)val1;
232             bool n2 = BooleanFunctions.toBoolean((double)val2);  
233             return cmpBoolBoolE(op, n1, n2);
234         }
235
236         static bool cmpBoolNumberO(Operator.Op op, object val1, object val2) {
237             double n1 = NumberFunctions.Number((bool)val1);
238             double n2 = (double)val2;  
239             return cmpNumberNumberO(op, n1, n2);
240         }
241         
242         static bool cmpBoolStringE(Operator.Op op, object val1, object val2) {
243             bool n1 = (bool)val1;
244             bool n2 = BooleanFunctions.toBoolean((string) val2);  
245             return cmpBoolBoolE(op, n1, n2);
246         }
247
248         static bool cmpRtfBoolE(Operator.Op op, object val1, object val2) {
249             bool n1 = BooleanFunctions.toBoolean(Rtf(val1));
250             bool n2 = (bool)val2;
251             return cmpBoolBoolE(op, n1, n2);
252         }
253
254         static bool cmpBoolStringO(Operator.Op op, object val1, object val2) {
255             return cmpNumberNumberO(op, 
256                 NumberFunctions.Number((bool)val1), 
257                 NumberFunctions.Number((string) val2)
258             );
259         }
260
261         static bool cmpRtfBoolO(Operator.Op op, object val1, object val2) {
262             return cmpNumberNumberO(op,
263                 NumberFunctions.Number(Rtf(val1)),
264                 NumberFunctions.Number((bool)val2)
265             );
266         }
267
268         static bool cmpNumberNumber(Operator.Op op, double n1, double n2) {
269             switch (op) {
270             case Operator.Op.LT : return( n1 <  n2 ) ;
271             case Operator.Op.GT : return( n1 >  n2 ) ;
272             case Operator.Op.LE : return( n1 <= n2 ) ;
273             case Operator.Op.GE : return( n1 >= n2 ) ;
274             case Operator.Op.EQ : return( n1 == n2 ) ;
275             case Operator.Op.NE : return( n1 != n2 ) ;
276             }
277             Debug.Fail("Unexpected Operator.op code in cmpNumberNumber()");
278             return false;
279         }
280         static bool cmpNumberNumberO(Operator.Op op, double n1, double n2) {
281             switch (op) {
282             case Operator.Op.LT : return( n1 <  n2 ) ;
283             case Operator.Op.GT : return( n1 >  n2 ) ;
284             case Operator.Op.LE : return( n1 <= n2 ) ;
285             case Operator.Op.GE : return( n1 >= n2 ) ;
286             }
287             Debug.Fail("Unexpected Operator.op code in cmpNumberNumberO()");
288             return false;
289         }
290         static bool cmpNumberNumber(Operator.Op op, object val1, object val2) {
291             double n1 = (double)val1;
292             double n2 = (double)val2;
293             return cmpNumberNumber(op, n1, n2);
294         }
295         
296         static bool cmpStringNumber(Operator.Op op, object val1, object val2) {
297             double n2 = (double)val2;
298             double n1 = NumberFunctions.Number((string) val1);  
299             return cmpNumberNumber(op, n1, n2);
300         }
301
302         static bool cmpRtfNumber(Operator.Op op, object val1, object val2) {
303             double n2 = (double)val2;
304             double n1 = NumberFunctions.Number(Rtf(val1));
305             return cmpNumberNumber(op, n1, n2);
306         }
307
308         static bool cmpStringStringE(Operator.Op op, string n1, string n2) {
309             Debug.Assert( op == Operator.Op.EQ || op == Operator.Op.NE, 
310                 "Unexpected Operator.op code in cmpStringStringE()"
311             );
312             return (op == Operator.Op.EQ) == (n1 == n2);
313         } 
314         static bool cmpStringStringE(Operator.Op op, object val1, object val2) {
315             string n1 = (string) val1;
316             string n2 = (string) val2;  
317             return cmpStringStringE(op, n1, n2);
318         }
319         static bool cmpRtfStringE(Operator.Op op, object val1, object val2) {
320             string n1 = Rtf(val1);
321             string n2 = (string) val2;
322             return cmpStringStringE(op, n1, n2);
323         }
324         static bool cmpRtfRtfE(Operator.Op op, object val1, object val2) {
325             string n1 = Rtf(val1);
326             string n2 = Rtf(val2);
327             return cmpStringStringE(op, n1, n2);
328         } 
329
330         static bool cmpStringStringO(Operator.Op op, object val1, object val2) {
331             double n1 = NumberFunctions.Number((string) val1);
332             double n2 = NumberFunctions.Number((string) val2);
333             return cmpNumberNumberO(op, n1, n2);
334         }
335
336         static bool cmpRtfStringO(Operator.Op op, object val1, object val2) {
337             double n1 = NumberFunctions.Number(Rtf(val1));
338             double n2 = NumberFunctions.Number((string)val2);
339             return cmpNumberNumberO(op, n1, n2);
340         }
341
342         static bool cmpRtfRtfO(Operator.Op op, object val1, object val2) {
343             double n1 = NumberFunctions.Number(Rtf(val1));
344             double n2 = NumberFunctions.Number(Rtf(val2));
345             return cmpNumberNumberO(op, n1, n2);
346         }
347
348         public override XPathNodeIterator Clone() { return new LogicalExpr(this); }
349
350         private struct NodeSet {
351             private Query opnd;
352             private XPathNavigator current;
353
354             public NodeSet(object opnd) {
355                 this.opnd = (Query) opnd;
356                 current = null;
357             }
358             public bool MoveNext() {
359                 current = opnd.Advance();
360                 return current != null;
361             }
362
363             public void Reset() {
364                 opnd.Reset();
365             }
366
367             public string Value { get { return this.current.Value; } }
368         }
369
370         private static string Rtf(    object o) { return ((XPathNavigator)o).Value; }
371
372         public override XPathResultType StaticType { get { return XPathResultType.Boolean; } }
373
374         public override void PrintQuery(XmlWriter w) {
375             w.WriteStartElement(this.GetType().Name);
376             w.WriteAttributeString("op", op.ToString());
377             opnd1.PrintQuery(w);
378             opnd2.PrintQuery(w);
379             w.WriteEndElement();
380         }
381     }
382 }