* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / System.XML / System.Xml.XPath / DefaultContext.cs
index 41b394a713972283f6104c097844e4f0b54b4983..96ec9fc2a1cdc5b2f632dc4a5da60e399d327af2 100644 (file)
@@ -6,8 +6,30 @@
 //
 // (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;
@@ -35,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)
@@ -47,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;
@@ -55,26 +101,41 @@ 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 string)
-                       {
-                               try
-                               {
-                                       return XmlConvert.ToDouble ((string) arg);      // TODO: spec? convert string to number
-                               }
-                               catch (System.FormatException)
-                               {
-                                       return double.NaN;
-                               }
-                       }
-                       if (arg is BaseIterator)
+                       if (arg is BaseIterator || arg is XPathNavigator)
                                arg = ToString (arg);   // follow on
+                       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)
@@ -84,8 +145,13 @@ namespace System.Xml.XPath
                
                public static double ToNumber (string arg)
                {
+                       if (arg == null)
+                               throw new ArgumentNullException ();
+                       string s = arg.Trim (XmlChar.WhitespaceChars);
+                       if (s.Length == 0)
+                               return double.NaN;
                        try {
-                               return XmlConvert.ToDouble ((string) arg.Trim (XmlChar.WhitespaceChars));
+                               return XmlConvert.ToDouble (s);
                        } catch (System.OverflowException) {
                                return double.NaN;
                        } catch (System.FormatException) {
@@ -110,6 +176,10 @@ namespace System.Xml.XPath
                
                public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
 
+               internal override bool Peer {
+                       get { return true; }
+               }
+
                public override object Evaluate (BaseIterator iter)
                {
                        return (double) iter.Count;
@@ -119,6 +189,10 @@ namespace System.Xml.XPath
                {
                        return "last()";
                }
+
+               internal override bool IsPositional {
+                       get { return true; }
+               }
        }
 
 
@@ -132,6 +206,10 @@ namespace System.Xml.XPath
                
                public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
 
+               internal override bool Peer {
+                       get { return true; }
+               }
+
                public override object Evaluate (BaseIterator iter)
                {
                        return (double) iter.CurrentPosition;
@@ -141,6 +219,10 @@ namespace System.Xml.XPath
                {
                        return "position()";
                }
+
+               internal override bool IsPositional {
+                       get { return true; }
+               }
        }
 
 
@@ -157,7 +239,11 @@ namespace System.Xml.XPath
                }
 
                public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
-               
+
+               internal override bool Peer {
+                       get { return arg0.Peer; }
+               }
+
                public override object Evaluate (BaseIterator iter)
                {
                        return (double) arg0.EvaluateNodeSet (iter).Count;
@@ -195,6 +281,10 @@ namespace System.Xml.XPath
                private static char [] rgchWhitespace = {' ', '\t', '\r', '\n'};
                public override XPathResultType ReturnType { get { return XPathResultType.NodeSet; }}
 
+               internal override bool Peer {
+                       get { return arg0.Peer; }
+               }
+
                public override object Evaluate (BaseIterator iter)
                {
                        String strArgs;
@@ -212,14 +302,13 @@ namespace System.Xml.XPath
                        
                        XPathNavigator n = iter.Current.Clone ();
                        ArrayList rgNodes = new ArrayList ();
-                       foreach (string strArg in strArgs.Split (rgchWhitespace))
-                       {
-                               if (n.MoveToId (strArg)) {
+                       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 EnumeratorIterator (iter, rgNodes.GetEnumerator ());
+                       return new ListIterator (iter, rgNodes);
                }
 
                public override string ToString ()
@@ -242,6 +331,10 @@ namespace System.Xml.XPath
                }
                
                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)
                {
@@ -273,6 +366,10 @@ namespace System.Xml.XPath
                                        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; }}
                
@@ -308,6 +405,10 @@ namespace System.Xml.XPath
                }
                
                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)
                {
@@ -322,7 +423,9 @@ namespace System.Xml.XPath
 
                public override string ToString ()
                {
-                       return "name(" + arg0.ToString () + ")";
+                       return String.Concat ("name(",
+                                arg0 != null ? arg0.ToString () : String.Empty,
+                                ")");
                }
        }
 
