* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / System.XML / System.Xml.XPath / DefaultContext.cs
index ed27d168858b47e3e0210da870aa562631477ea2..96ec9fc2a1cdc5b2f632dc4a5da60e399d327af2 100644 (file)
 //
 // (C) 2002 Piers Haken
 //
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
 using System;
 using System.Collections;
+using System.Globalization;
 using System.Xml;
 using System.Xml.XPath;
 using System.Xml.Xsl;
+using System.Text;
 
 namespace System.Xml.XPath
 {
-       /// <summary>
-       /// Summary description for DefaultContext.
-       /// </summary>
-       internal class DefaultContext : XsltContext
-       {
-               protected static Hashtable _htFunctions = new Hashtable ();
-
-               static DefaultContext()
-               {
-                       Add (new XPathFunctionLast ());
-                       Add (new XPathFunctionPosition ());
-                       Add (new XPathFunctionCount ());
-                       Add (new XPathFunctionId ());
-                       Add (new XPathFunctionLocalName ());
-                       Add (new XPathFunctionNamespaceUri ());
-                       Add (new XPathFunctionName ());
-                       Add (new XPathFunctionString ());
-                       Add (new XPathFunctionConcat ());
-                       Add (new XPathFunctionStartsWith ());
-                       Add (new XPathFunctionContains ());
-                       Add (new XPathFunctionSubstringBefore ());
-                       Add (new XPathFunctionSubstringAfter ());
-                       Add (new XPathFunctionSubstring ());
-                       Add (new XPathFunctionStringLength ());
-                       Add (new XPathFunctionNormalizeSpace ());
-                       Add (new XPathFunctionTranslate ());
-                       Add (new XPathFunctionBoolean ());
-                       Add (new XPathFunctionNot ());
-                       Add (new XPathFunctionTrue ());
-                       Add (new XPathFunctionFalse ());
-                       Add (new XPathFunctionLang ());
-                       Add (new XPathFunctionNumber ());
-                       Add (new XPathFunctionSum ());
-                       Add (new XPathFunctionFloor ());
-                       Add (new XPathFunctionCeil ());
-                       Add (new XPathFunctionRound ());
-               }
-
-               [MonoTODO]
-               public override IXsltContextFunction ResolveFunction (string prefix, string name, XPathResultType[] ArgTypes)
-               {
-                       // match the prefix
-                       if (prefix != null && prefix != "")     // TODO: should we allow some namespaces here?
-                               return null;
-
-                       // match the function name
-                       XPathFunction fn = (XPathFunction) _htFunctions [name];
-                       if (fn == null)
-                               return null;
-
-                       // check the number of arguments
-                       int cArgs = ArgTypes.Length;
-                       if (cArgs < fn.Minargs || cArgs > fn.Maxargs)
-                               return null;
-
-                       // check the types of the arguments
-                       XPathResultType [] rgTypes = fn.ArgTypes;
-                       if (rgTypes == null)
-                       {
-                               if (cArgs != 0)
-                                       return null;
-                       }
-                       else
-                       {
-                               int cTypes = rgTypes.Length;
-                               for (int iArg = 0; iArg < cArgs; iArg ++)
-                               {
-                                       XPathResultType typeRequested = ArgTypes [iArg];
-                                       XPathResultType typeDefined = (iArg >= cTypes) ? rgTypes [cTypes - 1] : rgTypes [iArg];
-                                       if (typeDefined != XPathResultType.Any && typeDefined != typeRequested)
-                                               return null;
-                               }
-                       }
-                       return fn;
-               }
-               public override IXsltContextVariable ResolveVariable (string prefix, string name)
-               {
-                       return null;
-               }
-               [MonoTODO]
-               public override int CompareDocument (string baseUri, string nextBaseUri) { throw new NotImplementedException (); }
-               [MonoTODO]
-               public override bool PreserveWhitespace (XPathNavigator nav) { throw new NotImplementedException (); }
-               [MonoTODO]
-               public override bool Whitespace { get { throw new NotImplementedException (); }}
-               protected static void Add (XPathFunction fn)
-               {
-                       _htFunctions.Add (fn.Name, fn);
-               }
-       }
-
        internal class XPathFunctions
        {
                public static bool ToBoolean (object arg)
@@ -125,9 +57,33 @@ namespace System.Xml.XPath
                                BaseIterator iter = (BaseIterator) arg;
                                return iter.MoveNext ();
                        }
+                       if (arg is XPathNavigator)
+                       {
+                               return ToBoolean (((XPathNavigator) arg).SelectChildren (XPathNodeType.All));
+                       }
                        throw new ArgumentException ();
                }
-               [MonoTODO]
+
+               public static bool ToBoolean (bool b)
+               {
+                       return b;
+               }
+
+               public static bool ToBoolean (double d)
+               {
+                       return d != 0.0 && d != double.NaN;
+               }
+
+               public static bool ToBoolean (string s)
+               {
+                       return s != null && s.Length > 0;
+               }
+
+               public static bool ToBoolean (BaseIterator iter)
+               {
+                       return iter != null && iter.MoveNext ();
+               }
+
                public static string ToString (object arg)
                {
                        if (arg == null)
@@ -137,7 +93,7 @@ namespace System.Xml.XPath
                        if (arg is bool)
                                return ((bool) arg) ? "true" : "false";
                        if (arg is double)
-                               return ((double) arg).ToString ("R", System.Globalization.NumberFormatInfo.InvariantInfo);
+                               return ToString ((double) arg);
                        if (arg is BaseIterator)
                        {
                                BaseIterator iter = (BaseIterator) arg;
@@ -145,259 +101,582 @@ namespace System.Xml.XPath
                                        return "";
                                return iter.Current.Value;
                        }
+                       if (arg is XPathNavigator)
+                       {
+                               return ((XPathNavigator) arg).Value;
+                       }
                        throw new ArgumentException ();
                }
