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