@@ -336,12 +439,16 @@ namespace System.Xml.XPath
                        if (args != null) {
                                arg0 = args.Arg;
                                if (args.Tail != null)
-                                       throw new XPathException ("boolean takes 1 or zero args");
+                                       throw new XPathException ("string 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)
@@ -369,6 +476,15 @@ namespace System.Xml.XPath
                }
                
                public override XPathResultType ReturnType { get { return XPathResultType.String; }}
+
+               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)
                {
@@ -386,10 +502,10 @@ namespace System.Xml.XPath
                        StringBuilder sb = new StringBuilder ();
                        sb.Append ("concat(");
                        for (int i = 0; i < rgs.Count - 1; i++) {
-                               sb.Append (rgs [i].ToString ());
+                               sb.AppendFormat (CultureInfo.InvariantCulture, "{0}", rgs [i].ToString ());
                                sb.Append (',');
                        }
-                       sb.Append (rgs [rgs.Count - 1].ToString ());
+                       sb.AppendFormat (CultureInfo.InvariantCulture, "{0}", rgs [rgs.Count - 1].ToString ());
                        sb.Append (')');
                        return sb.ToString ();
                }
@@ -410,6 +526,10 @@ namespace System.Xml.XPath
                }
                
                public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
+
+               internal override bool Peer {
+                       get { return arg0.Peer && arg1.Peer; }
+               }
                
                public override object Evaluate (BaseIterator iter)
                {
@@ -437,6 +557,10 @@ namespace System.Xml.XPath
                }
                
                public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
+
+               internal override bool Peer {
+                       get { return arg0.Peer && arg1.Peer; }
+               }
                
                public override object Evaluate (BaseIterator iter)
                {
@@ -464,6 +588,10 @@ namespace System.Xml.XPath
                }
                
                public override XPathResultType ReturnType { get { return XPathResultType.String; }}
+
+               internal override bool Peer {
+                       get { return arg0.Peer && arg1.Peer; }
+               }
                
                public override object Evaluate (BaseIterator iter)
                {
@@ -496,6 +624,10 @@ namespace System.Xml.XPath
                }
                
                public override XPathResultType ReturnType { get { return XPathResultType.String; }}
+
+               internal override bool Peer {
+                       get { return arg0.Peer && arg1.Peer; }
+               }
                
                public override object Evaluate (BaseIterator iter)
                {
@@ -530,6 +662,10 @@ namespace System.Xml.XPath
                }
                
                public override XPathResultType ReturnType { get { return XPathResultType.String; }}
+
+               internal override bool Peer {
+                       get { return arg0.Peer && arg1.Peer && (arg2 != null ? arg2.Peer : true); }
+               }
                
                public override object Evaluate (BaseIterator iter)
                {
@@ -587,6 +723,10 @@ namespace System.Xml.XPath
                }
                
                public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
+
+               internal override bool Peer {
+                       get { return arg0 != null ? arg0.Peer : true; }
+               }
                
                public override object Evaluate (BaseIterator iter)
                {
@@ -621,6 +761,10 @@ namespace System.Xml.XPath
                
                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)
                {
                        string str;
@@ -630,8 +774,8 @@ namespace System.Xml.XPath
                                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;
@@ -675,6 +819,10 @@ namespace System.Xml.XPath
                }
                
                public override XPathResultType ReturnType { get { return XPathResultType.String; }}
+
+               internal override bool Peer {
+                       get { return arg0.Peer && arg1.Peer && arg2.Peer; }
+               }
                
                public override object Evaluate (BaseIterator iter)
                {
@@ -712,8 +860,20 @@ namespace System.Xml.XPath
                }
        }
 
+       internal abstract class XPathBooleanFunction : XPathFunction
+       {
+               public XPathBooleanFunction (FunctionArguments args) : base (args)
+               {
+               }
+
+               public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
+
+               public override object StaticValue {
+                       get { return StaticValueAsBoolean; }
+               }
+       }
 
-       internal class XPathFunctionBoolean : XPathFunction
+       internal class XPathFunctionBoolean : XPathBooleanFunction
        {
                Expression arg0;
                
@@ -726,7 +886,9 @@ namespace System.Xml.XPath
                        }
                }
                
-               public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
+               internal override bool Peer {
+                       get { return arg0 != null ? arg0.Peer : true; }
+               }
 
                public override object Evaluate (BaseIterator iter)
                {
@@ -742,7 +904,7 @@ namespace System.Xml.XPath
        }
 
 
-       internal class XPathFunctionNot : XPathFunction
+       internal class XPathFunctionNot : XPathBooleanFunction
        {
                Expression arg0;
                
@@ -753,7 +915,9 @@ namespace System.Xml.XPath
                        arg0 = args.Arg;
                }
                