-               [MonoTODO]
+
+               public static string ToString (double d)
+               {
+                       // See XPath 1.0 section 4.2
+                       if (d == Double.NegativeInfinity)
+                               return "-Infinity";
+                       if (d == Double.PositiveInfinity)
+                               return "Infinity";
+                       // FIXME:
+                       // Return string in roundtrip format (currently it
+                       // rather breaks things, so we don't use it until
+                       // System.Double gets fixed.)
+#if TARGET_JVM
+                       return d.ToString ("R", System.Globalization.NumberFormatInfo.InvariantInfo);
+#else
+                       return ((double) d).ToString (System.Globalization.NumberFormatInfo.InvariantInfo);
+#endif
+               }
+
                public static double ToNumber (object arg)
                {
                        if (arg == null)
                                throw new ArgumentNullException ();
-                       if (arg is BaseIterator)
+                       if (arg is BaseIterator || arg is XPathNavigator)
                                arg = ToString (arg);   // follow on
-                       if (arg is string)
-                               return XmlConvert.ToDouble ((string) arg);      // TODO: spec? convert string to number
+                       if (arg is string) {
+                               string s = arg as string;
+                               return ToNumber (s); // use explicit overload
+                       }
                        if (arg is double)
                                return (double) arg;
                        if (arg is bool)
                                return Convert.ToDouble ((bool) arg);
                        throw new ArgumentException ();
                }
-       }
-
-       internal abstract class XPathFunction : IXsltContextFunction
-       {
-               public abstract XPathResultType ReturnType { get; }
-               public abstract int Minargs { get; }
-               public abstract int Maxargs { get; }
-               public abstract XPathResultType [] ArgTypes { get; }
-               public object Invoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+               
+               public static double ToNumber (string arg)
                {
-                       return TypesafeInvoke (xsltContext, args, docContext);
+                       if (arg == null)
+                               throw new ArgumentNullException ();
+                       string s = arg.Trim (XmlChar.WhitespaceChars);
+                       if (s.Length == 0)
+                               return double.NaN;
+                       try {
+                               return XmlConvert.ToDouble (s);
+                       } catch (System.OverflowException) {
+                               return double.NaN;
+                       } catch (System.FormatException) {
+                               return double.NaN;
+                       }
                }
+       }
 
-               public abstract string Name { get; }
-               public abstract object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext);
+       internal abstract class XPathFunction : Expression
+       {
+               public XPathFunction (FunctionArguments args) {}
        }
 
