2008-04-11 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.XML / System.Xml.XPath / Expression.cs
1 //
2 // System.Xml.XPath.XPathExpression support classes
3 //
4 // Author:
5 //   Piers Haken (piersh@friskit.com)
6 //
7 // (C) 2002 Piers Haken
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 using System;
31 using System.IO;
32 using System.Collections;
33 using System.Xml;
34 using System.Xml.XPath;
35 using System.Xml.Xsl;
36 using System.Globalization;
37 using Mono.Xml.XPath;
38
39 #if NET_2_0
40 using NSResolver = System.Xml.IXmlNamespaceResolver;
41 #else
42 using NSResolver = System.Xml.XmlNamespaceManager;
43 #endif
44
45 namespace System.Xml.XPath
46 {
47 #if XPATH_DEBUG
48         internal class CompiledExpression : Test.Xml.XPath.XPathExpression
49 #else
50         internal class CompiledExpression : XPathExpression
51 #endif
52         {
53                 protected NSResolver _nsm;
54                 protected Expression _expr;
55                 XPathSorters _sorters;
56                 string rawExpression;
57
58                 public CompiledExpression (string raw, Expression expr)
59                 {
60                         _expr = expr.Optimize ();
61                         rawExpression = raw;
62                 }
63                 private CompiledExpression (CompiledExpression other)
64                 {
65                         _nsm = other._nsm;
66                         _expr = other._expr;
67                         rawExpression = other.rawExpression;
68                 }
69 #if XPATH_DEBUG
70                 public override Test.Xml.XPath.XPathExpression Clone () { return new CompiledExpression (this); }
71 #else
72                 public override XPathExpression Clone () { return new CompiledExpression (this); }
73 #endif
74                 
75                 public Expression ExpressionNode { get { return _expr; }}
76
77                 public override void SetContext (XmlNamespaceManager nsManager)
78                 {
79                         _nsm = nsManager;
80                 }
81
82 #if NET_2_0
83                 public override void SetContext (IXmlNamespaceResolver nsResolver)
84                 {
85                         _nsm = nsResolver;
86                 }
87 #endif
88
89                 internal NSResolver NamespaceManager { get { return _nsm; } }
90                 public override String Expression { get { return rawExpression; }}
91                 public override XPathResultType ReturnType { get { return _expr.ReturnType; }}
92
93                 public object Evaluate (BaseIterator iter)
94                 {
95                         if (_sorters != null)
96                                 return EvaluateNodeSet (iter);
97
98                         try {
99                                 return _expr.Evaluate (iter);
100                         }
101                         catch (XPathException) {
102                                 throw;
103                         }
104                         catch (XsltException) {
105                                 throw;
106                         }
107                         catch (Exception e) {
108                                 throw new XPathException ("Error during evaluation", e);
109                         }
110                 }
111                 public XPathNodeIterator EvaluateNodeSet (BaseIterator iter)
112                 {
113 #if false
114                         try
115                         {
116 #endif
117                                 BaseIterator iterResults = (BaseIterator) _expr.EvaluateNodeSet (iter);
118                                 if (_sorters != null)
119                                         return _sorters.Sort (iterResults);
120                                 return iterResults;
121 #if false
122                         }
123                         catch (XPathException)
124                         {
125                                 throw;
126                         }
127                         catch (Exception e)
128                         {
129                                 throw new XPathException ("Error during evaluation", e);
130                         }
131 #endif
132                 }
133                 public double EvaluateNumber (BaseIterator iter)
134                 {
135 #if true
136                         return _expr.EvaluateNumber (iter);
137 #else
138                         try
139                         {
140                                 return _expr.EvaluateNumber (iter);
141                         }
142                         catch (XPathException)
143                         {
144                                 throw;
145                         }
146                         catch (Exception e)
147                         {
148                                 throw new XPathException ("Error during evaluation", e);
149                         }
150 #endif
151                 }
152                 public string EvaluateString (BaseIterator iter)
153                 {
154 #if true
155                         return _expr.EvaluateString (iter);
156 #else
157                         try
158                         {
159                                 return _expr.EvaluateString (iter);
160                         }
161                         catch (XPathException)
162                         {
163                                 throw;
164                         }
165                         catch (Exception e)
166                         {
167                                 throw new XPathException ("Error during evaluation", e);
168                         }
169 #endif
170                 }
171                 public bool EvaluateBoolean (BaseIterator iter)
172                 {
173 #if true
174                         return _expr.EvaluateBoolean (iter);
175 #else
176                         try
177                         {
178                                 return _expr.EvaluateBoolean (iter);
179                         }
180                         catch (XPathException)
181                         {
182                                 throw;
183                         }
184                         catch (Exception e)
185                         {
186                                 throw new XPathException ("Error during evaluation", e);
187                         }
188 #endif
189                 }
190
191                 public override void AddSort (Object obj, IComparer cmp)
192                 {
193                         if (_sorters == null)
194                                 _sorters = new XPathSorters ();
195                         _sorters.Add (obj, cmp);
196                 }
197                 public override void AddSort(object expr, XmlSortOrder orderSort, XmlCaseOrder orderCase, string lang, XmlDataType dataType)
198                 {
199                         if (_sorters == null)
200                                 _sorters = new XPathSorters ();
201                         _sorters.Add (expr, orderSort, orderCase, lang, dataType);
202                 }
203
204         }
205
206         class XPathSortElement
207         {
208                 public XPathNavigator Navigator;
209                 public object [] Values;
210         }
211
212         class XPathSorters : IComparer
213         {
214                 readonly ArrayList _rgSorters = new ArrayList ();
215
216                 public void Add (object expr, IComparer cmp)
217                 {
218                         _rgSorters.Add (new XPathSorter (expr, cmp));
219                 }
220
221                 public void Add (object expr, XmlSortOrder orderSort, XmlCaseOrder orderCase, string lang, XmlDataType dataType)
222                 {
223                         _rgSorters.Add (new XPathSorter (expr, orderSort, orderCase, lang, dataType));
224                 }
225
226                 public void CopyFrom (XPathSorter [] sorters)
227                 {
228                         _rgSorters.Clear ();
229                         _rgSorters.AddRange (sorters);
230                 }
231
232                 public BaseIterator Sort (BaseIterator iter)
233                 {
234                         ArrayList rgElts = ToSortElementList (iter);
235                         return Sort (rgElts, iter.NamespaceManager);
236                 }
237
238                 ArrayList ToSortElementList (BaseIterator iter)
239                 {
240                         ArrayList rgElts = new ArrayList ();
241                         int cSorters = _rgSorters.Count;
242                         while (iter.MoveNext ())
243                         {
244                                 XPathSortElement elt = new XPathSortElement ();
245                                 elt.Navigator = iter.Current.Clone ();
246                                 elt.Values = new object [cSorters];
247                                 for (int iSorter = 0; iSorter < _rgSorters.Count; ++iSorter)
248                                 {
249                                         XPathSorter sorter = (XPathSorter) _rgSorters [iSorter];
250                                         elt.Values [iSorter] = sorter.Evaluate (iter);
251                                 }
252                                 rgElts.Add (elt);
253                         }
254                         return rgElts;
255                 }
256
257                 public BaseIterator Sort (ArrayList rgElts, NSResolver nsm)
258                 {
259                         rgElts.Sort (this);
260                         XPathNavigator [] rgResults = new XPathNavigator [rgElts.Count];
261                         for (int iResult = 0; iResult < rgElts.Count; ++iResult)
262                         {
263                                 XPathSortElement elt = (XPathSortElement) rgElts [iResult];
264                                 rgResults [iResult] = elt.Navigator;
265                         }
266                         return new ListIterator (rgResults, nsm);
267                 }
268
269                 int IComparer.Compare (object o1, object o2)
270                 {
271                         XPathSortElement elt1 = (XPathSortElement) o1;
272                         XPathSortElement elt2 = (XPathSortElement) o2;
273                         for (int iSorter = 0; iSorter < _rgSorters.Count; ++iSorter)
274                         {
275                                 XPathSorter sorter = (XPathSorter) _rgSorters [iSorter];
276                                 int cmp = sorter.Compare (elt1.Values [iSorter], elt2.Values [iSorter]);
277                                 if (cmp != 0)
278                                         return cmp;
279                         }
280                         switch (elt1.Navigator.ComparePosition (elt2.Navigator)) {
281                         case XmlNodeOrder.Same:
282                                 return 0;
283                         case XmlNodeOrder.After:
284                                 return 1;
285                         default:
286                                 return -1;
287                         }
288                 }
289         }
290
291         class XPathSorter
292         {
293                 readonly Expression _expr;
294                 readonly IComparer _cmp;
295                 readonly XmlDataType _type;
296
297                 public XPathSorter (object expr, IComparer cmp)
298                 {
299                         _expr = ExpressionFromObject (expr);
300                         _cmp = cmp;
301                         _type = XmlDataType.Text;
302                 }
303
304                 public XPathSorter (object expr, XmlSortOrder orderSort, XmlCaseOrder orderCase, string lang, XmlDataType dataType)
305                 {
306                         _expr = ExpressionFromObject (expr);
307                         _type = dataType;
308                         if (dataType == XmlDataType.Number)
309                                 _cmp = new XPathNumberComparer (orderSort);
310                         else
311                                 _cmp = new XPathTextComparer (orderSort, orderCase, lang);
312                 }
313
314                 static Expression ExpressionFromObject (object expr)
315                 {
316                         if (expr is CompiledExpression)
317                                 return ((CompiledExpression) expr).ExpressionNode;
318                         if (expr is string)
319                                 return new XPathParser ().Compile ((string)expr);
320                         
321                         throw new XPathException ("Invalid query object");
322                 }
323
324                 public object Evaluate (BaseIterator iter)
325                 {
326                         if (_type == XmlDataType.Number)
327                                 return _expr.EvaluateNumber (iter);
328                         return _expr.EvaluateString (iter);
329                 }
330
331                 public int Compare (object o1, object o2)
332                 {
333                         return _cmp.Compare (o1, o2);
334                 }
335
336                 class XPathNumberComparer : IComparer
337                 {
338                         int _nMulSort;
339
340                         public XPathNumberComparer (XmlSortOrder orderSort)
341                         {
342                                 _nMulSort = (orderSort == XmlSortOrder.Ascending) ? 1 : -1;
343                         }
344
345                         int IComparer.Compare (object o1, object o2)
346                         {
347                                 double num1 = (double) o1;
348                                 double num2 = (double) o2;
349                                 if (num1 < num2)
350                                         return -_nMulSort;
351                                 if (num1 > num2)
352                                         return _nMulSort;
353                                 if (num1 == num2)
354                                         return 0;
355                                 if (double.IsNaN (num1))
356                                         return (double.IsNaN (num2)) ? 0 : -_nMulSort;
357                                 return _nMulSort;
358                         }
359                 }
360
361                 class XPathTextComparer : IComparer
362                 {
363                         int _nMulSort;
364                         int _nMulCase;
365                         XmlCaseOrder _orderCase;
366                         CultureInfo _ci;
367
368                         public XPathTextComparer (XmlSortOrder orderSort, XmlCaseOrder orderCase, string strLang)
369                         {
370                                 _orderCase = orderCase;
371                                 // FIXME: We have to set this in
372                                 // reverse order since currently
373                                 // we don't support collation.
374                                 _nMulCase = (orderCase == XmlCaseOrder.UpperFirst) ? -1 : 1;
375                                 _nMulSort = (orderSort == XmlSortOrder.Ascending) ? 1 : -1;
376
377                                 if (strLang == null || strLang == "")
378                                         _ci = CultureInfo.CurrentCulture;       // TODO: defer until evaluation?
379                                 else
380                                         _ci = new CultureInfo (strLang);
381                         }
382
383                         int IComparer.Compare (object o1, object o2)
384                         {
385                                 string str1 = (string) o1;
386                                 string str2 = (string) o2;
387                                 int cmp = String.Compare (str1, str2, true, _ci);
388                                 if (cmp != 0 || _orderCase == XmlCaseOrder.None)
389                                         return cmp * _nMulSort;
390                                 return _nMulSort * _nMulCase * String.Compare (str1, str2, false, _ci);
391                         }
392                 }
393         }
394
395         /// <summary>
396         /// Summary description for Expression.
397         /// </summary>
398         internal abstract class Expression
399         {
400                 public Expression ()
401                 {
402                 }
403                 public abstract XPathResultType ReturnType { get; }
404                 public virtual XPathResultType GetReturnType (BaseIterator iter) { return ReturnType; }
405
406                 public virtual Expression Optimize ()
407                 {
408                         return this;
409                 }
410
411                 public virtual bool HasStaticValue {
412                         get { return false; }
413                 }
414
415                 public virtual object StaticValue {
416                         get {
417                                 switch (ReturnType) {
418                                 case XPathResultType.String:
419                                         return StaticValueAsString;
420                                 case XPathResultType.Number:
421                                         return StaticValueAsNumber;
422                                 case XPathResultType.Boolean:
423                                         return StaticValueAsBoolean;
424                                 }
425                                 return null;
426                         }
427                 }
428
429                 public virtual string StaticValueAsString {
430                         get { return HasStaticValue ? XPathFunctions.ToString (StaticValue) : null; }
431                 }
432
433                 public virtual double StaticValueAsNumber {
434                         get { return HasStaticValue ? XPathFunctions.ToNumber (StaticValue) : 0; }
435                 }
436
437                 public virtual bool StaticValueAsBoolean {
438                         get { return HasStaticValue ? XPathFunctions.ToBoolean (StaticValue) : false; }
439                 }
440
441                 public virtual XPathNavigator StaticValueAsNavigator {
442                         get { return StaticValue as XPathNavigator; }
443                 }
444
445                 public abstract object Evaluate (BaseIterator iter);
446
447                 public virtual BaseIterator EvaluateNodeSet (BaseIterator iter)
448                 {
449                         XPathResultType type = GetReturnType (iter);
450                         switch (type) {
451                         case XPathResultType.NodeSet:
452                         case XPathResultType.Any:
453                         case XPathResultType.Navigator: // FIXME: It may pass not-allowed use of RTF
454                                 object o = Evaluate (iter);
455                                 BaseIterator iterResult = o as BaseIterator;
456                                 if (iterResult != null)
457                                         return iterResult;
458                                 XPathNavigator nav = o as XPathNavigator;
459                                 if (nav != null)
460                                         iterResult = nav.SelectChildren (XPathNodeType.All) as BaseIterator;
461                                 if (iterResult != null)
462                                         return iterResult;
463                                 break;
464                         }
465                         throw new XPathException ("expected nodeset: "+ToString ());
466                 }
467
468                 protected static XPathResultType GetReturnType (object obj)
469                 {
470                         if (obj is string)
471                                 return XPathResultType.String;
472                         if (obj is bool)
473                                 return XPathResultType.Boolean;
474                         if (obj is XPathNodeIterator)
475                                 return XPathResultType.NodeSet;
476                         if (obj is double || obj is int)
477                                 return XPathResultType.Number;
478                         if (obj is XPathNavigator)
479                                 return XPathResultType.Navigator;
480                         throw new XPathException ("invalid node type: "+obj.GetType ().ToString ());
481                 }
482
483                 internal virtual XPathNodeType EvaluatedNodeType {
484                         get { return XPathNodeType.All; }
485                 }
486
487                 internal virtual bool IsPositional {
488                         get { return false; }
489                 }
490
491                 // For "peer and subtree" optimization. see:
492                 // http://idealliance.org/papers/dx_xmle04/papers/02-03-02/02-03-02.html
493                 internal virtual bool Peer {
494                         get { return false; }
495                 }
496
497                 public virtual double EvaluateNumber (BaseIterator iter)
498                 {
499                         object result;
500                         XPathResultType type = GetReturnType (iter);
501                         if (type == XPathResultType.NodeSet)
502                         {
503                                 result = EvaluateString (iter);
504                                 type = XPathResultType.String;
505                         }
506                         else
507                                 result = Evaluate (iter);
508
509                         if (type == XPathResultType.Any)
510                                 type = GetReturnType (result);
511
512                         switch (type)
513                         {
514                                 case XPathResultType.Number:
515                                         return (double)result;
516                                 case XPathResultType.Boolean:
517                                         return ((bool) result) ? 1.0 : 0.0;
518                                 case XPathResultType.NodeSet:
519                                         return XPathFunctions.ToNumber (EvaluateString (iter));
520                                 case XPathResultType.String:
521                                         return XPathFunctions.ToNumber ((string) result);
522                                 case XPathResultType.Navigator:
523                                         return XPathFunctions.ToNumber (((XPathNavigator) (result)).Value);
524                                 default:
525                                         throw new XPathException ("invalid node type");
526                         }
527                 }
528
529                 public virtual string EvaluateString (BaseIterator iter)
530                 {
531                         object result = Evaluate (iter);
532                         XPathResultType type = GetReturnType (iter);
533                         if (type == XPathResultType.Any)
534                                 type = GetReturnType (result);
535                         switch (type)
536                         {
537                                 case XPathResultType.Number:
538                                         double d = (double) result;
539                                         return XPathFunctions.ToString (d);
540                                 case XPathResultType.Boolean:
541                                         return ((bool) result) ? "true" : "false";
542                                 case XPathResultType.String:
543                                         return (string) result;
544                                 case XPathResultType.NodeSet:
545                                 {
546                                         BaseIterator iterResult = (BaseIterator) result;
547                                         if (iterResult == null || !iterResult.MoveNext ())
548                                                 return "";
549                                         return iterResult.Current.Value;
550                                 }
551                                 case XPathResultType.Navigator:
552                                         return ((XPathNavigator) result).Value;
553                                 default:
554                                         throw new XPathException ("invalid node type");
555                         }
556                 }
557
558                 public virtual bool EvaluateBoolean (BaseIterator iter)
559                 {
560                         object result = Evaluate (iter);
561                         XPathResultType type = GetReturnType (iter);
562                         if (type == XPathResultType.Any)
563                                 type = GetReturnType (result);
564                         switch (type)
565                         {
566                                 case XPathResultType.Number:
567                                 {
568                                         double num = Convert.ToDouble (result);
569                                         return (num != 0.0 && num != -0.0 && !Double.IsNaN (num));
570                                 }
571                                 case XPathResultType.Boolean:
572                                         return (bool) result;
573                                 case XPathResultType.String:
574                                         return ((string) result).Length != 0;
575                                 case XPathResultType.NodeSet:
576                                 {
577                                         BaseIterator iterResult = (BaseIterator) result;
578                                         return (iterResult != null && iterResult.MoveNext ());
579                                 }
580                                 case XPathResultType.Navigator:
581                                         return (((XPathNavigator) result).HasChildren);
582                                 default:
583                                         throw new XPathException ("invalid node type");
584                         }
585                 }
586
587                 public object EvaluateAs (BaseIterator iter, XPathResultType type)
588                 {
589                         switch (type)
590                         {
591                         case XPathResultType.Boolean:
592                                 return EvaluateBoolean (iter);
593                         case XPathResultType.NodeSet:
594                                 return EvaluateNodeSet (iter);
595                         case XPathResultType.String:
596                                 return EvaluateString (iter);
597                         case XPathResultType.Number:
598                                 return EvaluateNumber (iter);
599                         }
600                         return Evaluate (iter);
601                 }
602
603                 public virtual bool RequireSorting { get { return false; } }
604         }
605
606         internal abstract class ExprBinary : Expression
607         {
608                 protected Expression _left, _right;
609
610                 public ExprBinary (Expression left, Expression right)
611                 {
612                         _left = left;
613                         _right = right;
614                 }
615
616                 public override Expression Optimize ()
617                 {
618                         _left = _left.Optimize ();
619                         _right = _right.Optimize ();
620                         return this;
621                 }
622
623                 public override bool HasStaticValue {
624                         get { return _left.HasStaticValue && _right.HasStaticValue; }
625                 }
626
627                 public override String ToString ()
628                 {
629                         return _left.ToString () + ' ' + Operator + ' ' + _right.ToString ();
630                 }
631                 protected abstract String Operator { get; }
632
633                 internal override XPathNodeType EvaluatedNodeType {
634                         get {
635                                 if (_left.EvaluatedNodeType == _right.EvaluatedNodeType)
636                                         return _left.EvaluatedNodeType;
637                                 else
638                                         return XPathNodeType.All;
639                         }
640                 }
641
642                 internal override bool IsPositional {
643                         get { return _left.IsPositional || _right.IsPositional; }
644                 }
645
646                 internal override bool Peer {
647                         get { return _left.Peer && _right.Peer; }
648                 }
649         }
650
651         internal abstract class ExprBoolean : ExprBinary
652         {
653                 public ExprBoolean (Expression left, Expression right) : base (left, right) {}
654
655                 public override Expression Optimize ()
656                 {
657                         base.Optimize ();
658                         if (!HasStaticValue)
659                                 return this;
660                         else if (StaticValueAsBoolean)
661                                 return new XPathFunctionTrue (null);
662                         else
663                                 return new XPathFunctionFalse (null);
664                 }
665
666                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
667                 public override object Evaluate (BaseIterator iter)
668                 {
669                         return EvaluateBoolean (iter);
670                 }
671                 public override double EvaluateNumber (BaseIterator iter)
672                 {
673                         return EvaluateBoolean (iter) ? 1 : 0;
674                 }
675                 
676                 public override string EvaluateString (BaseIterator iter)
677                 {
678                         return EvaluateBoolean (iter) ? "true" : "false";
679                 }
680         }
681
682         internal class ExprOR : ExprBoolean
683         {
684                 public ExprOR (Expression left, Expression right) : base (left, right) {}
685                 protected override String Operator { get { return "or"; }}
686
687                 public override bool StaticValueAsBoolean {
688                         get { return HasStaticValue ? _left.StaticValueAsBoolean || _right.StaticValueAsBoolean : false; }
689                 }
690
691                 public override bool EvaluateBoolean (BaseIterator iter)
692                 {
693                         if (_left.EvaluateBoolean (iter))
694                                 return true;
695                         return _right.EvaluateBoolean (iter);
696                 }
697         }
698
699         internal class ExprAND : ExprBoolean
700         {
701                 public ExprAND (Expression left, Expression right) : base (left, right) {}
702                 protected override String Operator { get { return "and"; }}
703
704                 public override bool StaticValueAsBoolean {
705                         get { return HasStaticValue ? _left.StaticValueAsBoolean && _right.StaticValueAsBoolean : false; }
706                 }
707
708                 public override bool EvaluateBoolean (BaseIterator iter)
709                 {
710                         if (!_left.EvaluateBoolean (iter))
711                                 return false;
712                         return _right.EvaluateBoolean (iter);
713                 }
714         }
715
716         internal abstract class EqualityExpr : ExprBoolean
717         {
718                 bool trueVal;
719                 public EqualityExpr (Expression left, Expression right, bool trueVal) : base (left, right)
720                 {
721                         this.trueVal = trueVal;
722                 }
723
724                 public override bool StaticValueAsBoolean {
725                         get {
726                                 if (!HasStaticValue)
727                                         return false;
728                                 if ((_left.ReturnType == XPathResultType.Navigator || _right.ReturnType == XPathResultType.Navigator) && _left.ReturnType == _right.ReturnType)
729                                         return (_left.StaticValueAsNavigator.IsSamePosition (
730                                         _right.StaticValueAsNavigator))
731                                          == trueVal;
732                                 if (_left.ReturnType == XPathResultType.Boolean | _right.ReturnType == XPathResultType.Boolean)
733                                         return (_left.StaticValueAsBoolean == _right.StaticValueAsBoolean) == trueVal;
734                                 if (_left.ReturnType == XPathResultType.Number | _right.ReturnType == XPathResultType.Number)
735                                         return (_left.StaticValueAsNumber == _right.StaticValueAsNumber) == trueVal;
736                                 if (_left.ReturnType == XPathResultType.String | _right.ReturnType == XPathResultType.String)
737                                         return (_left.StaticValueAsString == _right.StaticValueAsString) == trueVal;
738                                 return _left.StaticValue == _right.StaticValue == trueVal;
739                         }
740                 }
741
742                 // FIXME: Avoid extraneous evaluation
743                 public override bool EvaluateBoolean (BaseIterator iter)
744                 {
745                         XPathResultType typeL = _left.GetReturnType (iter);
746                         XPathResultType typeR = _right.GetReturnType (iter);
747
748                         // TODO: avoid double evaluations
749                         if (typeL == XPathResultType.Any)
750                                 typeL = GetReturnType (_left.Evaluate (iter));
751                         if (typeR == XPathResultType.Any)
752                                 typeR = GetReturnType (_right.Evaluate (iter));
753
754                         // Regard RTF as string
755                         if (typeL == XPathResultType.Navigator)
756                                 typeL = XPathResultType.String;
757                         if (typeR == XPathResultType.Navigator)
758                                 typeR = XPathResultType.String;
759
760                         if (typeL == XPathResultType.NodeSet || typeR == XPathResultType.NodeSet)
761                         {
762                                 Expression left, right;
763                                 if (typeL != XPathResultType.NodeSet)
764                                 {
765                                         left = _right;
766                                         right = _left;
767                                         XPathResultType typeTmp = typeL;
768                                         typeL = typeR;
769                                         typeR = typeTmp;
770                                 }
771                                 else
772                                 {
773                                         left = _left;
774                                         right = _right;
775                                 }
776                                 if (typeR == XPathResultType.Boolean)
777                                 {
778                                         return left.EvaluateBoolean (iter) == right.EvaluateBoolean (iter) == trueVal;
779                                 }
780                                 else
781                                 {
782                                         BaseIterator iterL = left.EvaluateNodeSet (iter);
783                                         if (typeR == XPathResultType.Number)
784                                         {
785                                                 double dR = right.EvaluateNumber (iter);
786                                                 while (iterL.MoveNext ())
787                                                         if (XPathFunctions.ToNumber (iterL.Current.Value) == dR == trueVal)
788                                                                 return true;
789                                         }
790                                         else if (typeR == XPathResultType.String)
791                                         {
792                                                 string strR = right.EvaluateString (iter);
793                                                 while (iterL.MoveNext ())
794                                                         if (iterL.Current.Value == strR == trueVal)
795                                                                 return true;
796                                         }
797                                         else if (typeR == XPathResultType.NodeSet)
798                                         {
799                                                 BaseIterator iterR = right.EvaluateNodeSet (iter);
800                                                 ArrayList rgNodesL = new ArrayList ();
801                                                 while (iterL.MoveNext ())
802                                                         rgNodesL.Add (XPathFunctions.ToString (iterL.Current.Value));
803                                                 while (iterR.MoveNext ())
804                                                 {
805                                                         string strR = XPathFunctions.ToString (iterR.Current.Value);
806                                                         for (int l = 0; l < rgNodesL.Count; l++)
807                                                                 if ((strR == (string) rgNodesL [l]) == trueVal)
808                                                                         return true;
809                                                 }
810                                         }
811                                         return false;
812                                 }
813                         }
814                         else if (typeL == XPathResultType.Boolean || typeR == XPathResultType.Boolean)
815                                 return _left.EvaluateBoolean (iter) == _right.EvaluateBoolean (iter) == trueVal;
816                         else if (typeL == XPathResultType.Number || typeR == XPathResultType.Number)
817                                 return _left.EvaluateNumber (iter) == _right.EvaluateNumber (iter) == trueVal;
818                         else
819                                 return _left.EvaluateString (iter) == _right.EvaluateString (iter) == trueVal;
820                 }
821         }
822         
823         internal class ExprEQ : EqualityExpr
824         {
825                 public ExprEQ (Expression left, Expression right) : base (left, right, true) {}
826                 protected override String Operator { get { return "="; }}
827         }
828
829         internal class ExprNE : EqualityExpr
830         {
831                 public ExprNE (Expression left, Expression right) : base (left, right, false) {}
832                 protected override String Operator { get { return "!="; }}
833         }
834
835         internal abstract class RelationalExpr : ExprBoolean
836         {
837                 public RelationalExpr (Expression left, Expression right) : base (left, right) {}
838
839                 public override bool StaticValueAsBoolean {
840                         get { return HasStaticValue ? Compare (_left.StaticValueAsNumber, _right.StaticValueAsNumber) : false; }
841                 }
842
843                 // FIXME: Avoid extraneous evaluation.
844                 public override bool EvaluateBoolean (BaseIterator iter)
845                 {
846                         XPathResultType typeL = _left.GetReturnType (iter);
847                         XPathResultType typeR = _right.GetReturnType (iter);
848
849                         if (typeL == XPathResultType.Any)
850                                 typeL = GetReturnType (_left.Evaluate (iter));
851                         if (typeR == XPathResultType.Any)
852                                 typeR = GetReturnType (_right.Evaluate (iter));
853
854                         // Regard RTF as string
855                         if (typeL == XPathResultType.Navigator)
856                                 typeL = XPathResultType.String;
857                         if (typeR == XPathResultType.Navigator)
858                                 typeR = XPathResultType.String;
859
860                         if (typeL == XPathResultType.NodeSet || typeR == XPathResultType.NodeSet)
861                         {
862                                 bool fReverse = false;
863                                 Expression left, right;
864                                 if (typeL != XPathResultType.NodeSet)
865                                 {
866                                         fReverse = true;
867                                         left = _right;
868                                         right = _left;
869                                         XPathResultType typeTmp = typeL;
870                                         typeL = typeR;
871                                         typeR = typeTmp;
872                                 }
873                                 else
874                                 {
875                                         left = _left;
876                                         right = _right;
877                                 }
878                                 if (typeR == XPathResultType.Boolean)
879                                 {
880                                         bool fL = left.EvaluateBoolean (iter);
881                                         bool fR = right.EvaluateBoolean (iter);
882                                         return Compare (Convert.ToDouble (fL), Convert.ToDouble (fR), fReverse);
883                                 }
884                                 else
885                                 {
886                                         BaseIterator iterL = left.EvaluateNodeSet (iter);
887                                         if (typeR == XPathResultType.Number || typeR == XPathResultType.String)
888                                         {
889                                                 double dR = right.EvaluateNumber (iter);
890                                                 while (iterL.MoveNext ())
891                                                         if (Compare (XPathFunctions.ToNumber (iterL.Current.Value), dR, fReverse))
892                                                                 return true;
893                                         }
894                                         else if (typeR == XPathResultType.NodeSet)
895                                         {
896                                                 BaseIterator iterR = right.EvaluateNodeSet (iter);
897                                                 ArrayList rgNodesL = new ArrayList ();
898                                                 while (iterL.MoveNext ())
899                                                         rgNodesL.Add (XPathFunctions.ToNumber (iterL.Current.Value));
900                                                 while (iterR.MoveNext ())
901                                                 {
902                                                         double numR = XPathFunctions.ToNumber (iterR.Current.Value);
903                                                         for (int l = 0; l < rgNodesL.Count; l++)
904                                                                 if (Compare ((double) rgNodesL [l], numR))
905                                                                         return true;
906                                                 }
907                                         }
908                                         return false;
909                                 }
910                         }
911                         else
912                                 return Compare (_left.EvaluateNumber (iter), _right.EvaluateNumber (iter));
913                 }
914                 public abstract bool Compare (double arg1, double arg2);
915                 public bool Compare (double arg1, double arg2, bool fReverse)
916                 {
917                         if (fReverse)
918                                 return Compare (arg2, arg1);
919                         else
920                                 return Compare (arg1, arg2);
921                 }
922         }
923
924         internal class ExprGT : RelationalExpr
925         {
926                 public ExprGT (Expression left, Expression right) : base (left, right) {}
927                 protected override String Operator { get { return ">"; }}
928                 public override bool Compare (double arg1, double arg2)
929                 {
930                         return arg1 > arg2;
931                 }
932         }
933
934         internal class ExprGE : RelationalExpr
935         {
936                 public ExprGE (Expression left, Expression right) : base (left, right) {}
937                 protected override String Operator { get { return ">="; }}
938                 public override bool Compare (double arg1, double arg2)
939                 {
940                         return arg1 >= arg2;
941                 }
942         }
943
944         internal class ExprLT : RelationalExpr
945         {
946                 public ExprLT (Expression left, Expression right) : base (left, right) {}
947                 protected override String Operator { get { return "<"; }}
948                 public override bool Compare (double arg1, double arg2)
949                 {
950                         return arg1 < arg2;
951                 }
952         }
953
954         internal class ExprLE : RelationalExpr
955         {
956                 public ExprLE (Expression left, Expression right) : base (left, right) {}
957                 protected override String Operator { get { return "<="; }}
958                 public override bool Compare (double arg1, double arg2)
959                 {
960                         return arg1 <= arg2;
961                 }
962         }
963
964         internal abstract class ExprNumeric : ExprBinary
965         {
966                 public ExprNumeric (Expression left, Expression right) : base (left, right) {}
967                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
968
969                 public override Expression Optimize ()
970                 {
971                         base.Optimize ();
972                         return !HasStaticValue ?
973                                 (Expression) this :
974                                 new ExprNumber (StaticValueAsNumber);
975                 }
976
977                 public override object Evaluate (BaseIterator iter)
978                 {
979                         return EvaluateNumber (iter);
980                 }
981         }
982
983         internal class ExprPLUS : ExprNumeric
984         {
985                 public ExprPLUS (Expression left, Expression right) : base (left, right) {}
986                 protected override String Operator { get { return "+"; }}
987
988                 public override double StaticValueAsNumber {
989                         get { return HasStaticValue ? _left.StaticValueAsNumber + _right.StaticValueAsNumber: 0; }
990                 }
991
992                 public override double EvaluateNumber (BaseIterator iter)
993                 {
994                         return _left.EvaluateNumber (iter) + _right.EvaluateNumber (iter);
995                 }
996         }
997
998         internal class ExprMINUS : ExprNumeric
999         {
1000                 public ExprMINUS (Expression left, Expression right) : base (left, right) {}
1001                 protected override String Operator { get { return "-"; }}
1002
1003                 public override double StaticValueAsNumber {
1004                         get { return HasStaticValue ? _left.StaticValueAsNumber - _right.StaticValueAsNumber: 0; }
1005                 }
1006
1007                 public override double EvaluateNumber (BaseIterator iter)
1008                 {
1009                         return _left.EvaluateNumber (iter) - _right.EvaluateNumber (iter);
1010                 }
1011         }
1012
1013         internal class ExprMULT : ExprNumeric
1014         {
1015                 public ExprMULT (Expression left, Expression right) : base (left, right) {}
1016                 protected override String Operator { get { return "*"; }}
1017
1018                 public override double StaticValueAsNumber {
1019                         get { return HasStaticValue ? _left.StaticValueAsNumber * _right.StaticValueAsNumber: 0; }
1020                 }
1021
1022                 public override double EvaluateNumber (BaseIterator iter)
1023                 {
1024                         return _left.EvaluateNumber (iter) * _right.EvaluateNumber (iter);
1025                 }
1026         }
1027
1028         internal class ExprDIV : ExprNumeric
1029         {
1030                 public ExprDIV (Expression left, Expression right) : base (left, right) {}
1031                 protected override String Operator { get { return " div "; }}
1032
1033                 public override double StaticValueAsNumber {
1034                         get { return HasStaticValue ? _left.StaticValueAsNumber / _right.StaticValueAsNumber: 0; }
1035                 }
1036
1037                 public override double EvaluateNumber (BaseIterator iter)
1038                 {
1039                         return _left.EvaluateNumber (iter) / _right.EvaluateNumber (iter);
1040                 }
1041         }
1042
1043         internal class ExprMOD : ExprNumeric
1044         {
1045                 public ExprMOD (Expression left, Expression right) : base (left, right) {}
1046                 protected override String Operator { get { return "%"; }}
1047
1048                 public override double StaticValueAsNumber {
1049                         get { return HasStaticValue ? _left.StaticValueAsNumber % _right.StaticValueAsNumber: 0; }
1050                 }
1051
1052                 public override double EvaluateNumber (BaseIterator iter)
1053                 {
1054                         return _left.EvaluateNumber (iter) % _right.EvaluateNumber (iter);
1055                 }
1056         }
1057
1058         internal class ExprNEG : Expression
1059         {
1060                 Expression _expr;
1061                 public ExprNEG (Expression expr)
1062                 {
1063                         _expr = expr;
1064                 }
1065                 public override String ToString () { return "- " + _expr.ToString (); }
1066                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
1067
1068                 public override Expression Optimize ()
1069                 {
1070                         _expr = _expr.Optimize ();
1071                         return !HasStaticValue ?
1072                                 (Expression) this :
1073                                 new ExprNumber (StaticValueAsNumber);
1074                 }
1075
1076                 internal override bool Peer {
1077                         get { return _expr.Peer; }
1078                 }
1079
1080                 public override bool HasStaticValue {
1081                         get { return _expr.HasStaticValue; }
1082                 }
1083
1084                 public override double StaticValueAsNumber {
1085                         get { return _expr.HasStaticValue ? -1 * _expr.StaticValueAsNumber : 0; }
1086                 }
1087
1088                 public override object Evaluate (BaseIterator iter)
1089                 {
1090                         return - _expr.EvaluateNumber (iter);
1091                 }
1092                 
1093                 public override double EvaluateNumber (BaseIterator iter)
1094                 {
1095                         return - _expr.EvaluateNumber (iter);
1096                 }
1097
1098                 internal override bool IsPositional {
1099                         get { return _expr.IsPositional; }
1100                 }
1101         }
1102
1103
1104         internal abstract class NodeSet : Expression
1105         {
1106                 public override XPathResultType ReturnType { get { return XPathResultType.NodeSet; }}
1107
1108                 // For "peer and subtree" optimization. see:
1109                 // http://idealliance.org/papers/dx_xmle04/papers/02-03-02/02-03-02.html
1110                 internal abstract bool Subtree { get; }
1111         }
1112
1113         internal class ExprUNION : NodeSet
1114         {
1115                 internal Expression left, right;
1116                 public ExprUNION (Expression left, Expression right)
1117                 {
1118                         this.left = left;
1119                         this.right = right;
1120                 }
1121
1122                 public override Expression Optimize ()
1123                 {
1124                         left = left.Optimize ();
1125                         right = right.Optimize ();
1126                         return this;
1127                 }
1128
1129                 public override String ToString () { return left.ToString ()+ " | " + right.ToString (); }
1130                 public override object Evaluate (BaseIterator iter)
1131                 {
1132                         BaseIterator iterLeft = left.EvaluateNodeSet (iter);
1133                         BaseIterator iterRight = right.EvaluateNodeSet (iter);
1134                         return new UnionIterator (iter, iterLeft, iterRight);
1135                 }
1136
1137                 internal override XPathNodeType EvaluatedNodeType {
1138                         get { return left.EvaluatedNodeType == right.EvaluatedNodeType ? left.EvaluatedNodeType : XPathNodeType.All; }
1139                 }
1140
1141                 internal override bool IsPositional {
1142                         get { return left.IsPositional || right.IsPositional; }
1143                 }
1144
1145                 internal override bool Peer {
1146                         get { return left.Peer && right.Peer; }
1147                 }
1148
1149                 internal override bool Subtree {
1150                         get {
1151                                 NodeSet nl = left as NodeSet;
1152                                 NodeSet nr = right as NodeSet;
1153                                 return nl != null && nr != null && nl.Subtree && nr.Subtree;
1154                         }
1155                 }
1156         }
1157
1158         internal class ExprSLASH : NodeSet
1159         {
1160                 public Expression left;
1161                 public NodeSet right;
1162                 public ExprSLASH (Expression left, NodeSet right)
1163                 {
1164                         this.left = left;
1165                         this.right = right;
1166                 }
1167
1168                 public override Expression Optimize ()
1169                 {
1170                         left = left.Optimize ();
1171                         right = (NodeSet) right.Optimize ();
1172                         return this;
1173                 }
1174
1175                 public override String ToString () { return left.ToString ()+ "/" + right.ToString (); }
1176                 public override object Evaluate (BaseIterator iter)
1177                 {
1178                         // Peer and subtree optimization. see
1179                         // http://idealliance.org/papers/dx_xmle04/papers/02-03-02/02-03-02.html
1180                         BaseIterator iterLeft = left.EvaluateNodeSet (iter);
1181                         if (left.Peer && right.Subtree && !RequireSorting)
1182                                 return new SimpleSlashIterator (iterLeft, right);
1183                         return new SlashIterator (iterLeft, right, RequireSorting);
1184                 }
1185
1186                 public override bool RequireSorting { get { return left.RequireSorting || right.RequireSorting; } }
1187
1188                 internal override XPathNodeType EvaluatedNodeType {
1189                         get { return right.EvaluatedNodeType; }
1190                 }
1191
1192                 internal override bool IsPositional {
1193                         get { return left.IsPositional || right.IsPositional; }
1194                 }
1195
1196                 internal override bool Peer {
1197                         get { return left.Peer && right.Peer; }
1198                 }
1199
1200                 internal override bool Subtree {
1201                         get {
1202                                 NodeSet n = left as NodeSet;
1203                                 return n != null && n.Subtree && right.Subtree;
1204                         }
1205                 }
1206         }
1207         
1208         internal class ExprSLASH2 : NodeSet {
1209                 public Expression left;
1210                 public NodeSet right;
1211                         
1212                 static NodeTest DescendantOrSelfStar = new NodeTypeTest (Axes.DescendantOrSelf, XPathNodeType.All);
1213
1214                 public ExprSLASH2 (Expression left, NodeSet right)
1215                 {
1216                         this.left = left;
1217                         this.right = right;
1218                 }
1219
1220                 public override Expression Optimize ()
1221                 {
1222                         left = left.Optimize ();
1223                         right = (NodeSet) right.Optimize ();
1224                         // Path A//B is equal to 
1225                         // A/descendant-or-self::node()/child::B, which is
1226                         // equivalent to A/descendant::B. Unlike '//', '/'
1227                         // could be optimized by SimpleSlashIterator.
1228                         NodeTest rnt = right as NodeTest;
1229                         if (rnt != null && rnt.Axis.Axis == Axes.Child) {
1230                                 NodeNameTest nameTest = rnt as NodeNameTest;
1231                                 if (nameTest != null)
1232                                         return new ExprSLASH (left,
1233                                                 new NodeNameTest (nameTest, Axes.Descendant));
1234                                 NodeTypeTest typeTest = rnt as NodeTypeTest;
1235                                 if (typeTest != null)
1236                                         return new ExprSLASH (left,
1237                                                 new NodeTypeTest (typeTest, Axes.Descendant));
1238                         }
1239                         return this;
1240                 }
1241
1242                 public override String ToString () { return left.ToString ()+ "//" + right.ToString (); }
1243                 public override object Evaluate (BaseIterator iter)
1244                 {
1245                         BaseIterator il = left.EvaluateNodeSet (iter);
1246                         if (left.Peer && !left.RequireSorting)
1247                                 il = new SimpleSlashIterator (
1248                                         il, DescendantOrSelfStar);
1249                         else
1250                                 il = new SlashIterator (il,
1251                                         DescendantOrSelfStar,
1252                                         left.RequireSorting);
1253
1254                         return new SlashIterator (
1255                                 il,
1256                                 right,
1257                                 DescendantOrSelfStar.RequireSorting || right.RequireSorting
1258                         );
1259                 }
1260
1261                 public override bool RequireSorting { get { return left.RequireSorting || right.RequireSorting; } }
1262
1263                 internal override XPathNodeType EvaluatedNodeType {
1264                         get { return right.EvaluatedNodeType; }
1265                 }
1266
1267                 internal override bool IsPositional {
1268                         get { return left.IsPositional || right.IsPositional; }
1269                 }
1270
1271                 internal override bool Peer {
1272                         get { return false; }
1273                 }
1274
1275                 internal override bool Subtree {
1276                         get {
1277                                 NodeSet n = left as NodeSet;
1278                                 return n != null && n.Subtree && right.Subtree;
1279                         }
1280                 }
1281         }
1282
1283         internal class ExprRoot : NodeSet
1284         {
1285                 public override String ToString () { return ""; }
1286                 public override object Evaluate (BaseIterator iter)
1287                 {
1288                         XPathNavigator navRoot = iter.Current.Clone ();
1289                         navRoot.MoveToRoot ();
1290                         return new SelfIterator (navRoot, iter.NamespaceManager);
1291                 }
1292
1293                 internal override XPathNodeType EvaluatedNodeType {
1294                         get { return XPathNodeType.Root; }
1295                 }
1296
1297                 internal override bool Peer {
1298                         get { return true; }
1299                 }
1300
1301                 internal override bool Subtree {
1302                         get { return false; }
1303                 }
1304         }
1305
1306         internal enum Axes
1307         {
1308                 Ancestor,
1309                 AncestorOrSelf,
1310                 Attribute,
1311                 Child,
1312                 Descendant,
1313                 DescendantOrSelf,
1314                 Following,
1315                 FollowingSibling,
1316                 Namespace,
1317                 Parent,
1318                 Preceding,
1319                 PrecedingSibling,
1320                 Self,
1321         }
1322
1323         internal class AxisSpecifier
1324         {
1325                 protected Axes _axis;
1326                 public AxisSpecifier (Axes axis)
1327                 {
1328                         _axis = axis;
1329                 }
1330                 public XPathNodeType NodeType
1331                 {
1332                         get
1333                         {
1334                                 switch (_axis)
1335                                 {
1336                                 case Axes.Namespace:
1337                                         return XPathNodeType.Namespace;
1338                                 case Axes.Attribute:
1339                                         return XPathNodeType.Attribute;
1340                                 default:
1341                                         return XPathNodeType.Element;
1342                                 }
1343                         }
1344                 }
1345                 public override string ToString ()
1346                 {
1347                         switch (_axis)
1348                         {
1349                                 case Axes.Ancestor:
1350                                         return "ancestor";
1351                                 case Axes.AncestorOrSelf:
1352                                         return "ancestor-or-self";
1353                                 case Axes.Attribute:
1354                                         return "attribute";
1355                                 case Axes.Child:
1356                                         return "child";
1357                                 case Axes.Descendant:
1358                                         return "descendant";
1359                                 case Axes.DescendantOrSelf:
1360                                         return "descendant-or-self";
1361                                 case Axes.Following:
1362                                         return "following";
1363                                 case Axes.FollowingSibling:
1364                                         return "following-sibling";
1365                                 case Axes.Namespace:
1366                                         return "namespace";
1367                                 case Axes.Parent:
1368                                         return "parent";
1369                                 case Axes.Preceding:
1370                                         return "preceding";
1371                                 case Axes.PrecedingSibling:
1372                                         return "preceding-sibling";
1373                                 case Axes.Self:
1374                                         return "self";
1375                                 default:
1376                                         throw new IndexOutOfRangeException ();
1377                         }
1378                 }
1379                 public Axes Axis { get { return _axis; }}
1380                 public virtual SimpleIterator Evaluate (BaseIterator iter)
1381                 {
1382                         switch (_axis)
1383                         {
1384                                 case Axes.Ancestor:
1385                                         return new AncestorIterator (iter);
1386                                 case Axes.AncestorOrSelf:
1387                                         return new AncestorOrSelfIterator (iter);
1388                                 case Axes.Attribute:
1389                                         return new AttributeIterator (iter);
1390                                 case Axes.Child:
1391                                         return new ChildIterator (iter);
1392                                 case Axes.Descendant:
1393                                         return new DescendantIterator (iter);
1394                                 case Axes.DescendantOrSelf:
1395                                         return new DescendantOrSelfIterator (iter);
1396                                 case Axes.Following:
1397                                         return new FollowingIterator (iter);
1398                                 case Axes.FollowingSibling:
1399                                         return new FollowingSiblingIterator (iter);
1400                                 case Axes.Namespace:
1401                                         return new NamespaceIterator (iter);
1402                                 case Axes.Parent:
1403                                         return new ParentIterator (iter);
1404                                 case Axes.Preceding:
1405                                         return new PrecedingIterator (iter);
1406                                 case Axes.PrecedingSibling:
1407                                         return new PrecedingSiblingIterator (iter);
1408                                 case Axes.Self:
1409                                         return new SelfIterator (iter);
1410                                 default:
1411                                         throw new IndexOutOfRangeException ();
1412                         }
1413                 }
1414         }
1415
1416         internal abstract class NodeTest : NodeSet
1417         {
1418                 protected AxisSpecifier _axis;
1419                 public NodeTest (Axes axis)
1420                 {
1421                         _axis = new AxisSpecifier (axis);
1422                 }
1423                 public abstract bool Match (NSResolver nsm, XPathNavigator nav);
1424                 public AxisSpecifier Axis { get { return _axis; }}
1425                 public override object Evaluate (BaseIterator iter)
1426                 {
1427                         SimpleIterator iterAxis = _axis.Evaluate (iter);
1428                         return new AxisIterator (iterAxis, this);
1429                 }
1430                 
1431                 public abstract void GetInfo (out string name, out string ns, out XPathNodeType nodetype, NSResolver nsm);
1432
1433                 public override bool RequireSorting {
1434                         get {
1435                                 switch (_axis.Axis) {
1436                                 case Axes.Ancestor:
1437                                 case Axes.AncestorOrSelf:
1438                                 case Axes.Preceding:
1439                                 case Axes.PrecedingSibling:
1440                                 case Axes.Attribute:
1441                                 case Axes.Namespace:
1442                                         return true;
1443                                 default:
1444                                         return false;
1445                                 }
1446                         }
1447
1448                 }
1449
1450                 internal override bool Peer {
1451                         get {
1452                                 switch (_axis.Axis) {
1453                                 case Axes.Ancestor:
1454                                 case Axes.AncestorOrSelf:
1455                                 case Axes.DescendantOrSelf:
1456                                 case Axes.Descendant:
1457                                 case Axes.Preceding:
1458                                 case Axes.Following:
1459                                         return false;
1460                                 default:
1461                                         return true;
1462                                 }
1463                         }
1464                 }
1465
1466                 internal override bool Subtree {
1467                         get {
1468                                 switch (_axis.Axis) {
1469                                 case Axes.Parent:
1470                                 case Axes.Ancestor:
1471                                 case Axes.AncestorOrSelf:
1472                                 case Axes.Preceding:
1473                                 case Axes.Following:
1474                                         return false;
1475                                 default:
1476                                         return true;
1477                                 }
1478                         }
1479
1480                 }
1481
1482                 internal override XPathNodeType EvaluatedNodeType {
1483                         get { return _axis.NodeType; }
1484                 }
1485         }
1486
1487         internal class NodeTypeTest : NodeTest
1488         {
1489                 public readonly XPathNodeType type;
1490                 protected String _param;
1491                 public NodeTypeTest (Axes axis) : base (axis)
1492                 {
1493                         this.type = _axis.NodeType;
1494                 }
1495                 public NodeTypeTest (Axes axis, XPathNodeType type) : base (axis)
1496                 {
1497                         this.type = type;
1498                 }
1499                 // FIXME: Better description
1500                 public NodeTypeTest (Axes axis, XPathNodeType type, String param) : base (axis)
1501                 {
1502                         this.type = type;
1503                         _param = param;
1504                         if (param != null && type != XPathNodeType.ProcessingInstruction)
1505                                 throw new XPathException ("No argument allowed for "+ToString (type)+"() test");        // TODO: better description
1506                 }
1507
1508                 // for optimizer use
1509                 internal NodeTypeTest (NodeTypeTest other, Axes axis)
1510                         : base (axis)
1511                 {
1512                         type = other.type;
1513                         _param = other._param;
1514                 }
1515
1516                 public override String ToString ()
1517                 {
1518                         String strType = ToString (type);
1519                         if (type == XPathNodeType.ProcessingInstruction && _param != null)
1520                                 strType += "('" + _param + "')";
1521                         else
1522                                 strType += "()";
1523
1524                         return _axis.ToString () + "::" + strType;
1525                 }
1526
1527                 private static String ToString (XPathNodeType type)
1528                 {
1529                         switch (type)
1530                         {
1531                                 case XPathNodeType.Comment:
1532                                         return "comment";
1533                                 case XPathNodeType.Text:
1534                                         return "text";
1535                                 case XPathNodeType.ProcessingInstruction:
1536                                         return "processing-instruction";
1537                                 case XPathNodeType.All:
1538                                 case XPathNodeType.Attribute:
1539                                 case XPathNodeType.Element:
1540                                 case XPathNodeType.Namespace:
1541                                         return "node";
1542                                 default:
1543                                         return "node-type [" + type.ToString () + "]";
1544                         }
1545                 }
1546
1547                 public override bool Match (NSResolver nsm, XPathNavigator nav)
1548                 {
1549                         XPathNodeType nodeType = nav.NodeType;
1550                         switch (type)
1551                         {
1552                                 case XPathNodeType.All:
1553                                         return true;
1554
1555                                 case XPathNodeType.ProcessingInstruction:
1556                                         if (nodeType != XPathNodeType.ProcessingInstruction)
1557                                                 return false;
1558                                         if (_param != null && nav.Name != _param)
1559                                                 return false;
1560                                         return true;
1561                                 
1562                                 case XPathNodeType.Text:
1563                                         switch (nodeType) {
1564                                         case XPathNodeType.Text:
1565                                         case XPathNodeType.Whitespace:
1566                                         case XPathNodeType.SignificantWhitespace:
1567                                                 return true;
1568                                         default:
1569                                                 return false;
1570                                         }
1571                                 default:
1572                                         return type == nodeType;
1573                         }
1574                 }
1575                 
1576                 public override void GetInfo (out string name, out string ns, out XPathNodeType nodetype, NSResolver nsm)
1577                 {
1578                         name = _param;
1579                         ns = null;
1580                         nodetype = type;
1581                 }
1582         }
1583
1584         internal class NodeNameTest : NodeTest
1585         {
1586                 protected XmlQualifiedName _name;
1587                 protected readonly bool resolvedName = false;
1588                 public NodeNameTest (Axes axis, XmlQualifiedName name, IStaticXsltContext ctx) : base (axis)
1589                 {
1590                         if (ctx != null) {
1591                                 name = ctx.LookupQName (name.ToString ());
1592                                 resolvedName = true;
1593                         }
1594                         _name = name;
1595                 }
1596                 
1597                 public NodeNameTest (Axes axis, XmlQualifiedName name, bool resolvedName) : base (axis)
1598                 {
1599                         _name = name;
1600                         this.resolvedName = resolvedName;
1601                 }
1602
1603                 // for optimized path rewrite
1604                 internal NodeNameTest (NodeNameTest source, Axes axis)
1605                         : base (axis)
1606                 {
1607                         _name = source._name;
1608                         resolvedName = source.resolvedName;
1609                 }
1610
1611                 public override String ToString () { return _axis.ToString () + "::" + _name.ToString (); }
1612                 
1613                 public XmlQualifiedName Name { get { return _name; } }
1614
1615                 public override bool Match (NSResolver nsm, XPathNavigator nav)
1616                 {
1617                         // must be the correct node type
1618                         if (nav.NodeType != _axis.NodeType)
1619                                 return false;
1620
1621                         if (_name.Name != "")
1622                         {
1623                                 // test the local part of the name first
1624                                 if (_name.Name != nav.LocalName)
1625                                         return false;
1626                         }
1627
1628                         // get the prefix for the given name
1629                         String strURI1 = "";
1630                         if (_name.Namespace != "")
1631                         {
1632                                 if (resolvedName)
1633                                         strURI1 = _name.Namespace;
1634                                 else if (nsm != null)
1635 // We still need to have such tricky switch, because the behavior is 
1636 // inconsistent between .NET 1.x and 2.0 when the argument is not
1637 // atomic string.
1638 #if NET_2_0
1639                                         strURI1 = nsm.LookupNamespace (_name.Namespace);
1640 #else
1641                                         strURI1 = nsm.LookupNamespace (_name.Namespace, false);
1642 #endif
1643                                 if (strURI1 == null)
1644                                         throw new XPathException ("Invalid namespace prefix: "+_name.Namespace);
1645                         }
1646
1647                         // test the prefixes
1648                         return strURI1 == nav.NamespaceURI;
1649                 }
1650                 
1651                 public override void GetInfo (out string name, out string ns, out XPathNodeType nodetype, NSResolver nsm)
1652                 {
1653                         // must be the correct node type
1654                         nodetype = _axis.NodeType;
1655                         
1656                         if (_name.Name != "")
1657                                 name = _name.Name;
1658                         else
1659                                 name = null;
1660                         ns = "";
1661                         if (nsm != null && _name.Namespace != "") {
1662                                 if (resolvedName)
1663                                         ns = _name.Namespace;
1664                                 else
1665 // We still need to have such tricky switch, because the behavior is 
1666 // inconsistent between .NET 1.x and 2.0 when the argument is not
1667 // atomic string.
1668 #if NET_2_0
1669                                         ns = nsm.LookupNamespace (_name.Namespace);     // TODO: check to see if this returns null or ""
1670 #else
1671                                         ns = nsm.LookupNamespace (_name.Namespace, false);      // TODO: check to see if this returns null or ""
1672 #endif
1673                                 if (ns == null)
1674                                         throw new XPathException ("Invalid namespace prefix: "+_name.Namespace);
1675                         }
1676                 }
1677         }
1678
1679         internal class ExprFilter : NodeSet
1680         {
1681                 internal Expression expr, pred;
1682                 
1683                 public ExprFilter (Expression expr, Expression pred)
1684                 {
1685                         this.expr = expr;
1686                         this.pred = pred;
1687                 }
1688
1689                 public override Expression Optimize ()
1690                 {
1691                         expr = expr.Optimize ();
1692                         pred = pred.Optimize ();
1693                         return this;
1694                 }
1695                 
1696                 internal Expression LeftHandSide {get{return expr;}}
1697                 public override String ToString () { return "(" + expr.ToString () + ")[" + pred.ToString () + "]"; }
1698                 public override object Evaluate (BaseIterator iter)
1699                 {
1700                         BaseIterator iterExpr = expr.EvaluateNodeSet (iter);
1701                         return new PredicateIterator (iterExpr, pred);
1702                 }
1703
1704                 internal override XPathNodeType EvaluatedNodeType {
1705                         get { return expr.EvaluatedNodeType; }
1706                 }
1707
1708                 internal override bool IsPositional {
1709                         get {
1710                                 if (pred.ReturnType == XPathResultType.Number)
1711                                         return true;
1712                                 return expr.IsPositional || pred.IsPositional;
1713                         }
1714                 }
1715
1716                 internal override bool Peer {
1717                         get { return expr.Peer && pred.Peer; }
1718                 }
1719
1720                 internal override bool Subtree {
1721                         get {
1722                                 NodeSet n = expr as NodeSet;
1723                                 return n != null && n.Subtree;
1724                         }
1725                 }
1726         }
1727
1728         internal class ExprNumber : Expression
1729         {
1730                 protected double _value;
1731                 public ExprNumber (double value)
1732                 {
1733                         _value = value;
1734                 }
1735                 public override String ToString () { return _value.ToString (); }
1736                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
1737
1738                 internal override bool Peer {
1739                         get { return true; }
1740                 }
1741
1742                 public override bool HasStaticValue {
1743                         get { return true; }
1744                 }
1745
1746                 public override double StaticValueAsNumber {
1747                         get { return XPathFunctions.ToNumber (_value); }
1748                 }
1749
1750                 public override object Evaluate (BaseIterator iter)
1751                 {
1752                         return _value;
1753                 }
1754                 
1755                 public override double EvaluateNumber (BaseIterator iter)
1756                 {
1757                         return _value;
1758                 }
1759
1760                 internal override bool IsPositional {
1761                         get { return false; }
1762                 }
1763         }
1764
1765         internal class BooleanConstant : Expression
1766         {
1767                 bool _value;
1768
1769                 public BooleanConstant (bool value)
1770                 {
1771                         _value = value;
1772                 }
1773
1774                 public override String ToString () { return _value ? "true()" : "false()"; }
1775                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
1776
1777                 internal override bool Peer {
1778                         get { return true; }
1779                 }
1780
1781                 public override bool HasStaticValue {
1782                         get { return true; }
1783                 }
1784
1785                 public override bool StaticValueAsBoolean {
1786                         get { return _value; }
1787                 }
1788
1789                 public override object Evaluate (BaseIterator iter)
1790                 {
1791                         return _value;
1792                 }
1793                 
1794                 public override bool EvaluateBoolean (BaseIterator iter)
1795                 {
1796                         return _value;
1797                 }
1798         }
1799
1800         internal class ExprLiteral : Expression
1801         {
1802                 protected String _value;
1803                 public ExprLiteral (String value)
1804                 {
1805                         _value = value;
1806                 }
1807                 public string Value { get { return _value; } }
1808                 public override String ToString () { return "'" + _value + "'"; }
1809                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
1810
1811                 internal override bool Peer {
1812                         get { return true; }
1813                 }
1814
1815                 public override bool HasStaticValue {
1816                         get { return true; }
1817                 }
1818
1819                 public override string StaticValueAsString {
1820                         get { return _value; }
1821                 }
1822
1823                 public override object Evaluate (BaseIterator iter)
1824                 {
1825                         return _value;
1826                 }
1827                 
1828                 public override string EvaluateString (BaseIterator iter)
1829                 {
1830                         return _value;
1831                 }
1832         }
1833
1834         internal class ExprVariable : Expression
1835         {
1836                 protected XmlQualifiedName _name;
1837                 protected bool resolvedName = false;
1838                 public ExprVariable (XmlQualifiedName name, IStaticXsltContext ctx)
1839                 {
1840                         if (ctx != null) {
1841                                 name = ctx.LookupQName (name.ToString ());
1842                                 resolvedName = true;
1843                         }
1844                         
1845                         _name = name;
1846                 }
1847                 public override String ToString () { return "$" + _name.ToString (); }
1848                 public override XPathResultType ReturnType { get { return XPathResultType.Any; }}
1849                 public override XPathResultType GetReturnType (BaseIterator iter)
1850                 {
1851                         return XPathResultType.Any;
1852                 }
1853                 
1854                 public override object Evaluate (BaseIterator iter)
1855                 {
1856                         IXsltContextVariable var = null;
1857                         
1858                         XsltContext context = iter.NamespaceManager as XsltContext;
1859                         if (context != null) {
1860                                 if (resolvedName)
1861                                         var = context.ResolveVariable (_name);
1862                                 else
1863                                         var = context.ResolveVariable (new XmlQualifiedName (_name.Name, _name.Namespace));
1864                         }
1865                         
1866                         if (var == null)
1867                                 throw new XPathException ("variable "+_name.ToString ()+" not found");
1868                         object objResult = var.Evaluate (context);
1869                         XPathNodeIterator iterResult = objResult as XPathNodeIterator;
1870                         if (iterResult != null)
1871                                 return iterResult is BaseIterator ? iterResult : new WrapperIterator (iterResult, iter.NamespaceManager);
1872                         return objResult;
1873                 }
1874
1875                 internal override bool Peer {
1876                         get { return false; }
1877                 }
1878         }
1879
1880         internal class ExprParens : Expression
1881         {
1882                 protected Expression _expr;
1883                 public ExprParens (Expression expr)
1884                 {
1885                         _expr = expr;
1886                 }
1887
1888                 public override Expression Optimize ()
1889                 {
1890                         _expr.Optimize ();
1891                         return this;
1892                 }
1893
1894                 public override bool HasStaticValue {
1895                         get { return _expr.HasStaticValue; }
1896                 }
1897
1898                 public override object StaticValue {
1899                         get { return _expr.StaticValue; }
1900                 }
1901
1902                 public override string StaticValueAsString {
1903                         get { return _expr.StaticValueAsString; }
1904                 }
1905
1906                 public override double StaticValueAsNumber {
1907                         get { return _expr.StaticValueAsNumber; }
1908                 }
1909
1910                 public override bool StaticValueAsBoolean {
1911                         get { return _expr.StaticValueAsBoolean; }
1912                 }
1913
1914                 public override String ToString () { return "(" + _expr.ToString () + ")"; }
1915                 public override XPathResultType ReturnType { get { return _expr.ReturnType; }}
1916                 public override object Evaluate (BaseIterator iter)
1917                 {
1918                         object o = (_expr.Evaluate (iter));
1919                         BaseIterator predBase = o as BaseIterator;
1920                         if (predBase != null)
1921                                 return new ParensIterator (predBase);
1922                         else
1923                                 return o;
1924                 }
1925
1926                 internal override XPathNodeType EvaluatedNodeType {
1927                         get { return _expr.EvaluatedNodeType; }
1928                 }
1929
1930                 internal override bool IsPositional {
1931                         get { return _expr.IsPositional; }
1932                 }
1933
1934                 internal override bool Peer {
1935                         get { return _expr.Peer; }
1936                 }
1937         }
1938
1939         internal class FunctionArguments
1940         {
1941                 protected Expression _arg;
1942                 protected FunctionArguments _tail;
1943                 public FunctionArguments (Expression arg, FunctionArguments tail)
1944                 {
1945                         _arg = arg;
1946                         _tail = tail;
1947                 }
1948                 public Expression Arg
1949                 {
1950                         get { return _arg; }
1951                 }
1952                 public FunctionArguments Tail
1953                 {
1954                         get { return _tail; }
1955                 }
1956                 
1957                 public void ToArrayList (ArrayList a)
1958                 {
1959                         FunctionArguments cur = this;
1960                         
1961                         do {
1962                                 a.Add (cur._arg);
1963                                 cur = cur._tail;
1964                         } while (cur != null);
1965                         
1966                 }
1967         }
1968
1969         internal class ExprFunctionCall : Expression
1970         {
1971                 protected readonly XmlQualifiedName _name;
1972                 protected readonly bool resolvedName = false;
1973                 protected readonly ArrayList _args = new ArrayList ();
1974                 public ExprFunctionCall (XmlQualifiedName name, FunctionArguments args, IStaticXsltContext ctx)
1975                 {
1976                         if (ctx != null) {
1977                                 name = ctx.LookupQName (name.ToString ());
1978                                 resolvedName = true;
1979                         }
1980                         
1981                         _name = name;
1982                         if (args != null)
1983                                 args.ToArrayList (_args);
1984                 }
1985                 
1986                 public static Expression Factory (XmlQualifiedName name, FunctionArguments args, IStaticXsltContext ctx)
1987                 {
1988                         if (name.Namespace != null && name.Namespace != "")
1989                                 return new ExprFunctionCall (name, args, ctx);
1990                         
1991                         switch (name.Name) {
1992                                 case "last": return new XPathFunctionLast (args);
1993                                 case "position": return new XPathFunctionPosition (args);
1994                                 case "count": return new XPathFunctionCount (args);
1995                                 case "id": return new XPathFunctionId (args);
1996                                 case "local-name": return new XPathFunctionLocalName (args);
1997                                 case "namespace-uri": return new XPathFunctionNamespaceUri (args);
1998                                 case "name": return new XPathFunctionName (args);
1999                                 case "string": return new XPathFunctionString (args);
2000                                 case "concat": return new XPathFunctionConcat (args);
2001                                 case "starts-with": return new XPathFunctionStartsWith (args);
2002                                 case "contains": return new XPathFunctionContains (args);
2003                                 case "substring-before": return new XPathFunctionSubstringBefore (args);
2004                                 case "substring-after": return new XPathFunctionSubstringAfter (args);
2005                                 case "substring": return new XPathFunctionSubstring (args);
2006                                 case "string-length": return new XPathFunctionStringLength (args);
2007                                 case "normalize-space": return new XPathFunctionNormalizeSpace (args);
2008                                 case "translate": return new XPathFunctionTranslate (args);
2009                                 case "boolean": return new XPathFunctionBoolean (args);
2010                                 case "not": return new XPathFunctionNot (args);
2011                                 case "true": return new XPathFunctionTrue (args);
2012                                 case "false": return new XPathFunctionFalse (args);
2013                                 case "lang": return new XPathFunctionLang (args);
2014                                 case "number": return new XPathFunctionNumber (args);
2015                                 case "sum": return new XPathFunctionSum (args);
2016                                 case "floor": return new XPathFunctionFloor (args);
2017                                 case "ceiling": return new XPathFunctionCeil (args);
2018                                 case "round": return new XPathFunctionRound (args);
2019                         }
2020                         return new ExprFunctionCall (name, args, ctx);
2021                 }
2022                 
2023                 public override String ToString ()
2024                 {
2025                         String strArgs = "";
2026                         for (int i = 0; i < _args.Count; i++) {
2027                                 Expression arg = (Expression) _args [i];
2028                                 if (strArgs != "")
2029                                         strArgs += ", ";
2030                                 strArgs += arg.ToString ();
2031                         }
2032                         return _name.ToString () + '(' + strArgs + ')';
2033                 }
2034                 public override XPathResultType ReturnType { get { return XPathResultType.Any; }}
2035                 public override XPathResultType GetReturnType (BaseIterator iter)
2036                 {
2037                         return XPathResultType.Any;
2038                 }
2039                 
2040                 private XPathResultType [] GetArgTypes (BaseIterator iter)
2041                 {
2042                         // TODO: can we cache these? what if the types depend on the nsm?
2043                         XPathResultType [] rgArgs = new XPathResultType [_args.Count];
2044                         for (int iArg = 0; iArg < _args.Count; iArg++)
2045                                 rgArgs [iArg] = ((Expression) _args [iArg]).GetReturnType (iter);
2046                         return rgArgs;
2047                 }
2048                 public override object Evaluate (BaseIterator iter)
2049                 {
2050                         XPathResultType [] rgTypes = GetArgTypes (iter);
2051                         IXsltContextFunction func = null;
2052                         XsltContext context = iter.NamespaceManager as XsltContext;
2053                         if (context != null) {
2054                                 if (resolvedName)
2055                                         func = context.ResolveFunction (_name, rgTypes);
2056                                 else
2057                                         func = context.ResolveFunction (_name.Namespace, _name.Name, rgTypes);
2058                         }
2059
2060                         if (func == null)
2061                                 throw new XPathException ("function "+_name.ToString ()+" not found");
2062
2063                         object [] rgArgs = new object [_args.Count];
2064                         if (func.Maxargs != 0)
2065                         {
2066                                 XPathResultType [] rgFuncTypes = func.ArgTypes;
2067                                 for (int iArg = 0; iArg < _args.Count; iArg ++)
2068                                 {
2069                                         XPathResultType typeArg;
2070                                         if (rgFuncTypes == null)
2071                                                 typeArg = XPathResultType.Any;
2072                                         else if (iArg < rgFuncTypes.Length)
2073                                                 typeArg = rgFuncTypes [iArg];
2074                                         else
2075                                                 typeArg = rgFuncTypes [rgFuncTypes.Length - 1];
2076
2077                                         Expression arg = (Expression) _args [iArg];
2078                                         object result = arg.EvaluateAs (iter, typeArg);
2079                                         rgArgs [iArg] = result;
2080                                 }
2081                         }
2082                         return func.Invoke (context, rgArgs, iter.Current);
2083                 }
2084
2085                 internal override bool Peer {
2086                         get { return false; }
2087                 }
2088         }
2089 }