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