+
        internal class XPathFunctionLast : XPathFunction
        {
+               public XPathFunctionLast (FunctionArguments args) : base (args)
+               {
+                       if (args != null)
+                               throw new XPathException ("last takes 0 args");
+               }
+               
                public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
-               public override int Minargs { get { return 0; }}
-               public override int Maxargs { get { return 0; }}
-               public override XPathResultType [] ArgTypes { get { return null; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+               internal override bool Peer {
+                       get { return true; }
+               }
+
+               public override object Evaluate (BaseIterator iter)
                {
-                       throw new NotImplementedException ();   // special-cased
+                       return (double) iter.Count;
+               }
+
+               public override string ToString ()
+               {
+                       return "last()";
+               }
+
+               internal override bool IsPositional {
+                       get { return true; }
                }
-               public override string Name { get { return "last"; }}
        }
+
+
        internal class XPathFunctionPosition : XPathFunction
        {
+               public XPathFunctionPosition (FunctionArguments args) : base (args)
+               {
+                       if (args != null)
+                               throw new XPathException ("position takes 0 args");
+               }
+               
                public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
-               public override int Minargs { get { return 0; }}
-               public override int Maxargs { get { return 0; }}
-               public override XPathResultType [] ArgTypes { get { return null; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+               internal override bool Peer {
+                       get { return true; }
+               }
+
+               public override object Evaluate (BaseIterator iter)
                {
-                       throw new NotImplementedException ();   // special-cased
+                       return (double) iter.CurrentPosition;
+               }
+
+               public override string ToString ()
+               {
+                       return "position()";
+               }
+
+               internal override bool IsPositional {
+                       get { return true; }
                }
-               public override string Name { get { return "position"; }}
        }
+
+
        internal class XPathFunctionCount : XPathFunction
        {
+               Expression arg0;
+               
+               public XPathFunctionCount (FunctionArguments args) : base (args)
+               {
+                       if (args == null || args.Tail != null)
+                               throw new XPathException ("count takes 1 arg");
+                       
+                       arg0 = args.Arg;
+               }
+
                public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
-               public override int Minargs { get { return 1; }}
-               public override int Maxargs { get { return 1; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.NodeSet }; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+               internal override bool Peer {
+                       get { return arg0.Peer; }
+               }
+
+               public override object Evaluate (BaseIterator iter)
+               {
+                       return (double) arg0.EvaluateNodeSet (iter).Count;
+               }
+               
+               public override bool EvaluateBoolean (BaseIterator iter)
+               {
+                       if (arg0.GetReturnType (iter) == XPathResultType.NodeSet)
+                               return arg0.EvaluateBoolean (iter);
+                       
+                       return arg0.EvaluateNodeSet (iter).MoveNext ();
+               }
+
+               public override string ToString ()
                {
-                       return ((BaseIterator) args [0]).Count;
+                       return "count(" + arg0.ToString () + ")";
                }
-               public override string Name { get { return "count"; }}
        }
+
+
        internal class XPathFunctionId : XPathFunction
        {
+               Expression arg0;
+               
+               public XPathFunctionId (FunctionArguments args) : base (args)
+               {
+                       if (args == null || args.Tail != null)
+                               throw new XPathException ("id takes 1 arg");
+                       
+                       arg0 = args.Arg;
+               }
+
+               public Expression Id { get { return arg0; } }
+               
                private static char [] rgchWhitespace = {' ', '\t', '\r', '\n'};
                public override XPathResultType ReturnType { get { return XPathResultType.NodeSet; }}
-               public override int Minargs { get { return 1; }}
-               public override int Maxargs { get { return 1; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Any }; }}
-               [MonoTODO]
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+               internal override bool Peer {
+                       get { return arg0.Peer; }
+               }
+
+               public override object Evaluate (BaseIterator iter)
                {
                        String strArgs;
-                       BaseIterator iter = args [0] as BaseIterator;
-                       if (iter != null)
+                       object val = arg0.Evaluate (iter);
+                       
+                       BaseIterator valItr = val as BaseIterator;
+                       if (valItr != null)
                        {
                                strArgs = "";
-                               while (!iter.MoveNext ())
-                                       strArgs += iter.Current.Value + " ";
+                               while (valItr.MoveNext ())
+                                       strArgs += valItr.Current.Value + " ";
                        }
                        else
-                               strArgs = XPathFunctions.ToString (args [0]);
-                       string [] rgstrArgs = strArgs.Split (rgchWhitespace);
+                               strArgs = XPathFunctions.ToString (val);
+                       
+                       XPathNavigator n = iter.Current.Clone ();
                        ArrayList rgNodes = new ArrayList ();
-                       foreach (string strArg in rgstrArgs)
-                       {
-                               if (docContext.MoveToId (strArg))
-                                       rgNodes.Add (docContext.Clone ());
-                       }
-                       return new ArrayListIterator (iter, rgNodes);
+                       string [] ids = strArgs.Split (rgchWhitespace);
+                       for (int i = 0; i < ids.Length; i++)
+                               if (n.MoveToId (ids [i]))
+                                       rgNodes.Add (n.Clone ());
+
+                       rgNodes.Sort (XPathNavigatorComparer.Instance);
+                       return new ListIterator (iter, rgNodes);
+               }
+
+               public override string ToString ()
+               {
+                       return "id(" + arg0.ToString () + ")";
                }
-               public override string Name { get { return "id"; }}
        }
+
        internal class XPathFunctionLocalName : XPathFunction
        {
-               public override XPathResultType ReturnType { get { return XPathResultType.NodeSet; }}
-               public override int Minargs { get { return 0; }}
-               public override int Maxargs { get { return 1; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.NodeSet }; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+               Expression arg0;
+               
+               public XPathFunctionLocalName (FunctionArguments args) : base (args)
                {
-                       BaseIterator iter = (args.Length == 1) ? ((BaseIterator) args [0]) : new SelfIterator (docContext, xsltContext);
-                       if (iter == null || !iter.MoveNext ())
+                       if (args != null) {
+                               arg0 = args.Arg;
+                               if (args.Tail != null)
+                                       throw new XPathException ("local-name takes 1 or zero args");
+                       }
+               }
+               
+               public override XPathResultType ReturnType { get { return XPathResultType.String; }}
+
+               internal override bool Peer {
+                       get { return arg0 != null ? arg0.Peer : true; }
+               }
+               
+               public override object Evaluate (BaseIterator iter)
+               {
+                       if (arg0 == null)
+                               return iter.Current.LocalName;
+                       
+                       BaseIterator argNs = arg0.EvaluateNodeSet (iter);
+                       if (argNs == null || !argNs.MoveNext ())
                                return "";
-                       return iter.Current.LocalName;
+                       return argNs.Current.LocalName;
+               }
+
+               public override string ToString ()
+               {
+                       return "local-name(" + arg0.ToString () + ")";
                }
-               public override string Name { get { return "local-name"; }}
        }
+
+
        internal class XPathFunctionNamespaceUri : XPathFunction
        {
+               Expression arg0;
+               
+               public XPathFunctionNamespaceUri (FunctionArguments args) : base (args)
+               {
+                       if (args != null) {
+                               arg0 = args.Arg;
+                               if (args.Tail != null)
+                                       throw new XPathException ("namespace-uri takes 1 or zero args");
+                       }
+               }
+
+               internal override bool Peer {
+                       get { return arg0 != null ? arg0.Peer : true; }
+               }
+               
                public override XPathResultType ReturnType { get { return XPathResultType.String; }}
-               public override int Minargs { get { return 0; }}
-               public override int Maxargs { get { return 1; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.NodeSet }; }}
-               [MonoTODO]
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
-               {
-                       BaseIterator iter = (args.Length == 1) ? ((BaseIterator) args [0]) : new SelfIterator (docContext, xsltContext);
-                       if (iter == null || !iter.MoveNext ())
+               
+               public override object Evaluate (BaseIterator iter)
+               {
+                       if (arg0 == null)
+                               return iter.Current.NamespaceURI;
+                       
+                       BaseIterator argNs = arg0.EvaluateNodeSet (iter);
+                       if (argNs == null || !argNs.MoveNext ())
                                return "";
-                       return iter.Current.NamespaceURI;       // TODO: should the namespace be expanded wrt. the given context?
+                       return argNs.Current.NamespaceURI;
+               }
+
+               public override string ToString ()
+               {
+                       return "namespace-uri(" + arg0.ToString () + ")";
                }
-               public override string Name { get { return "namespace-uri"; }}
        }
+
+
        internal class XPathFunctionName : XPathFunction
        {
+               Expression arg0;
+               
+               public XPathFunctionName (FunctionArguments args) : base (args)
+               {
+                       if (args != null) {
+                               arg0 = args.Arg;
+                               if (args.Tail != null)
+                                       throw new XPathException ("name takes 1 or zero args");
+                       }
+               }
+               
                public override XPathResultType ReturnType { get { return XPathResultType.String; }}
-               public override int Minargs { get { return 0; }}
-               public override int Maxargs { get { return 1; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.NodeSet }; }}
-               [MonoTODO]
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
-               {
-                       BaseIterator iter = (args.Length == 1) ? ((BaseIterator) args [0]) : new SelfIterator (docContext, xsltContext);
-                       if (iter == null || !iter.MoveNext ())
+
+               internal override bool Peer {
+                       get { return arg0 != null ? arg0.Peer : true; }
+               }
+               
+               public override object Evaluate (BaseIterator iter)
+               {
+                       if (arg0 == null)
+                               return iter.Current.Name;
+                       
+                       BaseIterator argNs = arg0.EvaluateNodeSet (iter);
+                       if (argNs == null || !argNs.MoveNext ())
                                return "";
-                       return iter.Current.Name;
+                       return argNs.Current.Name;
+               }
+
+               public override string ToString ()
+               {
+                       return String.Concat ("name(",
+                                arg0 != null ? arg0.ToString () : String.Empty,
+                                ")");
                }
-               public override string Name { get { return "name"; }}
        }
+
+
        internal class XPathFunctionString : XPathFunction
        {
+               Expression arg0;
+               
+               public XPathFunctionString (FunctionArguments args) : base (args)
+               {
+                       if (args != null) {
+                               arg0 = args.Arg;
+                               if (args.Tail != null)
+                                       throw new XPathException ("string takes 1 or zero args");
+                       }
+               }
+               
                public override XPathResultType ReturnType { get { return XPathResultType.String; }}
-               public override int Minargs { get { return 0; }}
-               public override int Maxargs { get { return 1; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Any }; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+               internal override bool Peer {
+                       get { return arg0 != null ? arg0.Peer : true; }
+               }
+
+               public override object Evaluate (BaseIterator iter)
                {
-                       return XPathFunctions.ToString (args [0]);
+                       if (arg0 == null)
+                               return iter.Current.Value;
+                       return arg0.EvaluateString (iter);
+               }
+
+               public override string ToString ()
+               {
+                       return "string(" + arg0.ToString () + ")";
                }
-               public override string Name { get { return "string"; }}
        }
+
+
        internal class XPathFunctionConcat : XPathFunction
        {
+               ArrayList rgs;
+               
+               public XPathFunctionConcat (FunctionArguments args) : base (args)
+               {
+                       if (args == null || args.Tail == null)
+                               throw new XPathException ("concat takes 2 or more args");
+                       
+                       args.ToArrayList (rgs = new ArrayList ());
+               }
+               
                public override XPathResultType ReturnType { get { return XPathResultType.String; }}
-               public override int Minargs { get { return 2; }}
-               public override int Maxargs { get { return int.MaxValue; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String, XPathResultType.String }; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+               internal override bool Peer {
+                       get {
+                               for (int i = 0; i < rgs.Count; i++)
+                                       if (!((Expression) rgs [i]).Peer)
+                                               return false;
+                               return true;
+                       }
+               }
+               
+               public override object Evaluate (BaseIterator iter)
+               {
+                       StringBuilder sb = new StringBuilder ();
+                       
+                       int len = rgs.Count;
+                       for (int i = 0; i < len; i++)
+                               sb.Append (((Expression)rgs[i]).EvaluateString (iter));
+                       
+                       return sb.ToString ();
+               }
+
+               public override string ToString ()
                {
-                       String str = "";
-                       foreach (string strArg in args)
-                               str += strArg;
-                       return str;
+                       StringBuilder sb = new StringBuilder ();
+                       sb.Append ("concat(");
+                       for (int i = 0; i < rgs.Count - 1; i++) {
+                               sb.AppendFormat (CultureInfo.InvariantCulture, "{0}", rgs [i].ToString ());
+                               sb.Append (',');
+                       }
+                       sb.AppendFormat (CultureInfo.InvariantCulture, "{0}", rgs [rgs.Count - 1].ToString ());
+                       sb.Append (')');
+                       return sb.ToString ();
                }
-               public override string Name { get { return "concat"; }}
        }
+
+
        internal class XPathFunctionStartsWith : XPathFunction
        {
+               Expression arg0, arg1;
+               
+               public XPathFunctionStartsWith (FunctionArguments args) : base (args)
+               {
+                       if (args == null || args.Tail == null || args.Tail.Tail != null)
+                               throw new XPathException ("starts-with takes 2 args");
+                       
+                       arg0 = args.Arg;
+                       arg1 = args.Tail.Arg;
+               }
+               
                public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
-               public override int Minargs { get { return 2; }}
-               public override int Maxargs { get { return 2; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String }; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+               internal override bool Peer {
+                       get { return arg0.Peer && arg1.Peer; }
+               }
+               
+               public override object Evaluate (BaseIterator iter)
+               {
+                       return arg0.EvaluateString (iter).StartsWith (arg1.EvaluateString (iter));
+               }
+
+               public override string ToString ()
                {
-                       string str1 = (string) args [0];
-                       string str2 = (string) args [1];
-                       return str1.StartsWith (str2);
+                       return String.Concat ("starts-with(", arg0.ToString (), ",", arg1.ToString (), ")");
                }
-               public override string Name { get { return "starts-with"; }}
        }
+
+
        internal class XPathFunctionContains : XPathFunction
        {
+               Expression arg0, arg1;
+               
+               public XPathFunctionContains (FunctionArguments args) : base (args)
+               {
+                       if (args == null || args.Tail == null || args.Tail.Tail != null)
+                               throw new XPathException ("contains takes 2 args");
+                       
+                       arg0 = args.Arg;
+                       arg1 = args.Tail.Arg;
+               }
+               
                public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
-               public override int Minargs { get { return 2; }}
-               public override int Maxargs { get { return 2; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String }; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+               internal override bool Peer {
+                       get { return arg0.Peer && arg1.Peer; }
+               }
+               
+               public override object Evaluate (BaseIterator iter)
+               {
+                       return arg0.EvaluateString (iter).IndexOf (arg1.EvaluateString (iter)) != -1;
+               }
+
+               public override string ToString ()
                {
-                       string str1 = (string) args [0];
-                       string str2 = (string) args [1];
-                       return str1.IndexOf (str2) != -1;
+                       return String.Concat ("contains(", arg0.ToString (), ",", arg1.ToString (), ")");
                }
-               public override string Name { get { return "contains"; }}
        }
+
+
        internal class XPathFunctionSubstringBefore : XPathFunction
        {
+               Expression arg0, arg1;
+               
+               public XPathFunctionSubstringBefore (FunctionArguments args) : base (args)
+               {
+                       if (args == null || args.Tail == null || args.Tail.Tail != null)
+                               throw new XPathException ("substring-before takes 2 args");
+                       
+                       arg0 = args.Arg;
+                       arg1 = args.Tail.Arg;
+               }
+               
                public override XPathResultType ReturnType { get { return XPathResultType.String; }}
-               public override int Minargs { get { return 2; }}
-               public override int Maxargs { get { return 2; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String }; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+               internal override bool Peer {
+                       get { return arg0.Peer && arg1.Peer; }
+               }
+               
+               public override object Evaluate (BaseIterator iter)
                {
-                       string str1 = (string) args [0];
-                       string str2 = (string) args [1];
+                       string str1 = arg0.EvaluateString (iter);
+                       string str2 = arg1.EvaluateString (iter);
                        int ich = str1.IndexOf (str2);
                        if (ich <= 0)
                                return "";
                        return str1.Substring (0, ich);
                }
-               public override string Name { get { return "substring-before"; }}
+
+               public override string ToString ()
+               {
+                       return String.Concat ("substring-before(", arg0.ToString (), ",", arg1.ToString (), ")");
+               }
        }
+
+
        internal class XPathFunctionSubstringAfter : XPathFunction
        {
+               Expression arg0, arg1;
+               
+               public XPathFunctionSubstringAfter (FunctionArguments args) : base (args)
+               {
+                       if (args == null || args.Tail == null || args.Tail.Tail != null)
+                               throw new XPathException ("substring-after takes 2 args");
+                       
+                       arg0 = args.Arg;
+                       arg1 = args.Tail.Arg;
+               }
+               
                public override XPathResultType ReturnType { get { return XPathResultType.String; }}
-               public override int Minargs { get { return 2; }}
-               public override int Maxargs { get { return 2; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String }; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+               internal override bool Peer {
+                       get { return arg0.Peer && arg1.Peer; }
+               }
+               
+               public override object Evaluate (BaseIterator iter)
                {
-                       string str1 = (string) args [0];
-                       string str2 = (string) args [1];
+                       string str1 = arg0.EvaluateString (iter);
+                       string str2 = arg1.EvaluateString (iter);
                        int ich = str1.IndexOf (str2);
-                       if (ich <= 0)
+                       if (ich < 0)
                                return "";
                        return str1.Substring (ich + str2.Length);
                }
-               public override string Name { get { return "substring-after"; }}
+
+               public override string ToString ()
+               {
+                       return String.Concat ("substring-after(", arg0.ToString (), ",", arg1.ToString (), ")");
+               }
        }
+
+
        internal class XPathFunctionSubstring : XPathFunction
        {
+               Expression arg0, arg1, arg2;
+               
+               public XPathFunctionSubstring (FunctionArguments args) : base (args)
+               {
+                       if (args == null || args.Tail == null || (args.Tail.Tail != null && args.Tail.Tail.Tail != null))
+                               throw new XPathException ("substring takes 2 or 3 args");
+                       
+                       arg0 = args.Arg;
+                       arg1 = args.Tail.Arg;
+                       if (args.Tail.Tail != null)
+                               arg2= args.Tail.Tail.Arg;
+               }
+               
                public override XPathResultType ReturnType { get { return XPathResultType.String; }}
-               public override int Minargs { get { return 2; }}
-               public override int Maxargs { get { return int.MaxValue; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String, XPathResultType.String }; }}
-               [MonoTODO]
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
-               {
-                       // TODO: check this, what the hell were they smoking?
-                       string str = (string) args [0];
-                       double ich = Math.Round ((double) args [1]) - 1;
-                       if (Double.IsNaN (ich) || ich >= (double) str.Length)
+
+               internal override bool Peer {
+                       get { return arg0.Peer && arg1.Peer && (arg2 != null ? arg2.Peer : true); }
+               }
+               
+               public override object Evaluate (BaseIterator iter)
+               {
+                       string str = arg0.EvaluateString (iter);
+                       double ich = Math.Round (arg1.EvaluateNumber (iter)) - 1;
+                       if (Double.IsNaN (ich) ||
+                               Double.IsNegativeInfinity (ich) ||
+                               ich >= (double) str.Length)
                                return "";
 
-                       if (args.Length == 2)
+                       if (arg2 == null)
                        {
                                if (ich < 0)
                                        ich = 0.0;
@@ -405,7 +684,7 @@ namespace System.Xml.XPath
                        }
                        else
                        {
-                               double cch = Math.Round ((double) args [2]);
+                               double cch = Math.Round (arg2.EvaluateNumber (iter));
                                if (Double.IsNaN (cch))
                                        return "";
                                if (ich < 0.0 || cch < 0.0) 
@@ -421,43 +700,82 @@ namespace System.Xml.XPath
                                return str.Substring ((int) ich, (int) cch);
                        }
                }
-               public override string Name { get { return "substring"; }}
+
+               public override string ToString ()
+               {
+                       return String.Concat (new string [] {
+                               "substring(", arg0.ToString (), ",", arg1.ToString (), ",", arg2.ToString (), ")"});
+               }
        }
+
+
        internal class XPathFunctionStringLength : XPathFunction
        {
+               Expression arg0;
+               
+               public XPathFunctionStringLength (FunctionArguments args) : base (args)
+               {
+                       if (args != null) {
+                               arg0 = args.Arg;
+                               if (args.Tail != null)
+                                       throw new XPathException ("string-length takes 1 or zero args");
+                       }
+               }
+               
                public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
-               public override int Minargs { get { return 0; }}
-               public override int Maxargs { get { return 1; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String }; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+               internal override bool Peer {
+                       get { return arg0 != null ? arg0.Peer : true; }
+               }
+               
+               public override object Evaluate (BaseIterator iter)
                {
                        string str;
-                       if (args.Length == 1)
-                               str = (string) args [0];
+                       if (arg0 != null)
+                               str = arg0.EvaluateString (iter);
                        else
-                               str = docContext.Value;
+                               str = iter.Current.Value;
                        return (double) str.Length;
                }
-               public override string Name { get { return "string-length"; }}
+
+               public override string ToString ()
+               {
+                       return String.Concat (new string [] {
+                               "string-length(", arg0.ToString (), ")"});
+               }
        }
+
+
        internal class XPathFunctionNormalizeSpace : XPathFunction
        {
+               Expression arg0;
+               
+               public XPathFunctionNormalizeSpace (FunctionArguments args) : base (args)
+               {
+                       if (args != null) {
+                               arg0 = args.Arg;
+                               if (args.Tail != null)
+                                       throw new XPathException ("normalize-space takes 1 or zero args");
+                       }
+               }
+               
                public override XPathResultType ReturnType { get { return XPathResultType.String; }}
-               public override int Minargs { get { return 0; }}
-               public override int Maxargs { get { return 1; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String }; }}
-               [MonoTODO]
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+               internal override bool Peer {
+                       get { return arg0 !=null ? arg0.Peer : true; }
+               }
+
+               public override object Evaluate (BaseIterator iter)
                {
                        string str;
-                       if (args.Length == 1)
-                               str = (string) args [0];
+                       if (arg0 != null)
+                               str = arg0.EvaluateString (iter);
                        else
-                               str = docContext.Value;
+                               str = iter.Current.Value;
                        System.Text.StringBuilder sb = new System.Text.StringBuilder ();
                        bool fSpace = false;
-                       foreach (char ch in str)
-                       {
+                       for (int i = 0; i < str.Length; i++) {
+                               char ch = str [i];
                                if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')
                                {
                                        fSpace = true;
@@ -475,144 +793,448 @@ namespace System.Xml.XPath
                        }
                        return sb.ToString ();
                }
-               public override string Name { get { return "normalize-space"; }}
+
+               public override string ToString ()
+               {
+                       return String.Concat (new string [] {
+                               "normalize-space(",
+                               arg0 != null ? arg0.ToString () : String.Empty,
+                               ")"});
+               }
        }
+
+
        internal class XPathFunctionTranslate : XPathFunction
        {
+               Expression arg0, arg1, arg2;
+               
+               public XPathFunctionTranslate (FunctionArguments args) : base (args)
+               {
+                       if (args == null || args.Tail == null || args.Tail.Tail == null || args.Tail.Tail.Tail != null)
+                               throw new XPathException ("translate takes 3 args");
+                       
+                       arg0 = args.Arg;
+                       arg1 = args.Tail.Arg;
+                       arg2= args.Tail.Tail.Arg;
+               }
+               
                public override XPathResultType ReturnType { get { return XPathResultType.String; }}
-               public override int Minargs { get { return 3; }}
-               public override int Maxargs { get { return 3; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String, XPathResultType.String, XPathResultType.String }; }}
-               [MonoTODO]
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+               internal override bool Peer {
+                       get { return arg0.Peer && arg1.Peer && arg2.Peer; }
+               }
+               
+               public override object Evaluate (BaseIterator iter)
+               {
+                       string s0 = arg0.EvaluateString (iter);
+                       string s1 = arg1.EvaluateString (iter);
+                       string s2 = arg2.EvaluateString (iter);
+                       
+                       StringBuilder ret = new StringBuilder (s0.Length);
+                               
+                       int pos = 0, len = s0.Length, s2len = s2.Length;
+                       
+                       while (pos < len) {
+                               int idx = s1.IndexOf (s0 [pos]);
+                               
+                               if (idx != -1) {
+                                       if (idx < s2len)
+                                               ret.Append (s2 [idx]);
+                               }
+                               else
+                                       ret.Append (s0 [pos]);
+                               
+                               pos++;
+                       }
+                       
+                       return ret.ToString ();
+               }
+
+               public override string ToString ()
                {
-                       throw new NotImplementedException ();
+                       return String.Concat (new string [] {
+                               "string-length(",
+                               arg0.ToString (), ",",
+                               arg1.ToString (), ",",
+                               arg2.ToString (), ")"});
                }
-               public override string Name { get { return "translate"; }}
        }
-       internal class XPathFunctionBoolean : XPathFunction
+
+       internal abstract class XPathBooleanFunction : XPathFunction
        {
+               public XPathBooleanFunction (FunctionArguments args) : base (args)
+               {
+               }
+
                public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
-               public override int Minargs { get { return 1; }}
-               public override int Maxargs { get { return 1; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Any }; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+               public override object StaticValue {
+                       get { return StaticValueAsBoolean; }
+               }
+       }
+
+       internal class XPathFunctionBoolean : XPathBooleanFunction
+       {
+               Expression arg0;
+               
+               public XPathFunctionBoolean (FunctionArguments args) : base (args)
+               {
+                       if (args != null) {
+                               arg0 = args.Arg;
+                               if (args.Tail != null)
+                                       throw new XPathException ("boolean takes 1 or zero args");
+                       }
+               }
+               
+               internal override bool Peer {
+                       get { return arg0 != null ? arg0.Peer : true; }
+               }
+
+               public override object Evaluate (BaseIterator iter)
+               {
+                       if (arg0 == null)
+                               return XPathFunctions.ToBoolean (iter.Current.Value);
+                       return arg0.EvaluateBoolean (iter);
+               }
+
+               public override string ToString ()
                {
-                       return XPathFunctions.ToBoolean (args [0]);
+                       return String.Concat (new string [] {"boolean(", arg0.ToString (), ")"});
                }
-               public override string Name { get { return "boolean"; }}
        }
-       internal class XPathFunctionNot : XPathFunction
+
+
+       internal class XPathFunctionNot : XPathBooleanFunction
        {
-               public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
-               public override int Minargs { get { return 1; }}
-               public override int Maxargs { get { return 1; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Any }; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+               Expression arg0;
+               
+               public XPathFunctionNot (FunctionArguments args) : base (args)
+               {
+                       if (args == null || args.Tail != null)
+                               throw new XPathException ("not takes one arg");
+                       arg0 = args.Arg;
+               }
+               
+               internal override bool Peer {
+                       get { return arg0.Peer; }
+               }
+
+               public override object Evaluate (BaseIterator iter)
+               {
+                       return !arg0.EvaluateBoolean (iter);
+               }
+
+               public override string ToString ()
                {
-                       return !(XPathFunctions.ToBoolean (args [0]));
+                       return String.Concat (new string [] {"not(", arg0.ToString (), ")"});
                }
-               public override string Name { get { return "not"; }}
        }
-       internal class XPathFunctionTrue : XPathFunction
+
+
+       internal class XPathFunctionTrue : XPathBooleanFunction
        {
-               public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
-               public override int Minargs { get { return 0; }}
-               public override int Maxargs { get { return 0; }}
-               public override XPathResultType [] ArgTypes { get { return null; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+               public XPathFunctionTrue (FunctionArguments args) : base (args)
+               {
+                       if (args != null)
+                               throw new XPathException ("true takes 0 args");
+               }
+
+               public override bool HasStaticValue {
+                       get { return true; }
+               }
+
+               public override bool StaticValueAsBoolean {
+                       get { return true; }
+               }
+               
+               internal override bool Peer {
+                       get { return true; }
+               }
+
+               public override object Evaluate (BaseIterator iter)
                {
                        return true;
                }
-               public override string Name { get { return "true"; }}
+
+               public override string ToString ()
+               {
+                       return "true()";
+               }
        }
-       internal class XPathFunctionFalse : XPathFunction
+
+
+       internal class XPathFunctionFalse : XPathBooleanFunction
        {
-               public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
-               public override int Minargs { get { return 0; }}
-               public override int Maxargs { get { return 0; }}
-               public override XPathResultType [] ArgTypes { get { return null; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+               public XPathFunctionFalse (FunctionArguments args) : base (args)
+               {
+                       if (args != null)
+                               throw new XPathException ("false takes 0 args");
+               }
+
+               public override bool HasStaticValue {
+                       get { return true; }
+               }
+
+               public override bool StaticValueAsBoolean {
+                       get { return false; }
+               }
+
+               internal override bool Peer {
+                       get { return true; }
+               }
+
+               public override object Evaluate (BaseIterator iter)
                {
                        return false;
                }
-               public override string Name { get { return "false"; }}
+
+               public override string ToString ()
+               {
+                       return "false()";
+               }
        }
+
+
        internal class XPathFunctionLang : XPathFunction
        {
+               Expression arg0;
+               
+               public XPathFunctionLang (FunctionArguments args) : base (args)
+               {
+                       if (args == null || args.Tail != null)
+                               throw new XPathException ("lang takes one arg");
+                       arg0 = args.Arg;
+               }
+
                public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
-               public override int Minargs { get { return 1; }}
-               public override int Maxargs { get { return 1; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.String }; }}
-               [MonoTODO]
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+               internal override bool Peer {
+                       get { return arg0.Peer; }
+               }
+
+               public override object Evaluate (BaseIterator iter)
                {
-                       throw new NotImplementedException ();
+                       return EvaluateBoolean (iter);
+               }
+
+               public override bool EvaluateBoolean (BaseIterator iter)
+               {
+                       string lang = arg0.EvaluateString (iter).ToLower (CultureInfo.InvariantCulture);
+                       string actualLang = iter.Current.XmlLang.ToLower (CultureInfo.InvariantCulture);
+                       
+                       return lang == actualLang || lang == (actualLang.Split ('-')[0]);
+               }
+
+               public override string ToString ()
+               {
+                       return String.Concat (new string [] {"lang(", arg0.ToString (), ")"});
                }
-               public override string Name { get { return "lang"; }}
        }
-       internal class XPathFunctionNumber : XPathFunction
+
+       internal abstract class XPathNumericFunction : XPathFunction
        {
+               internal XPathNumericFunction (FunctionArguments args)
+                       : base (args)
+               {
+               }
+
                public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
-               public override int Minargs { get { return 0; }}
-               public override int Maxargs { get { return 1; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Any }; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+
+               public override object StaticValue {
+                       get { return StaticValueAsNumber; }
+               }
+       }
+
+       internal class XPathFunctionNumber : XPathNumericFunction
+       {
+               Expression arg0;
+               
+               public XPathFunctionNumber (FunctionArguments args) : base (args)
+               {
+                       if (args != null) {
+                               arg0 = args.Arg;
+                               if (args.Tail != null)
+                                       throw new XPathException ("number takes 1 or zero args");
+                       }
+               }
+
+               public override Expression Optimize ()
+               {
+                       if (arg0 == null)
+                               return this;
+                       arg0 = arg0.Optimize ();
+                       return !arg0.HasStaticValue ?
+                               (Expression) this :
+                               new ExprNumber (StaticValueAsNumber);
+               }
+
+               public override bool HasStaticValue {
+                       get { return arg0 != null && arg0.HasStaticValue; }
+               }
+
+               public override double StaticValueAsNumber {
+                       get { return arg0 != null ? arg0.StaticValueAsNumber : 0; }
+               }
+
+               internal override bool Peer {
+                       get { return arg0 != null ? arg0.Peer : true; }
+               }
+
+               public override object Evaluate (BaseIterator iter)
+               {
+                       if (arg0 == null)
+                               return XPathFunctions.ToNumber (iter.Current.Value);
+                       return arg0.EvaluateNumber (iter);
+               }
+
+               public override string ToString ()
                {
-                       return XPathFunctions.ToNumber (args [0]);
+                       return String.Concat (new string [] {"number(", arg0.ToString (), ")"});
                }
-               public override string Name { get { return "number"; }}
        }
-       internal class XPathFunctionSum : XPathFunction
+
+
+       internal class XPathFunctionSum : XPathNumericFunction
        {
-               public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
-               public override int Minargs { get { return 1; }}
-               public override int Maxargs { get { return 1; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.NodeSet }; }}
-               [MonoTODO]
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+               Expression arg0;
+               
+               public XPathFunctionSum (FunctionArguments args) : base (args)
+               {
+                       if (args == null || args.Tail != null)
+                               throw new XPathException ("sum takes one arg");
+                       arg0 = args.Arg;
+               }
+               
+               internal override bool Peer {
+                       get { return arg0.Peer; }
+               }
+
+               public override object Evaluate (BaseIterator iter)
                {
-                       throw new NotImplementedException ();
+                       XPathNodeIterator itr = arg0.EvaluateNodeSet (iter);
+                       
+                       double sum = 0;
+                       while (itr.MoveNext ())
+                               sum += XPathFunctions.ToNumber (itr.Current.Value);
+                       
+                       return sum;
+               }
+
+               public override string ToString ()
+               {
+                       return String.Concat (new string [] {"sum(", arg0.ToString (), ")"});
                }
-               public override string Name { get { return "sum"; }}
        }
-       internal class XPathFunctionFloor : XPathFunction
+
+
+       internal class XPathFunctionFloor : XPathNumericFunction
        {
-               public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
-               public override int Minargs { get { return 1; }}
-               public override int Maxargs { get { return 1; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Number }; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+               Expression arg0;
+               
+               public XPathFunctionFloor (FunctionArguments args) : base (args)
+               {
+                       if (args == null || args.Tail != null)
+                               throw new XPathException ("floor takes one arg");
+                       arg0 = args.Arg;
+               }
+
+               public override bool HasStaticValue {
+                       get { return arg0.HasStaticValue; }
+               }
+
+               public override double StaticValueAsNumber {
+                       get { return HasStaticValue ? Math.Floor (arg0.StaticValueAsNumber) : 0; }
+               }
+               
+               internal override bool Peer {
+                       get { return arg0.Peer; }
+               }
+
+               public override object Evaluate (BaseIterator iter)
+               {
+                       return Math.Floor (arg0.EvaluateNumber (iter));
+               }
+
+               public override string ToString ()
                {
-                       return Math.Floor ((double) args [0]);
+                       return String.Concat (new string [] {"floor(", arg0.ToString (), ")"});
                }
-               public override string Name { get { return "floor"; }}
        }
-       internal class XPathFunctionCeil : XPathFunction
+
+
+       internal class XPathFunctionCeil : XPathNumericFunction
        {
-               public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
-               public override int Minargs { get { return 1; }}
-               public override int Maxargs { get { return 1; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Number }; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+               Expression arg0;
+               
+               public XPathFunctionCeil (FunctionArguments args) : base (args)
+               {
+                       if (args == null || args.Tail != null)
+                               throw new XPathException ("ceil takes one arg");
+                       arg0 = args.Arg;
+               }
+
+               public override bool HasStaticValue {
+                       get { return arg0.HasStaticValue; }
+               }
+
+               public override double StaticValueAsNumber {
+                       get { return HasStaticValue ? Math.Ceiling (arg0.StaticValueAsNumber) : 0; }
+               }
+               
+               internal override bool Peer {
+                       get { return arg0.Peer; }
+               }
+
+               public override object Evaluate (BaseIterator iter)
+               {
+                       return Math.Ceiling (arg0.EvaluateNumber (iter));
+               }
+
+               public override string ToString ()
                {
-                       return Math.Ceiling ((double) args [0]);
+                       return String.Concat (new string [] {"ceil(", arg0.ToString (), ")"});
                }
-               public override string Name { get { return "ceil"; }}
        }
-       internal class XPathFunctionRound : XPathFunction
+
+
+       internal class XPathFunctionRound : XPathNumericFunction
        {
-               public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
-               public override int Minargs { get { return 1; }}
-               public override int Maxargs { get { return 1; }}
-               public override XPathResultType [] ArgTypes { get { return new XPathResultType [] { XPathResultType.Number }; }}
-               public override object TypesafeInvoke (XsltContext xsltContext, object[] args, XPathNavigator docContext)
+               Expression arg0;
+               
+               public XPathFunctionRound (FunctionArguments args) : base (args)
+               {
+                       if (args == null || args.Tail != null)
+                               throw new XPathException ("round takes one arg");
+                       arg0 = args.Arg;
+               }
+               
+               public override bool HasStaticValue {
+                       get { return arg0.HasStaticValue; }
+               }
+
+               public override double StaticValueAsNumber {
+                       get { return HasStaticValue ? Round (arg0.StaticValueAsNumber) : 0; }
+               }
+
+               internal override bool Peer {
+                       get { return arg0.Peer; }
+               }
+
+               public override object Evaluate (BaseIterator iter)
+               {
+                       return Round (arg0.EvaluateNumber (iter));
+               }
+
+               private double Round (double arg)
                {
-                       double arg = (double) args [0];
                        if (arg < -0.5 || arg > 0)
                                return Math.Floor (arg + 0.5);
                        return Math.Round (arg);
                }
-               public override string Name { get { return "round"; }}
+
+               public override string ToString ()
+               {
+                       return String.Concat (new string [] {"round(", arg0.ToString (), ")"});
+               }
        }
 }