1 //------------------------------------------------------------------------------
2 // <copyright file="LogicalExpr.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 namespace MS.Internal.Xml.XPath {
11 using System.Xml.XPath;
12 using System.Diagnostics;
13 using System.Globalization;
16 internal sealed class LogicalExpr : ValueQuery {
21 public LogicalExpr(Operator.Op op, Query opnd1, Query opnd2) {
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
31 private LogicalExpr(LogicalExpr other) : base (other) {
33 this.opnd1 = Clone(other.opnd1);
34 this.opnd2 = Clone(other.opnd2);
37 public override void SetXsltContext(XsltContext context){
38 opnd1.SetXsltContext(context);
39 opnd2.SetXsltContext(context);
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);
49 op = Operator.InvertOperator(op);
50 object valTemp = val1;
58 if (op == Operator.Op.EQ || op == Operator.Op.NE) {
59 return CompXsltE[type1][type2](op, val1, val2);
61 return CompXsltO[type1][type2](op, val1, val2);
65 delegate bool cmpXslt(Operator.Op op, object val1, object val2);
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) },
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) },
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);
88 NodeSet n1 = new NodeSet(val1);
89 NodeSet n2 = new NodeSet(val2);
92 if (! n1.MoveNext()) {
95 if (! n2.MoveNext()) {
99 string str1 = n1.Value;
102 if ((str1 == n2.Value) == isEQ) {
105 }while (n2.MoveNext());
111 static bool cmpQueryQueryO(Operator.Op op, object val1, object val2) {
113 op == Operator.Op.LT || op == Operator.Op.GT ||
114 op == Operator.Op.LE || op == Operator.Op.GE
117 NodeSet n1 = new NodeSet(val1);
118 NodeSet n2 = new NodeSet(val2);
121 if (!n1.MoveNext()) {
124 if (!n2.MoveNext()) {
128 double num1 = NumberFunctions.Number(n1.Value);
131 if (cmpNumberNumber(op, num1, NumberFunctions.Number(n2.Value))) {
134 } while (n2.MoveNext());
138 static bool cmpQueryNumber(Operator.Op op, object val1, object val2) {
139 NodeSet n1 = new NodeSet(val1);
140 double n2 = (double) val2;
142 while (n1.MoveNext()) {
143 if (cmpNumberNumber(op, NumberFunctions.Number(n1.Value), n2)) {
150 static bool cmpQueryStringE(Operator.Op op, object val1, object val2) {
151 NodeSet n1 = new NodeSet(val1);
152 string n2 = (string) val2;
154 while (n1.MoveNext()) {
155 if (cmpStringStringE(op, n1.Value, n2)) {
162 static bool cmpQueryStringO(Operator.Op op, object val1, object val2) {
163 NodeSet n1 = new NodeSet(val1);
164 double n2 = NumberFunctions.Number((string) val2);
166 while (n1.MoveNext()) {
167 if (cmpNumberNumberO(op, NumberFunctions.Number(n1.Value), n2)) {
174 static bool cmpRtfQueryE(Operator.Op op, object val1, object val2) {
175 string n1 = Rtf(val1);
176 NodeSet n2 = new NodeSet(val2);
178 while (n2.MoveNext()) {
179 if (cmpStringStringE(op, n1, n2.Value)) {
186 static bool cmpRtfQueryO(Operator.Op op, object val1, object val2) {
187 double n1 = NumberFunctions.Number(Rtf(val1));
188 NodeSet n2 = new NodeSet(val2);
190 while (n2.MoveNext()) {
191 if (cmpNumberNumberO(op, n1, NumberFunctions.Number(n2.Value))) {
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);
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);
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()"
216 return (op == Operator.Op.EQ) == (n1 == n2);
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);
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);
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);
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);
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);
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);
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)
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)
268 static bool cmpNumberNumber(Operator.Op op, double n1, double n2) {
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 ) ;
277 Debug.Fail("Unexpected Operator.op code in cmpNumberNumber()");
280 static bool cmpNumberNumberO(Operator.Op op, double n1, double n2) {
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 ) ;
287 Debug.Fail("Unexpected Operator.op code in cmpNumberNumberO()");
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);
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);
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);
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()"
312 return (op == Operator.Op.EQ) == (n1 == n2);
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);
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);
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);
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);
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);
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);
348 public override XPathNodeIterator Clone() { return new LogicalExpr(this); }
350 private struct NodeSet {
352 private XPathNavigator current;
354 public NodeSet(object opnd) {
355 this.opnd = (Query) opnd;
358 public bool MoveNext() {
359 current = opnd.Advance();
360 return current != null;
363 public void Reset() {
367 public string Value { get { return this.current.Value; } }
370 private static string Rtf( object o) { return ((XPathNavigator)o).Value; }
372 public override XPathResultType StaticType { get { return XPathResultType.Boolean; } }
374 public override void PrintQuery(XmlWriter w) {
375 w.WriteStartElement(this.GetType().Name);
376 w.WriteAttributeString("op", op.ToString());