-               public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
+               internal override bool Peer {
+                       get { return arg0.Peer; }
+               }
 
                public override object Evaluate (BaseIterator iter)
                {
@@ -767,15 +931,25 @@ namespace System.Xml.XPath
        }
 
 
-       internal class XPathFunctionTrue : XPathFunction
+       internal class XPathFunctionTrue : XPathBooleanFunction
        {
                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; }
+               }
                
-               public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
+               internal override bool Peer {
+                       get { return true; }
+               }
 
                public override object Evaluate (BaseIterator iter)
                {
@@ -789,14 +963,25 @@ namespace System.Xml.XPath
        }
 
 
-       internal class XPathFunctionFalse : XPathFunction
+       internal class XPathFunctionFalse : XPathBooleanFunction
        {
                public XPathFunctionFalse (FunctionArguments args) : base (args)
                {
                        if (args != null)
                                throw new XPathException ("false takes 0 args");
                }
-               public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
+
+               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)
                {
@@ -820,13 +1005,22 @@ namespace System.Xml.XPath
                                throw new XPathException ("lang takes one arg");
                        arg0 = args.Arg;
                }
-               
+
                public override XPathResultType ReturnType { get { return XPathResultType.Boolean; }}
 
+               internal override bool Peer {
+                       get { return arg0.Peer; }
+               }
+
                public override object Evaluate (BaseIterator iter)
                {
-                       string lang = arg0.EvaluateString (iter).ToLower ();
-                       string actualLang = iter.Current.XmlLang.ToLower ();
+                       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]);
                }
@@ -837,8 +1031,21 @@ namespace System.Xml.XPath
                }
        }
 
+       internal abstract class XPathNumericFunction : XPathFunction
+       {
+               internal XPathNumericFunction (FunctionArguments args)
+                       : base (args)
+               {
+               }
 
-       internal class XPathFunctionNumber : XPathFunction
+               public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
+
+               public override object StaticValue {
+                       get { return StaticValueAsNumber; }
+               }
+       }
+
+       internal class XPathFunctionNumber : XPathNumericFunction
        {
                Expression arg0;
                
@@ -850,8 +1057,28 @@ namespace System.Xml.XPath
                                        throw new XPathException ("number takes 1 or zero args");
                        }
                }
-               
-               public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
+
+               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)
                {
@@ -867,7 +1094,7 @@ namespace System.Xml.XPath
        }
 
 
-       internal class XPathFunctionSum : XPathFunction
+       internal class XPathFunctionSum : XPathNumericFunction
        {
                Expression arg0;
                
@@ -878,7 +1105,9 @@ namespace System.Xml.XPath
                        arg0 = args.Arg;
                }
                
-               public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
+               internal override bool Peer {
+                       get { return arg0.Peer; }
+               }
 
                public override object Evaluate (BaseIterator iter)
                {
@@ -898,7 +1127,7 @@ namespace System.Xml.XPath
        }
 
 
-       internal class XPathFunctionFloor : XPathFunction
+       internal class XPathFunctionFloor : XPathNumericFunction
        {
                Expression arg0;
                
@@ -908,8 +1137,18 @@ namespace System.Xml.XPath
                                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; }
+               }
                
-               public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
+               internal override bool Peer {
+                       get { return arg0.Peer; }
+               }
 
                public override object Evaluate (BaseIterator iter)
                {
@@ -923,7 +1162,7 @@ namespace System.Xml.XPath
        }
 
 
-       internal class XPathFunctionCeil : XPathFunction
+       internal class XPathFunctionCeil : XPathNumericFunction
        {
                Expression arg0;
                
@@ -933,8 +1172,18 @@ namespace System.Xml.XPath
                                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; }
+               }
                
-               public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
+               internal override bool Peer {
+                       get { return arg0.Peer; }
+               }
 
                public override object Evaluate (BaseIterator iter)
                {
@@ -948,7 +1197,7 @@ namespace System.Xml.XPath
        }
 
 
-       internal class XPathFunctionRound : XPathFunction
+       internal class XPathFunctionRound : XPathNumericFunction
        {
                Expression arg0;
                
@@ -959,11 +1208,25 @@ namespace System.Xml.XPath
                        arg0 = args.Arg;
                }
                
-               public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
+               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)
                {
-                       double arg = arg0.EvaluateNumber (iter);
+                       return Round (arg0.EvaluateNumber (iter));
+               }
+
+               private double Round (double arg)
+               {
                        if (arg < -0.5 || arg > 0)
                                return Math.Floor (arg + 0.5);
                        return Math.Round (arg);