* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / System.XML / System.Xml.XPath / DefaultContext.cs
index c0b928f89d6a65823a92d8d1fd11a187aed2ef0f..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,6 +57,10 @@ 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 ();
                }
 
@@ -67,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;
@@ -75,14 +101,36 @@ namespace System.Xml.XPath
                                        return "";
                                return iter.Current.Value;
                        }
+                       if (arg is XPathNavigator)
+                       {
+                               return ((XPathNavigator) arg).Value;
+                       }
                        throw new ArgumentException ();
                }
 
+               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) {
                                string s = arg as string;
@@ -128,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;
@@ -154,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;
@@ -183,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;
@@ -221,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;
@@ -244,7 +308,7 @@ namespace System.Xml.XPath
                                        rgNodes.Add (n.Clone ());
 
                        rgNodes.Sort (XPathNavigatorComparer.Instance);
-                       return new ListIterator (iter, rgNodes, true);
+                       return new ListIterator (iter, rgNodes);
                }
 
                public override string ToString ()
@@ -267,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)
                {
@@ -298,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; }}
                
@@ -333,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)
                {
@@ -347,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,
+                                ")");
                }
        }
 
@@ -361,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)
@@ -394,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)
                {
@@ -411,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 ();
                }
@@ -435,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)
                {
@@ -462,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)
                {
@@ -489,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)
                {
@@ -521,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)
                {
@@ -555,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)
                {
@@ -612,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)
                {
@@ -646,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;
@@ -700,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)
                {
@@ -737,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;
                
@@ -751,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)
                {
@@ -767,7 +904,7 @@ namespace System.Xml.XPath
        }
 
 
-       internal class XPathFunctionNot : XPathFunction
+       internal class XPathFunctionNot : XPathBooleanFunction
        {
                Expression arg0;
                
@@ -778,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)
                {
@@ -792,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)
                {
@@ -814,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)
                {
@@ -845,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]);
                }
@@ -862,8 +1031,21 @@ namespace System.Xml.XPath
                }
        }
 
+       internal abstract class XPathNumericFunction : XPathFunction
+       {
+               internal XPathNumericFunction (FunctionArguments args)
+                       : base (args)
+               {
+               }
+
+               public override XPathResultType ReturnType { get { return XPathResultType.Number; }}
+
+               public override object StaticValue {
+                       get { return StaticValueAsNumber; }
+               }
+       }
 
-       internal class XPathFunctionNumber : XPathFunction
+       internal class XPathFunctionNumber : XPathNumericFunction
        {
                Expression arg0;
                
@@ -875,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)
                {
@@ -892,7 +1094,7 @@ namespace System.Xml.XPath
        }
 
 
-       internal class XPathFunctionSum : XPathFunction
+       internal class XPathFunctionSum : XPathNumericFunction
        {
                Expression arg0;
                
@@ -903,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)
                {
@@ -923,7 +1127,7 @@ namespace System.Xml.XPath
        }
 
 
-       internal class XPathFunctionFloor : XPathFunction
+       internal class XPathFunctionFloor : XPathNumericFunction
        {
                Expression arg0;
                
@@ -933,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)
                {
@@ -948,7 +1162,7 @@ namespace System.Xml.XPath
        }
 
 
-       internal class XPathFunctionCeil : XPathFunction
+       internal class XPathFunctionCeil : XPathNumericFunction
        {
                Expression arg0;
                
@@ -958,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)
                {
@@ -973,7 +1197,7 @@ namespace System.Xml.XPath
        }
 
 
-       internal class XPathFunctionRound : XPathFunction
+       internal class XPathFunctionRound : XPathNumericFunction
        {
                Expression arg0;
                
@@ -984,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);