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