2002-09-21 Piers Haken <piersh@friskit.com>
[mono.git] / mcs / class / System.XML / System.Xml.XPath / Expression.cs
1 //
2 // System.Xml.XPath.XPathExpression support classes
3 //
4 // Author:
5 //   Piers Haken (piersh@friskit.com)
6 //
7 // (C) 2002 Piers Haken
8 //
9 using System;
10 using System.IO;
11 using System.Collections;
12 using System.Xml;
13 using System.Xml.XPath;
14 using System.Xml.Xsl;
15
16 namespace System.Xml.XPath
17 {
18 #if XPATH_DEBUG
19         internal class CompiledExpression : Test.Xml.XPath.XPathExpression
20 #else
21         internal class CompiledExpression : XPathExpression
22 #endif
23         {
24                 protected XmlNamespaceManager _nsm;
25                 protected Expression _expr;
26
27                 public CompiledExpression (Expression expr)
28                 {
29                         _expr = expr;
30                 }
31                 private CompiledExpression (CompiledExpression other)
32                 {
33                         _nsm = other._nsm;
34                         _expr = other._expr;
35                 }
36 #if XPATH_DEBUG
37                 public override Test.Xml.XPath.XPathExpression Clone () { return new CompiledExpression (this); }
38 #else
39                 public override XPathExpression Clone () { return new CompiledExpression (this); }
40 #endif
41
42                 public override void SetContext (XmlNamespaceManager nsManager)
43                 {
44                         _nsm = nsManager;
45                 }
46                 public override String Expression { get { return _expr.ToString (); }}
47                 public override XPathResultType ReturnType { get { return _expr.ReturnType; }}
48                 [MonoTODO]
49                 public override void AddSort (Object obj, IComparer cmp)
50                 {
51                         throw new NotImplementedException ();
52                 }
53                 [MonoTODO]
54                 public override void AddSort(object obj, XmlSortOrder sortOrder, XmlCaseOrder caseOrder, string str, XmlDataType type)
55                 {
56                         throw new NotImplementedException ();
57                 }
58
59                 public object Evaluate (BaseIterator iter)
60                 {
61                         try
62                         {
63                                 return _expr.Evaluate (iter);
64                         }
65                         catch (XPathException e)
66                         {
67                                 throw e;
68                         }
69                         catch (Exception e)
70                         {
71                                 throw new XPathException ("Error during evaluation", e);
72                         }
73                 }
74                 public XPathNodeIterator EvaluateNodeSet (BaseIterator iter)
75                 {
76                         try
77                         {
78                                 return _expr.EvaluateNodeSet (iter);
79                         }
80                         catch (XPathException e)
81                         {
82                                 throw e;
83                         }
84                         catch (Exception e)
85                         {
86                                 throw new XPathException ("Error during evaluation", e);
87                         }
88                 }
89         }
90
91
92         /// <summary>
93         /// Summary description for Expression.
94         /// </summary>
95         internal abstract class Expression
96         {
97                 public Expression ()
98                 {
99                 }
100                 public abstract XPathResultType ReturnType { get; }
101                 public virtual XPathResultType GetReturnType (BaseIterator iter) { return ReturnType; }
102                 public virtual object Evaluate (BaseIterator iter) { return null; }
103
104                 public BaseIterator EvaluateNodeSet (BaseIterator iter)
105                 {
106                         if (GetReturnType (iter) == XPathResultType.NodeSet)
107                                 return (BaseIterator) Evaluate (iter);
108                         throw new XPathException ("expected nodeset: "+ToString ());
109                 }
110                 [MonoTODO]
111                 public double EvaluateNumber (BaseIterator iter)
112                 {
113                         object result;
114                         XPathResultType type = GetReturnType (iter);
115                         if (type == XPathResultType.NodeSet)
116                         {
117                                 result = EvaluateString (iter);
118                                 type = XPathResultType.String;
119                         }
120                         else
121                                 result = Evaluate (iter);
122
123                         switch (type)
124                         {
125                                 case XPathResultType.Number:
126                                         return (double) result;
127                                 case XPathResultType.Boolean:
128                                         return Convert.ToDouble ((bool) result);
129                                 case XPathResultType.String:
130                                         return XmlConvert.ToDouble ((string) result);   // TODO: spec? convert string to number
131                                 default:
132                                         throw new XPathException ("invalid node type"); // TODO: handle other types
133                         }
134                 }
135                 [MonoTODO]
136                 public string EvaluateString (BaseIterator iter)
137                 {
138                         object result = Evaluate (iter);
139                         switch (GetReturnType (iter))
140                         {
141                                 case XPathResultType.Number:
142                                         return (string) XmlConvert.ToString ((double) result);  // TODO: spec? convert number to string
143                                 case XPathResultType.Boolean:
144                                         return ((bool) result) ? "true" : "false";
145                                 case XPathResultType.String:
146                                         return (string) result;
147                                 case XPathResultType.NodeSet:
148                                 {
149                                         BaseIterator iterResult = (BaseIterator) result;
150                                         if (iterResult == null || !iterResult.MoveNext ())
151                                                 return "";
152                                         return iterResult.Current.Value;
153                                 }
154                                 default:
155                                         throw new XPathException ("invalid node type"); // TODO: handle other types
156                         }
157                 }
158                 [MonoTODO]
159                 public bool EvaluateBoolean (BaseIterator iter)
160                 {
161                         object result = Evaluate (iter);
162                         switch (GetReturnType (iter))
163                         {
164                                 case XPathResultType.Number:
165                                 {
166                                         double num = (double) result;
167                                         return (num != 0.0 && num != -0.0 && num != Double.NaN);
168                                 }
169                                 case XPathResultType.Boolean:
170                                         return (bool) result;
171                                 case XPathResultType.String:
172                                         return ((string) result).Length != 0;
173                                 case XPathResultType.NodeSet:
174                                 {
175                                         BaseIterator iterResult = (BaseIterator) result;
176                                         return (iterResult != null && iterResult.MoveNext ());
177                                 }
178                                 default:
179                                         throw new XPathException ("invalid node type"); // TODO: handle other types
180                         }
181                 }
182         }
183
184         internal abstract class ExprBinary : Expression
185         {
186                 protected Expression _left, _right;
187
188                 public ExprBinary (Expression left, Expression right)
189                 {
190                         _left = left;
191                         _right = right;
192                 }
193                 public override String ToString ()
194                 {
195                         return _left.ToString () + ' ' + Operator + ' ' + _right.ToString ();
196                 }
197                 protected abstract String Operator { get; }
198         }
199
200         internal abstract class ExprBoolean : ExprBinary
201         {
202                 public ExprBoolean (Expression left, Expression right) : base (left, right) {}
203                 public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
204         }
205
206         internal class ExprOR : ExprBoolean
207         {
208                 public ExprOR (Expression left, Expression right) : base (left, right) {}
209                 protected override String Operator { get { return "or"; }}
210                 public override object Evaluate (BaseIterator iter)
211                 {
212                         if (_left.EvaluateBoolean (iter))
213                                 return true;
214                         return _right.EvaluateBoolean (iter);
215                 }
216         }
217         internal class ExprAND : ExprBoolean
218         {
219                 public ExprAND (Expression left, Expression right) : base (left, right) {}
220                 protected override String Operator { get { return "and"; }}
221                 public override object Evaluate (BaseIterator iter)
222                 {
223                         if (!_left.EvaluateBoolean (iter))
224                                 return false;
225                         return _right.EvaluateBoolean (iter);
226                 }
227         }
228
229         internal abstract class EqualityExpr : ExprBoolean
230         {
231                 public EqualityExpr (Expression left, Expression right) : base (left, right) {}
232                 [MonoTODO]
233                 public override object Evaluate (BaseIterator iter)
234                 {
235                         XPathResultType typeL = _left.GetReturnType (iter);
236                         XPathResultType typeR = _right.GetReturnType (iter);
237                         if (typeL == XPathResultType.NodeSet || typeR == XPathResultType.NodeSet)
238                         {
239                                 Expression left, right;
240                                 if (typeL != XPathResultType.NodeSet)
241                                 {
242                                         left = _right;
243                                         right = _left;
244                                         XPathResultType typeTmp = typeL;
245                                         typeL = typeR;
246                                         typeR = typeTmp;
247                                 }
248                                 else
249                                 {
250                                         left = _left;
251                                         right = _right;
252                                 }
253                                 if (typeR == XPathResultType.Boolean)
254                                 {
255                                         bool fL = left.EvaluateBoolean (iter);
256                                         bool fR = right.EvaluateBoolean (iter);
257                                         return Compare (Convert.ToDouble (fL), Convert.ToDouble (fR));
258                                 }
259                                 else
260                                 {
261                                         BaseIterator iterL = left.EvaluateNodeSet (iter);
262                                         if (typeR == XPathResultType.Number)
263                                         {
264                                                 double dR = right.EvaluateNumber (iter);
265                                                 while (iterL.MoveNext ())
266                                                         if (Compare (XPathFunctions.ToNumber (iterL.Current.Value), dR))
267                                                                 return true;
268                                         }
269                                         else if (typeR == XPathResultType.String)
270                                         {
271                                                 string strR = right.EvaluateString (iter);
272                                                 while (iterL.MoveNext ())
273                                                         if (Compare (iterL.Current.Value, strR))
274                                                                 return true;
275                                         }
276                                         else if (typeR == XPathResultType.NodeSet)
277                                         {
278                                                 BaseIterator iterR = right.EvaluateNodeSet (iter);
279                                                 ArrayList rgNodesL = new ArrayList ();
280                                                 while (iterL.MoveNext ())
281                                                         rgNodesL.Add (XPathFunctions.ToString (iterL.Current.Value));
282                                                 while (iterR.MoveNext ())
283                                                 {
284                                                         string strR = XPathFunctions.ToString (iterR.Current.Value);
285                                                         foreach (string strL in rgNodesL)
286                                                                 if (Compare (strL, strR))
287                                                                         return true;
288                                                 }
289                                         }
290                                         return false;
291                                 }
292                         }
293                         else if (typeL == XPathResultType.Boolean || typeR == XPathResultType.Boolean)
294                                 return Compare (_left.EvaluateBoolean (iter), _right.EvaluateBoolean (iter));
295                         else if (typeL == XPathResultType.Number || typeR == XPathResultType.Number)
296                                 return Compare (_left.EvaluateNumber (iter), _right.EvaluateNumber (iter));
297                         else
298                                 return Compare (_left.EvaluateString (iter), _right.EvaluateString (iter));
299                 }
300                 [MonoTODO]
301                 public abstract bool Compare (object arg1, object arg2);        // TODO: should probably have type-safe methods here
302         }
303         
304         internal class ExprEQ : EqualityExpr
305         {
306                 public ExprEQ (Expression left, Expression right) : base (left, right) {}
307                 protected override String Operator { get { return "="; }}
308                 public override bool Compare (object arg1, object arg2)
309                 {
310                         return arg1.Equals (arg2);
311                 }
312         }
313         internal class ExprNE : EqualityExpr
314         {
315                 public ExprNE (Expression left, Expression right) : base (left, right) {}
316                 protected override String Operator { get { return "!="; }}
317                 public override bool Compare (object arg1, object arg2)
318                 {
319                         return !arg1.Equals (arg2);
320                 }
321         }
322
323         internal abstract class RelationalExpr : ExprBoolean
324         {
325                 public RelationalExpr (Expression left, Expression right) : base (left, right) {}
326                 [MonoTODO]
327                 public override object Evaluate (BaseIterator iter)
328                 {
329                         XPathResultType typeL = _left.GetReturnType (iter);
330                         XPathResultType typeR = _right.GetReturnType (iter);
331                         if (typeL == XPathResultType.NodeSet || typeR == XPathResultType.NodeSet)
332                         {
333                                 bool fReverse = false;
334                                 Expression left, right;
335                                 if (typeL != XPathResultType.NodeSet)
336                                 {
337                                         fReverse = true;
338                                         left = _right;
339                                         right = _left;
340                                         XPathResultType typeTmp = typeL;
341                                         typeL = typeR;
342                                         typeR = typeTmp;
343                                 }
344                                 else
345                                 {
346                                         left = _left;
347                                         right = _right;
348                                 }
349                                 if (typeR == XPathResultType.Boolean)
350                                 {
351                                         bool fL = left.EvaluateBoolean (iter);
352                                         bool fR = right.EvaluateBoolean (iter);
353                                         return Compare (Convert.ToDouble (fL), Convert.ToDouble (fR), fReverse);
354                                 }
355                                 else
356                                 {
357                                         BaseIterator iterL = left.EvaluateNodeSet (iter);
358                                         if (typeR == XPathResultType.Number || typeR == XPathResultType.String)
359                                         {
360                                                 double dR = right.EvaluateNumber (iter);
361                                                 while (iterL.MoveNext ())
362                                                         if (Compare (XPathFunctions.ToNumber (iterL.Current.Value), dR, fReverse))
363                                                                 return true;
364                                         }
365                                         else if (typeR == XPathResultType.NodeSet)
366                                         {
367                                                 BaseIterator iterR = right.EvaluateNodeSet (iter);
368                                                 ArrayList rgNodesL = new ArrayList ();
369                                                 while (iterL.MoveNext ())
370                                                         rgNodesL.Add (XPathFunctions.ToNumber (iterL.Current.Value));
371                                                 while (iterR.MoveNext ())
372                                                 {
373                                                         double numR = XPathFunctions.ToNumber (iterR.Current.Value);
374                                                         foreach (double numL in rgNodesL)
375                                                                 if (Compare (numL, numR))
376                                                                         return true;
377                                                 }
378                                         }
379                                         return false;
380                                 }
381                         }
382                         else
383                                 return Compare (_left.EvaluateNumber (iter), _right.EvaluateNumber (iter));
384                 }
385                 public abstract bool Compare (double arg1, double arg2);
386                 public bool Compare (double arg1, double arg2, bool fReverse)
387                 {
388                         if (fReverse)
389                                 return Compare (arg2, arg1);
390                         else
391                                 return Compare (arg1, arg2);
392                 }
393         }
394         internal class ExprGT : RelationalExpr
395         {
396                 public ExprGT (Expression left, Expression right) : base (left, right) {}
397                 protected override String Operator { get { return ">"; }}
398                 public override bool Compare (double arg1, double arg2)
399                 {
400                         return arg1 > arg2;
401                 }
402         }
403         internal class ExprGE : RelationalExpr
404         {
405                 public ExprGE (Expression left, Expression right) : base (left, right) {}
406                 protected override String Operator { get { return ">="; }}
407                 public override bool Compare (double arg1, double arg2)
408                 {
409                         return arg1 >= arg2;
410                 }
411         }
412         internal class ExprLT : RelationalExpr
413         {
414                 public ExprLT (Expression left, Expression right) : base (left, right) {}
415                 protected override String Operator { get { return "<"; }}
416                 public override bool Compare (double arg1, double arg2)
417                 {
418                         return arg1 < arg2;
419                 }
420         }
421         internal class ExprLE : RelationalExpr
422         {
423                 public ExprLE (Expression left, Expression right) : base (left, right) {}
424                 protected override String Operator { get { return "<="; }}
425                 public override bool Compare (double arg1, double arg2)
426                 {
427                         return arg1 <= arg2;
428                 }
429         }
430
431
432         internal abstract class ExprNumeric : ExprBinary
433         {
434                 public ExprNumeric (Expression left, Expression right) : base (left, right) {}
435                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
436         }
437
438         internal class ExprPLUS : ExprNumeric
439         {
440                 public ExprPLUS (Expression left, Expression right) : base (left, right) {}
441                 protected override String Operator { get { return "+"; }}
442                 public override object Evaluate (BaseIterator iter)
443                 {
444                         return _left.EvaluateNumber (iter) + _right.EvaluateNumber (iter);
445                 }
446         }
447         internal class ExprMINUS : ExprNumeric
448         {
449                 public ExprMINUS (Expression left, Expression right) : base (left, right) {}
450                 protected override String Operator { get { return "-"; }}
451                 public override object Evaluate (BaseIterator iter)
452                 {
453                         return _left.EvaluateNumber (iter) - _right.EvaluateNumber (iter);
454                 }
455         }
456         internal class ExprMULT : ExprNumeric
457         {
458                 public ExprMULT (Expression left, Expression right) : base (left, right) {}
459                 protected override String Operator { get { return "*"; }}
460                 public override object Evaluate (BaseIterator iter)
461                 {
462                         return _left.EvaluateNumber (iter) * _right.EvaluateNumber (iter);
463                 }
464         }
465         internal class ExprDIV : ExprNumeric
466         {
467                 public ExprDIV (Expression left, Expression right) : base (left, right) {}
468                 protected override String Operator { get { return "/"; }}
469                 public override object Evaluate (BaseIterator iter)
470                 {
471                         return _left.EvaluateNumber (iter) / _right.EvaluateNumber (iter);
472                 }
473         }
474         internal class ExprMOD : ExprNumeric
475         {
476                 public ExprMOD (Expression left, Expression right) : base (left, right) {}
477                 protected override String Operator { get { return "%"; }}
478                 [MonoTODO]
479                 public override object Evaluate (BaseIterator iter)
480                 {
481                         return _left.EvaluateNumber (iter) % _right.EvaluateNumber (iter);      // TODO: spec?
482                 }
483         }
484         internal class ExprNEG : Expression
485         {
486                 Expression _expr;
487                 public ExprNEG (Expression expr)
488                 {
489                         _expr = expr;
490                 }
491                 public override String ToString () { return "- " + _expr.ToString (); }
492                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
493                 public override object Evaluate (BaseIterator iter)
494                 {
495                         return - _expr.EvaluateNumber (iter);
496                 }
497         }
498
499
500         internal abstract class NodeSet : Expression
501         {
502                 public override XPathResultType ReturnType { get { return XPathResultType.NodeSet; }}
503         }
504         internal class ExprUNION : NodeSet
505         {
506                 protected Expression _left, _right;
507                 public ExprUNION (NodeSet left, NodeSet right)
508                 {
509                         _left = left;
510                         _right = right;
511                 }
512                 public override String ToString () { return _left.ToString ()+ " | " + _right.ToString (); }
513                 public override object Evaluate (BaseIterator iter)
514                 {
515                         BaseIterator iterLeft = _left.EvaluateNodeSet (iter);
516                         BaseIterator iterRight = _right.EvaluateNodeSet (iter);
517                         return new UnionIterator (iter, iterLeft, iterRight);
518                 }
519         }
520         internal class ExprSLASH : NodeSet
521         {
522                 protected Expression _left, _right;
523                 public ExprSLASH (Expression left, NodeSet right)
524                 {
525                         _left = left;
526                         _right = right;
527                 }
528                 public override String ToString () { return _left.ToString ()+ "/" + _right.ToString (); }
529                 public override object Evaluate (BaseIterator iter)
530                 {
531                         BaseIterator iterLeft = _left.EvaluateNodeSet (iter);
532                         return new SlashIterator (iterLeft, _right);
533                 }
534         }
535         internal class ExprRoot : NodeSet
536         {
537                 public override String ToString () { return ""; }
538                 public override object Evaluate (BaseIterator iter)
539                 {
540                         XPathNavigator navRoot = iter.Current.Clone ();
541                         navRoot.MoveToRoot ();
542                         return new SelfIterator (navRoot, iter.Context);
543                 }
544         }
545
546         internal enum Axes
547         {
548                 Ancestor,
549                 AncestorOrSelf,
550                 Attribute,
551                 Child,
552                 Descendant,
553                 DescendantOrSelf,
554                 Following,
555                 FollowingSibling,
556                 Namespace,
557                 Parent,
558                 Preceding,
559                 PrecedingSibling,
560                 Self,
561         }
562
563         internal class AxisSpecifier
564         {
565                 protected Axes _axis;
566                 public AxisSpecifier (Axes axis)
567                 {
568                         _axis = axis;
569                 }
570                 public XPathNodeType NodeType
571                 {
572                         get
573                         {
574                                 switch (_axis)
575                                 {
576                                         case Axes.Namespace:
577                                                 return XPathNodeType.Namespace;
578                                         case Axes.Attribute:
579                                                 return XPathNodeType.Attribute;
580                                         default:
581                                                 return XPathNodeType.Element;
582                                 }
583                         }
584                 }
585                 public override string ToString ()
586                 {
587                         switch (_axis)
588                         {
589                                 case Axes.Ancestor:
590                                         return "ancestor";
591                                 case Axes.AncestorOrSelf:
592                                         return "ancestor-or-self";
593                                 case Axes.Attribute:
594                                         return "attribute";
595                                 case Axes.Child:
596                                         return "child";
597                                 case Axes.Descendant:
598                                         return "descendant";
599                                 case Axes.DescendantOrSelf:
600                                         return "descendant-or-self";
601                                 case Axes.Following:
602                                         return "following";
603                                 case Axes.FollowingSibling:
604                                         return "following-sibling";
605                                 case Axes.Namespace:
606                                         return "namespace";
607                                 case Axes.Parent:
608                                         return "parent";
609                                 case Axes.Preceding:
610                                         return "preceeding";
611                                 case Axes.PrecedingSibling:
612                                         return "preceeding-sibling";
613                                 case Axes.Self:
614                                         return "self";
615                                 default:
616                                         throw new IndexOutOfRangeException ();
617                         }
618                 }
619                 public Axes Axis { get { return _axis; }}
620                 public virtual BaseIterator Evaluate (BaseIterator iter)
621                 {
622                         switch (_axis)
623                         {
624                                 case Axes.Ancestor:
625                                         return new AncestorIterator (iter);
626                                 case Axes.AncestorOrSelf:
627                                         return new AncestorOrSelfIterator (iter);
628                                 case Axes.Attribute:
629                                         return new AttributeIterator (iter);
630                                 case Axes.Child:
631                                         return new ChildIterator (iter);
632                                 case Axes.Descendant:
633                                         return new DescendantIterator (iter);
634                                 case Axes.DescendantOrSelf:
635                                         return new DescendantOrSelfIterator (iter);
636                                 case Axes.Following:
637                                         return new FollowingIterator (iter);
638                                 case Axes.FollowingSibling:
639                                         return new FollowingSiblingIterator (iter);
640                                 case Axes.Namespace:
641                                         return new NamespaceIterator (iter);
642                                 case Axes.Parent:
643                                         return new ParentIterator (iter);
644                                 case Axes.Preceding:
645                                         return new PrecedingIterator (iter);
646                                 case Axes.PrecedingSibling:
647                                         return new PrecedingSiblingIterator (iter);
648                                 case Axes.Self:
649                                         return new SelfIterator (iter);
650                                 default:
651                                         throw new IndexOutOfRangeException ();
652                         }
653                 }
654         }
655
656         internal abstract class NodeTest
657         {
658                 protected AxisSpecifier _axis;
659                 public NodeTest (AxisSpecifier axis)
660                 {
661                         _axis = axis;
662                 }
663                 public NodeTest (Axes axis)
664                 {
665                         _axis = new AxisSpecifier (axis);
666                 }
667                 public abstract bool Match (XsltContext context, XPathNavigator nav);
668                 public AxisSpecifier Axis { get { return _axis; }}
669                 public virtual BaseIterator Evaluate (BaseIterator iter)
670                 {
671                         BaseIterator iterAxis = _axis.Evaluate (iter);
672                         return new AxisIterator (iterAxis, this);
673                 }
674         }
675
676         internal class NodeTypeTest : NodeTest
677         {
678                 protected XPathNodeType _type;
679                 protected String _param;
680                 public NodeTypeTest (Axes axis) : base (axis)
681                 {
682                         _type = _axis.NodeType;
683                 }
684                 public NodeTypeTest (Axes axis, XPathNodeType type) : base (axis)
685                 {
686                         _type = type;
687                 }
688                 [MonoTODO]
689                 public NodeTypeTest (Axes axis, XPathNodeType type, String param) : base (axis)
690                 {
691                         _type = type;
692                         _param = param;
693                         if (param != null && type != XPathNodeType.ProcessingInstruction)
694                                 throw new XPathException ("No argument allowed for "+ToString (_type)+"() test");       // TODO: better description
695                 }
696                 public override String ToString ()
697                 {
698                         String strType = ToString (_type);
699                         if (_type == XPathNodeType.ProcessingInstruction && _param != null)
700                                 strType += "('" + _param + "')";
701                         else
702                                 strType += "()";
703
704                         return _axis.ToString () + "::" + strType;
705                 }
706                 private static String ToString (XPathNodeType type)
707                 {
708                         switch (type)
709                         {
710                                 case XPathNodeType.Comment:
711                                         return "comment";
712                                 case XPathNodeType.Text:
713                                         return "text";
714                                 case XPathNodeType.ProcessingInstruction:
715                                         return "processing-instruction";
716                                 case XPathNodeType.All:
717                                 case XPathNodeType.Attribute:
718                                 case XPathNodeType.Element:
719                                         return "node";
720                                 default:
721                                         throw new NotImplementedException ();
722                         }
723                 }
724                 public override bool Match (XsltContext context, XPathNavigator nav)
725                 {
726                         XPathNodeType nodeType = nav.NodeType;
727                         switch (_type)
728                         {
729                                 case XPathNodeType.All:
730                                         return true;
731
732                                 case XPathNodeType.ProcessingInstruction:
733                                         if (nodeType != XPathNodeType.ProcessingInstruction)
734                                                 return false;
735                                         if (_param != null && nav.Name != _param)
736                                                 return false;
737                                         return true;
738                                 
739                                 default:
740                                         return _type == nodeType;
741                         }
742                 }
743         }
744         internal class NodeNameTest : NodeTest
745         {
746                 protected QName _name;
747                 public NodeNameTest (Axes axis, QName name) : base (axis)
748                 {
749                         _name = name;
750                 }
751                 public override String ToString () { return _axis.ToString () + "::" + _name.ToString (); }
752                 [MonoTODO]
753                 public override bool Match (XsltContext context, XPathNavigator nav)
754                 {
755                         // must be the correct node type
756                         if (nav.NodeType != _axis.NodeType)
757                                 return false;
758
759                         if (_name.Local != null && _name.Local != "")
760                         {
761                                 // test the local part of the name first
762                                 if (_name.Local != nav.LocalName)
763                                         return false;
764                         }
765
766                         // get the prefix for the given name
767                         String strURI1 = "";
768                         if (_name.Prefix != null)
769                         {
770                                 strURI1 = context.LookupNamespace (_name.Prefix);       // TODO: check to see if this returns null or ""
771                                 if (strURI1 == null)
772                                         throw new XPathException ("Invalid namespace prefix: "+_name.Prefix);
773                         }
774
775                         string strURI = nav.NamespaceURI;
776                         if (strURI == null && strURI1 == "")    // TODO: remove when bug #26855 fixed
777                                 return true;
778
779                         // test the prefixes
780                         return strURI1 == nav.NamespaceURI;
781                 }
782         }
783
784         internal class ExprStep : NodeSet
785         {
786                 protected NodeTest _test;
787                 protected Expression [] _preds;
788                 public ExprStep (NodeTest test, ExprPredicates preds)
789                 {
790                         _test = test;
791                         if (preds != null)
792                                 _preds = preds.GetPredicates ();
793                 }
794                 public ExprStep (NodeTest test)
795                 {
796                         _test = test;
797                 }
798                 public override String ToString ()
799                 {
800                         String strExpr = _test.ToString ();
801                         if (_preds != null)
802                         {
803                                 foreach (Expression pred in _preds)
804                                 {
805                                         strExpr += '[' + pred.ToString () + ']';
806                                 }
807                         }
808                         return strExpr;
809                 }
810                 public override object Evaluate (BaseIterator iter)
811                 {
812                         BaseIterator iterStep = _test.Evaluate (iter);
813                         if (_preds == null)
814                                 return iterStep;
815
816                         return new PredicateIterator (iterStep, _preds);
817                 }
818         }
819
820
821         internal class ExprPredicates
822         {
823                 protected Expression _pred;
824                 protected ExprPredicates _tail;
825                 public ExprPredicates (Expression pred, ExprPredicates tail)
826                 {
827                         _pred = pred;
828                         _tail = tail;
829                 }
830                 public ExprPredicates (Expression pred)
831                 {
832                         _pred = pred;
833                 }
834                 public Expression [] GetPredicates ()
835                 {
836                         ArrayList lstPreds = new ArrayList ();
837                         ExprPredicates curr = this;
838                         while (curr != null)
839                         {
840                                 lstPreds.Add (curr._pred);
841                                 curr = curr._tail;
842                         }
843                         return (Expression []) lstPreds.ToArray (typeof (Expression));
844                 }
845         }
846
847         internal class ExprFilter : Expression
848         {
849                 protected Expression _expr;
850                 protected Expression _pred;
851                 public ExprFilter (Expression expr, Expression pred)
852                 {
853                         _expr = expr;
854                         _pred = pred;
855                 }
856                 public override String ToString () { return "(" + _expr.ToString () + ")[" + _pred.ToString () + "]"; }
857                 public override XPathResultType ReturnType { get { return XPathResultType.NodeSet; }}
858         }
859
860         internal class QName
861         {
862                 protected String _prefix;
863                 protected String _local;
864                 public QName (String prefix, String local)
865                 {
866                         _prefix = prefix;
867                         _local = local;
868                 }
869                 public override String ToString ()
870                 {
871                         String strLocal = (_local != null) ? _local : "*";
872                         if (_prefix != null)
873                                 return _prefix + ':' + strLocal;
874                         return strLocal;
875                 }
876                 public String Prefix { get { return _prefix; } }
877                 public String Local { get { return _local; } }
878         }
879         internal class NCName : QName
880         {
881                 public NCName (String local) : base (null, local) {}
882         }
883
884         internal class ExprNumber : Expression
885         {
886                 protected double _value;
887                 public ExprNumber (double value)
888                 {
889                         _value = value;
890                 }
891                 public override String ToString () { return _value.ToString (); }
892                 public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
893                 public override object Evaluate (BaseIterator iter)
894                 {
895                         return _value;
896                 }
897         }
898         internal class ExprLiteral : Expression
899         {
900                 protected String _value;
901                 public ExprLiteral (String value)
902                 {
903                         _value = value;
904                 }
905                 public override String ToString () { return "'" + _value + "'"; }
906                 public override XPathResultType ReturnType { get { return XPathResultType.String; }}
907                 public override object Evaluate (BaseIterator iter)
908                 {
909                         return _value;
910                 }
911         }
912
913         internal class ExprVariable : Expression
914         {
915                 protected QName _name;
916                 public ExprVariable (QName name)
917                 {
918                         _name = name;
919                 }
920                 public override String ToString () { return "$" + _name.ToString (); }
921                 public override XPathResultType ReturnType { get { return XPathResultType.Any; }}
922                 public override XPathResultType GetReturnType (BaseIterator iter)
923                 {
924                         IXsltContextVariable var = iter.Context.ResolveVariable (_name.Prefix, _name.Local);
925                         return var.VariableType;
926                 }
927         }
928
929         internal class FunctionArguments
930         {
931                 protected Expression _arg;
932                 protected FunctionArguments _tail;
933                 public FunctionArguments (Expression arg, FunctionArguments tail)
934                 {
935                         _arg = arg;
936                         _tail = tail;
937                 }
938                 public Expression Arg
939                 {
940                         get { return _arg; }
941                 }
942                 public FunctionArguments Tail
943                 {
944                         get { return _tail; }
945                 }
946         }
947         internal class ExprFunctionCall : Expression
948         {
949                 protected QName _name;
950                 protected ArrayList _args = new ArrayList ();
951                 public ExprFunctionCall (String name, FunctionArguments args)
952                 {
953                         _name = new NCName (name);
954                         while (args != null)
955                         {
956                                 _args.Add (args.Arg);
957                                 args = args.Tail;
958                         }
959                 }
960                 public override String ToString ()
961                 {
962                         String strArgs = "";
963                         foreach (Expression arg in _args)
964                         {
965                                 if (strArgs != "")
966                                         strArgs += ", ";
967                                 strArgs += arg.ToString ();
968                         }
969                         return _name.ToString () + '(' + strArgs + ')';
970                 }
971                 public override XPathResultType ReturnType { get { return XPathResultType.Any; }}
972                 public override XPathResultType GetReturnType (BaseIterator iter)
973                 {
974                         IXsltContextFunction func = iter.Context.ResolveFunction (_name.Prefix, _name.Local, GetArgTypes (iter));
975                         return func.ReturnType;
976                 }
977                 private XPathResultType [] GetArgTypes (BaseIterator iter)
978                 {
979                         // TODO: can we cache these? what if the types depend on the context?
980                         XPathResultType [] rgArgs = new XPathResultType [_args.Count];
981                         for (int iArg = 0; iArg < _args.Count; iArg++)
982                                 rgArgs [iArg] = ((Expression) _args [iArg]).GetReturnType (iter);
983                         return rgArgs;
984                 }
985                 public override object Evaluate (BaseIterator iter)
986                 {
987                         //special-case the 'last' and 'position' functions
988                         if (_args.Count == 0 && _name.Prefix == null)
989                         {
990                                 if (_name.Local == "last")
991                                 {
992                                         return (double) iter.Count;
993                                 }
994                                 else if (_name.Local == "position")
995                                 {
996                                         return (double) iter.CurrentPosition;
997                                 }
998                         }
999
1000                         XPathResultType [] rgTypes = GetArgTypes (iter);
1001                         //FIXME: what if func == null after next line?
1002                         IXsltContextFunction func = iter.Context.ResolveFunction (_name.Prefix, _name.Local, rgTypes);
1003                         object [] rgArgs = new object [_args.Count];
1004                         for (int iArg = 0; iArg < _args.Count; iArg ++)
1005                                 rgArgs [iArg] = ((Expression) _args [iArg]).Evaluate (iter);
1006                         return func.Invoke (iter.Context, rgArgs, iter.Current);
1007                 }
1008         }
1009 }