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