From dda2afcff17e525e74f9294622ffcbb652589d22 Mon Sep 17 00:00:00 2001 From: Atsushi Eno Date: Fri, 22 Oct 2004 18:36:23 +0000 Subject: 2004-10-22 Atsushi Enomoto SequenceType.cs, XPath2Expression.cs, XPathSequence.cs, XQueryASTCompiler.cs, XQueryArithmeticOperator.cs, XQueryCliFunction.cs, XQueryCommandImpl.cs, XQueryComparisonOperator.cs, XQueryCompileContext.cs, XQueryCompileOptions.cs, XQueryContext.cs, XQueryConvert.cs, XQueryDefaultFunctionCall.cs, (not in use), XQueryExpression.cs, XQueryFunction.cs, XQueryFunctionCliImpl.cs, XQueryFunctionContextAttribute.cs, XQueryFunctionTable.cs, XQueryModuleProlog.cs, XQueryStaticContext.cs, XQueryTokenizer.cs, XmlQueryCompileException.cs, XmlQueryException.cs, XQueryParser.jay, skelton-2.0.cs: Initial Checkin (it is not compiled as yet). svn path=/trunk/mcs/; revision=35257 --- mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/ChangeLog | 28 + .../Mono.Xml.Ext/Mono.Xml.XPath2/SequenceType.cs | 728 ++++++ .../Mono.Xml.XPath2/XPath2Expression.cs | 2439 +++++++++++++++++++ .../Mono.Xml.Ext/Mono.Xml.XPath2/XPathSequence.cs | 1779 ++++++++++++++ .../Mono.Xml.XPath2/XQueryASTCompiler.cs | 265 ++ .../Mono.Xml.XPath2/XQueryArithmeticOperator.cs | 368 +++ .../Mono.Xml.XPath2/XQueryCliFunction.cs | 210 ++ .../Mono.Xml.XPath2/XQueryCommandImpl.cs | 100 + .../Mono.Xml.XPath2/XQueryComparisonOperator.cs | 235 ++ .../Mono.Xml.XPath2/XQueryCompileContext.cs | 93 + .../Mono.Xml.XPath2/XQueryCompileOptions.cs | 101 + .../Mono.Xml.Ext/Mono.Xml.XPath2/XQueryContext.cs | 318 +++ .../Mono.Xml.Ext/Mono.Xml.XPath2/XQueryConvert.cs | 1021 ++++++++ .../Mono.Xml.XPath2/XQueryDefaultFunctionCall.cs | 387 +++ .../Mono.Xml.XPath2/XQueryExpression.cs | 579 +++++ .../Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunction.cs | 322 +++ .../Mono.Xml.XPath2/XQueryFunctionCliImpl.cs | 1135 +++++++++ .../XQueryFunctionContextAttribute.cs | 45 + .../Mono.Xml.XPath2/XQueryFunctionTable.cs | 66 + .../Mono.Xml.XPath2/XQueryModuleProlog.cs | 529 ++++ .../Mono.Xml.Ext/Mono.Xml.XPath2/XQueryParser.jay | 2535 ++++++++++++++++++++ .../Mono.Xml.XPath2/XQueryStaticContext.cs | 231 ++ .../Mono.Xml.XPath2/XQueryTokenizer.cs | 1285 ++++++++++ .../Mono.Xml.XPath2/XmlQueryCompileException.cs | 74 + .../Mono.Xml.XPath2/XmlQueryException.cs | 112 + .../Mono.Xml.Ext/Mono.Xml.XPath2/skeleton-2.0.cs | 364 +++ 26 files changed, 15349 insertions(+) create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/ChangeLog create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/SequenceType.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XPath2Expression.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XPathSequence.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryASTCompiler.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryArithmeticOperator.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryCliFunction.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryCommandImpl.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryComparisonOperator.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryCompileContext.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryCompileOptions.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryContext.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryConvert.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryDefaultFunctionCall.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryExpression.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunction.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunctionCliImpl.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunctionContextAttribute.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunctionTable.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryModuleProlog.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryParser.jay create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryStaticContext.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryTokenizer.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XmlQueryCompileException.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XmlQueryException.cs create mode 100755 mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/skeleton-2.0.cs (limited to 'mcs/class/Mono.Xml.Ext') diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/ChangeLog b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/ChangeLog new file mode 100755 index 00000000000..fe9cf44b453 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/ChangeLog @@ -0,0 +1,28 @@ +2004-10-22 Atsushi Enomoto + + SequenceType.cs, + XPath2Expression.cs, + XPathSequence.cs, + XQueryASTCompiler.cs, + XQueryArithmeticOperator.cs, + XQueryCliFunction.cs, + XQueryCommandImpl.cs, + XQueryComparisonOperator.cs, + XQueryCompileContext.cs, + XQueryCompileOptions.cs, + XQueryContext.cs, + XQueryConvert.cs, + XQueryDefaultFunctionCall.cs, (not in use), + XQueryExpression.cs, + XQueryFunction.cs, + XQueryFunctionCliImpl.cs, + XQueryFunctionContextAttribute.cs, + XQueryFunctionTable.cs, + XQueryModuleProlog.cs, + XQueryStaticContext.cs, + XQueryTokenizer.cs, + XmlQueryCompileException.cs, + XmlQueryException.cs, + XQueryParser.jay, + skelton-2.0.cs: Initial Checkin (it is not compiled as yet). + diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/SequenceType.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/SequenceType.cs new file mode 100755 index 00000000000..dadaeb8b8f0 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/SequenceType.cs @@ -0,0 +1,728 @@ +// +// SequenceType.cs - represents XPath 2.0 item type +// +// Author: +// Atsushi Enomoto +// +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// + +#if NET_2_0 +using System; +using System.Collections; +using System.Globalization; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Query; +using System.Xml.XPath; +using Mono.Xml; + +namespace Mono.Xml.XPath2 +{ + public class SequenceType + { + static SequenceType singleItem = new SequenceType (ItemType.AnyItem, Occurence.One); + static SequenceType singleAnyAtomic = new SequenceType (ItemType.AnyAtomicType, Occurence.One); + + internal static SequenceType AnyType { + get { return Create (InternalPool.XsAnyType, Occurence.ZeroOrMore); } + } + internal static SequenceType SingleItem { + get { return singleItem; } + } + internal static SequenceType SingleAnyAtomic { + get { return singleAnyAtomic; } + } + + internal static SequenceType Node { + get { return Create (XmlTypeCode.Node, Occurence.One); } + } + internal static SequenceType Document { + get { return Create (XmlTypeCode.Document, Occurence.One); } + } + internal static SequenceType Element { + get { return Create (XmlTypeCode.Element, Occurence.One); } + } + internal static SequenceType Attribute { + get { return Create (XmlTypeCode.Attribute, Occurence.One); } + } + internal static SequenceType Namespace { + get { return Create (XmlTypeCode.Namespace, Occurence.One); } + } + internal static SequenceType Text { + get { return Create (XmlTypeCode.Text, Occurence.One); } + } + internal static SequenceType XmlPI { + get { return Create (XmlTypeCode.ProcessingInstruction, Occurence.One); } + } + internal static SequenceType Comment { + get { return Create (XmlTypeCode.Comment, Occurence.One); } + } + + internal static SequenceType AtomicString { + get { return Create (InternalPool.XsString, Occurence.One); } + } + internal static SequenceType Boolean { + get { return Create (InternalPool.XsBoolean, Occurence.One); } + } + internal static SequenceType Decimal { + get { return Create (InternalPool.XsDecimal, Occurence.One); } + } + internal static SequenceType Integer { + get { return Create (InternalPool.XsInteger, Occurence.One); } + } + internal static SequenceType Int { + get { return Create (InternalPool.XsInt, Occurence.One); } + } + internal static SequenceType Short { + get { return Create (InternalPool.XsShort, Occurence.One); } + } + internal static SequenceType UnsignedInt { + get { return Create (InternalPool.XsUnsignedInt, Occurence.One); } + } + internal static SequenceType UnsignedShort { + get { return Create (InternalPool.XsUnsignedShort, Occurence.One); } + } + internal static SequenceType Double { + get { return Create (InternalPool.XsDouble, Occurence.One); } + } + internal static SequenceType Single { + get { return Create (InternalPool.XsFloat, Occurence.One); } + } + internal static SequenceType DateTime { + get { return Create (InternalPool.XsDateTime, Occurence.One); } + } + internal static SequenceType QName { + get { return Create (InternalPool.XsQName, Occurence.One); } + } + + internal static SequenceType IntegerList { + get { return Create (XmlTypeCode.Integer, Occurence.ZeroOrMore); } + } + + + static Hashtable standardTypes = new Hashtable (); + + internal static SequenceType Create (Type cliType) + { + // typed Array + if (cliType.IsArray) + return Create (InternalPool.XmlTypeCodeFromRuntimeType (cliType.GetElementType (), true), Occurence.ZeroOrMore); +// if (cliType.GetInterface ("System.Collections.IEnumerable") != null) +// return Create (XmlTypeCode.Item, Occurence.ZeroOrMore); + if (cliType == typeof (XmlQualifiedName)) + return QName; + if (cliType == typeof (XPathNavigator) || cliType.IsSubclassOf (typeof (XPathNavigator))) + return Node; + if (cliType == typeof (XPathAtomicValue)) + return SingleAnyAtomic; + if (cliType == typeof (XPathItem)) + return SingleItem; + // FIXME: handle Nullable type + return Create (InternalPool.XmlTypeCodeFromRuntimeType (cliType, true), Occurence.One); + } + + internal static SequenceType Create (XmlTypeCode typeCode, Occurence occurence) + { + switch (typeCode) { + case XmlTypeCode.Item: + case XmlTypeCode.AnyAtomicType: + case XmlTypeCode.Node: + case XmlTypeCode.Document: + case XmlTypeCode.Element: + case XmlTypeCode.Attribute: + case XmlTypeCode.ProcessingInstruction: + case XmlTypeCode.Comment: + case XmlTypeCode.Namespace: + case XmlTypeCode.Text: + return new SequenceType (new ItemType (typeCode), occurence); + default: + return Create (XmlSchemaType.GetBuiltInSimpleType (typeCode), occurence); + } + } + + internal static SequenceType Create (XmlSchemaType schemaType, Occurence occurence) + { + switch (schemaType.QualifiedName.Namespace) { + case XmlSchema.Namespace: + case InternalPool.XdtNamespace: + break; + default: + return new SequenceType (schemaType, occurence); + } + + Hashtable cacheForType = standardTypes [schemaType] as Hashtable; + if (cacheForType == null) { + cacheForType = new Hashtable (); + standardTypes [schemaType] = cacheForType; + } else { + SequenceType type = cacheForType [occurence] as SequenceType; + if (type != null) + return type; + } + SequenceType t = new SequenceType (schemaType, occurence); + cacheForType [occurence] = t; + return t; + } + + [MonoTODO] + internal static SequenceType ComputeCommonBase (SequenceType t1, SequenceType t2) + { + // FIXME: implement + // throw new NotImplementedException (); + return SequenceType.AnyType; + } + + internal static bool IsNumeric (XmlTypeCode code) + { + switch (code) { + case XmlTypeCode.Decimal: + case XmlTypeCode.Float: + case XmlTypeCode.Double: + case XmlTypeCode.Integer: + case XmlTypeCode.NonPositiveInteger: + case XmlTypeCode.NegativeInteger: + case XmlTypeCode.Long: + case XmlTypeCode.Int: + case XmlTypeCode.Short: + case XmlTypeCode.Byte: + case XmlTypeCode.NonNegativeInteger: + case XmlTypeCode.UnsignedLong: + case XmlTypeCode.UnsignedInt: + case XmlTypeCode.UnsignedShort: + case XmlTypeCode.UnsignedByte: + case XmlTypeCode.PositiveInteger: + return true; + } + return false; + } + + // Instance members + + private SequenceType (XmlSchemaType schemaType, Occurence occurence) + { + this.schemaType = schemaType; + this.itemType = ItemType.AnyItem; + this.occurence = occurence; + } + + internal SequenceType (ItemType itemType, Occurence occurence) + { + this.schemaType = InternalPool.XsAnyType; + this.itemType = itemType; + this.occurence = occurence; + } + + XmlSchemaType schemaType; + Occurence occurence; + ItemType itemType; + + public XmlSchemaType SchemaType { + get { return schemaType; } + } + + public ItemType ItemType { + get { return itemType; } + } + + public Occurence Occurence { + get { return occurence; } + } + + internal bool Matches (XPathSequence iter) + { + throw new NotImplementedException (); + } + + [MonoTODO] + internal bool CanConvertTo (SequenceType other) + { + // FIXME: implement precisely + return this == other; + // throw new NotImplementedException (); + } + + internal bool CanConvert (XPathSequence iter) + { + bool occured = false; + bool onlyOnce = (occurence == Occurence.One || occurence == Occurence.Optional); + bool required = (occurence == Occurence.One || occurence == Occurence.OneOrMore); + foreach (XPathItem item in iter) { + if (occured && onlyOnce) + return false; + if (!CanConvert (item)) + return false; + } + return occured || !required; + } + + public bool CanConvert (XPathItem item) + { + throw new NotImplementedException (); + } + + public bool IsInstance (XPathItem item) + { + throw new NotImplementedException (); + } + + public XPathItem Convert (XPathItem item) + { + throw new NotImplementedException (); + } + + public object ToRuntimeType (XPathSequence seq) + { + // FIXME: handle ZeroOrMore|OneOrMore + switch (occurence) { + case Occurence.One: + case Occurence.Optional: + if (!seq.MoveNext ()) + return null; + XPathItem item = seq.Current; + // FIXME: should check and reject two or + // more items?? + return item.TypedValue; + } + ArrayList al = new ArrayList (); + while (seq.MoveNext ()) + al.Add (seq.Current.TypedValue); + return al.ToArray (InternalPool.RuntimeTypeFromXmlTypeCode (schemaType.TypeCode)); +// return seq; + } + } + + public enum Occurence + { + One, + Optional, + ZeroOrMore, + OneOrMore, + } + + #region NodeTest + + public enum XPathAxisType + { + Child, + Descendant, + Attribute, + Self, + DescendantOrSelf, + FollowingSibling, + Following, + Parent, + Ancestor, + PrecedingSibling, + Preceding, + AncestorOrSelf, + Namespace // only applicable under XPath 2.0, not XQuery 1.0 + } + + public class XPathAxis + { + // FIXME: add more parameters to distinguish them + private XPathAxis (XPathAxisType axisType) + { + this.axisType = axisType; + switch (axisType) { + case XPathAxisType.Parent: + case XPathAxisType.Ancestor: + case XPathAxisType.AncestorOrSelf: + case XPathAxisType.Preceding: + case XPathAxisType.PrecedingSibling: + this.reverse = true; + break; + } + } + + bool reverse; + XPathAxisType axisType; + + public bool ReverseAxis { + get { return reverse; } + } + + public XPathAxisType AxisType { + get { return axisType; } + } + + static XPathAxis child, descendant, attribute, self, + descendantOrSelf, followingSibling, following, + parent, ancestor, precedingSibling, preceding, + ancestorOrSelf; + + static XPathAxis () + { + child = new XPathAxis (XPathAxisType.Child); + descendant = new XPathAxis (XPathAxisType.Descendant); + attribute = new XPathAxis (XPathAxisType.Attribute); + self = new XPathAxis (XPathAxisType.Self); + descendantOrSelf = new XPathAxis (XPathAxisType.DescendantOrSelf); + followingSibling = new XPathAxis (XPathAxisType.FollowingSibling); + following = new XPathAxis (XPathAxisType.Following); + parent = new XPathAxis (XPathAxisType.Parent); + ancestor = new XPathAxis (XPathAxisType.Ancestor); + precedingSibling = new XPathAxis (XPathAxisType.PrecedingSibling); + preceding = new XPathAxis (XPathAxisType.Preceding); + ancestorOrSelf = new XPathAxis (XPathAxisType.AncestorOrSelf); + } + + public static XPathAxis Child { + get { return child; } + } + + public static XPathAxis Descendant { + get { return descendant; } + } + + public static XPathAxis Attribute { + get { return attribute; } + } + + public static XPathAxis Self { + get { return self; } + } + + public static XPathAxis DescendantOrSelf { + get { return descendantOrSelf; } + } + + public static XPathAxis FollowingSibling { + get { return followingSibling; } + } + + public static XPathAxis Following { + get { return following; } + } + + public static XPathAxis Parent { + get { return parent; } + } + + public static XPathAxis Ancestor { + get { return ancestor; } + } + + public static XPathAxis PrecedingSibling { + get { return precedingSibling; } + } + + public static XPathAxis Preceding { + get { return preceding; } + } + + public static XPathAxis AncestorOrSelf { + get { return ancestorOrSelf; } + } + } + + // ItemType + public class ItemType + { + static ItemType anyItem = new ItemType (XmlTypeCode.Item); + static ItemType anyAtomicType = new ItemType (XmlTypeCode.AnyAtomicType); + + public static ItemType AnyItem { + get { return anyItem; } + } + + public static ItemType AnyAtomicType { + get { return anyAtomicType; } + } + + XmlTypeCode typeCode; + + public ItemType (XmlTypeCode typeCode) + { + this.typeCode = typeCode; + } + + public XmlTypeCode TypeCode { + get { return typeCode; } + } + + internal virtual void CheckReference (XQueryASTCompiler compiler) + { + } + } + + // KindTest + + public class KindTest : ItemType + { + public KindTest (XmlTypeCode type) + : base (type) + { + } + + internal virtual void Compile (XQueryASTCompiler compiler) + { + } + + public virtual bool Matches (XPathItem item) + { + XPathNavigator nav = item as XPathNavigator; + if (nav == null) + return false; + // FIXME: is it true? ('untyped' means 'matches with any type' ? + if (item.XmlType == null) + return true; + if (item.XmlType.TypeCode != TypeCode) + return false; + return true; + } + } + + public class DocumentTest : KindTest + { + ElementTest content; + + public DocumentTest (ElementTest content) + : base (XmlTypeCode.Document) + { + this.content = content; + } + + public ElementTest Content { + get { return content; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + content.CheckReference (compiler); + } + + internal override void Compile (XQueryASTCompiler compiler) + { + } + + public override bool Matches (XPathItem item) + { + XPathNavigator nav = item as XPathNavigator; + if (nav == null) + return false; + + if (item.XmlType.TypeCode != XmlTypeCode.Document) + return false; + + if (Content == null) + return true; + + nav = nav.Clone (); + nav.MoveToFirstChild (); + while (nav.NodeType != XPathNodeType.Element) + if (!nav.MoveToNext ()) + return false; + return Content.Matches (nav); + } + } + + public class ElementTest : KindTest + { + XmlQualifiedName name; + XmlQualifiedName typeName; + XmlSchemaType schemaType; + bool nillable; + + public ElementTest (XmlQualifiedName name) + : base (XmlTypeCode.Element) + { + this.name = name; + } + + public ElementTest (XmlQualifiedName name, XmlQualifiedName type, bool nillable) + : base (XmlTypeCode.Element) + { + this.name = name; + this.typeName = type; + this.nillable = nillable; + } + + public XmlQualifiedName Name { + get { return name; } + } + + public XmlQualifiedName TypeName { + get { return typeName; } + } + + public XmlSchemaType SchemaType { + get { + return schemaType; + } + } + + public bool Nillable { + get { return nillable; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + compiler.CheckSchemaTypeName (typeName); + } + + internal override void Compile (XQueryASTCompiler compiler) + { + schemaType = compiler.ResolveSchemaType (TypeName); + if (schemaType == null) + throw new XmlQueryCompileException ("Specified schema type was not found."); + } + + public override bool Matches (XPathItem item) + { + XPathNavigator nav = item as XPathNavigator; + if (nav == null) + return false; + + if (item.XmlType.TypeCode != XmlTypeCode.Element) + return false; + + if (Name != XmlQualifiedName.Empty) + if (nav.LocalName != Name.Name || nav.NamespaceURI != Name.Namespace) + return false; + + // FIXME: it won't be XQueryConvert.CanConvert(), but other strict-matching evaluation + if (SchemaType != null && !XQueryConvert.CanConvert (item, SchemaType)) + return false; + // FIXME: check nillable + + return true; + } + } + + public class AttributeTest : KindTest + { + static AttributeTest anyAttribute; + + static AttributeTest () + { + anyAttribute = new AttributeTest (XmlQualifiedName.Empty); + } + + public static AttributeTest AnyAttribute { + get { return anyAttribute; } + } + + public AttributeTest (XmlQualifiedName name) + : base (XmlTypeCode.Attribute) + { + this.name = name; + } + + public AttributeTest (XmlQualifiedName name, XmlQualifiedName typeName) + : base (XmlTypeCode.Attribute) + { + this.name = name; + this.typeName = typeName; + } + + XmlQualifiedName name; + XmlQualifiedName typeName; + XmlSchemaType schemaType; + + public XmlQualifiedName Name { + get { return name; } + } + + public XmlQualifiedName TypeName { + get { return typeName; } + } + + public XmlSchemaType SchemaType { + get { return schemaType; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + compiler.CheckSchemaTypeName (typeName); + } + + internal override void Compile (XQueryASTCompiler compiler) + { + schemaType = compiler.ResolveSchemaType (TypeName); + if (schemaType == null) + throw new XmlQueryCompileException ("Specified schema type was not found."); + } + + public override bool Matches (XPathItem item) + { + XPathNavigator nav = item as XPathNavigator; + if (nav == null) + return false; + + if (item.XmlType.TypeCode != XmlTypeCode.Attribute) + return false; + + if (Name != XmlQualifiedName.Empty) + if (nav.LocalName != Name.Name || nav.NamespaceURI != Name.Namespace) + return false; + + // FIXME: it won't be XQueryConvert.CanConvert(), but other strict-matching evaluation + if (SchemaType != null && !XQueryConvert.CanConvert (item, SchemaType)) + return false; + + return true; + } + } + + public class XmlPITest : KindTest + { + string name; + + public XmlPITest (string nameTest) + : base (XmlTypeCode.ProcessingInstruction) + { + this.name = nameTest; + } + + public string Name { + get { return name; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + } + + internal override void Compile (XQueryASTCompiler compiler) + { + } + + public override bool Matches (XPathItem item) + { + XPathNavigator nav = item as XPathNavigator; + if (nav == null) + return false; + + if (item.XmlType.TypeCode != XmlTypeCode.ProcessingInstruction) + return false; + if (Name != String.Empty && nav.LocalName != Name) + return false; + return true; + } + } + + #endregion +} + +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XPath2Expression.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XPath2Expression.cs new file mode 100755 index 00000000000..f4ec7fff289 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XPath2Expression.cs @@ -0,0 +1,2439 @@ +// +// XPath2Expression.cs - abstract syntax tree for XPath 2.0 +// +// Author: +// Atsushi Enomoto +// +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// +#if NET_2_0 +using System; +using System.Collections; +using System.Globalization; +using System.Xml; +using System.Xml.Query; +using System.Xml.Schema; +using System.Xml.XPath; +using Mono.Xml.XQuery; +using Mono.Xml; + +namespace Mono.Xml.XPath2 +{ + public class ExprSequence : CollectionBase + { + public ExprSequence () + { + } + + public void Add (ExprSingle expr) + { + List.Add (expr); + } + + public void AddRange (ICollection items) + { + if (items != null) + foreach (ExprSingle e in items) + List.Add (e); + } + + public void Insert (int pos, ExprSingle expr) + { + List.Insert (pos, expr); + } + + public ExprSingle this [int i] { + get { return List [i] as ExprSingle; } + set { List [i] = value; } + } + + internal void CheckReference (XQueryASTCompiler compiler) + { + foreach (ExprSingle expr in List) + expr.CheckReference (compiler); + } + } + + public abstract partial class ExprSingle + { + internal abstract void CheckReference (XQueryASTCompiler compiler); + +#region CompileAndEvaluate + internal static readonly XPathAtomicValue AtomicTrue = new XPathAtomicValue (true, InternalPool.XsBoolean); + internal static readonly XPathAtomicValue AtomicFalse = new XPathAtomicValue (false, InternalPool.XsBoolean); + + XQueryStaticContext ctx; + + internal ExprSingle Compile (XQueryASTCompiler compiler) + { + this.ctx = ctx; + return CompileCore (compiler); + } + + // If internal&&protected is available in C#, it is the best signature. + internal abstract ExprSingle CompileCore (XQueryASTCompiler compiler); + + internal XQueryStaticContext Context { + get { return ctx; } + } + + public abstract SequenceType StaticType { get; } + + /** + This is the core part of ExprSingle. It is + generally used to evaluate expression and returns + XPathItem sequence (iterator). The result is unordered + */ + public abstract XPathSequence Evaluate (XPathSequence iter); + + public virtual XPathSequence EvaluateOrdered (XPathSequence iter) + { + if (RequireSorting) { + ArrayList al = new ArrayList (); + foreach (XPathItem item in Evaluate (iter)) + al.Add (item); + return new ListIterator (iter.Context, al); + } + else + return Evaluate (iter); + } + + public virtual void Serialize (XPathSequence iter) + { + XmlWriter w = iter.Context.Writer; + XPathSequence result = Evaluate (iter); + bool initial = true; + foreach (XPathItem item in result) { + if (initial) + initial = false; + else + w.WriteWhitespace (" "); + WriteXPathItem (item, w); + } + } + + private void WriteXPathItem (XPathItem item, XmlWriter w) + { + if (item.IsNode) { + XPathNavigator nav = item as XPathNavigator; + if (w.WriteState != WriteState.Start && nav.NodeType == XPathNodeType.Root) + throw new XmlQueryException ("Current output can not accept root node."); + if (w.WriteState == WriteState.Attribute) + w.WriteString (nav.Value); + else + w.WriteNode (nav, false); + } else + w.WriteString (item.Value); + } + + // get EBV (fn:boolean()) + public virtual bool EvaluateAsBoolean (XPathSequence iter) + { + XPathSequence result = Evaluate (iter); + if (!result.MoveNext ()) + return false; + XPathItem v = result.Current; + if (v is XPathNavigator) + return true; + if (result.MoveNext ()) + return true; + switch (v.XmlType.TypeCode) { + case XmlTypeCode.Boolean: + return v.ValueAsBoolean; + case XmlTypeCode.String: + case XmlTypeCode.UntypedAtomic: + return v.Value != String.Empty; + case XmlTypeCode.Float: + return v.ValueAsSingle != Single.NaN && v.ValueAsSingle != 0.0; + case XmlTypeCode.Double: + return v.ValueAsDouble != Double.NaN && v.ValueAsSingle != 0.0; + case XmlTypeCode.Decimal: + return v.ValueAsDecimal != 0; + case XmlTypeCode.Integer: + case XmlTypeCode.NonPositiveInteger: + case XmlTypeCode.NegativeInteger: + case XmlTypeCode.Long: + case XmlTypeCode.Int: + case XmlTypeCode.Short: + case XmlTypeCode.Byte: + case XmlTypeCode.UnsignedInt: + case XmlTypeCode.UnsignedShort: + case XmlTypeCode.UnsignedByte: + return v.ValueAsInt64 != 0; + case XmlTypeCode.NonNegativeInteger: + case XmlTypeCode.UnsignedLong: + case XmlTypeCode.PositiveInteger: + return (ulong) (v.ValueAs (typeof (ulong))) != 0; + } + // otherwise, return true + return true; + } + + public virtual int EvaluateAsInt (XPathSequence iter) + { + XPathAtomicValue v = Atomize (Evaluate (iter)); + return v != null ? v.ValueAsInt32 : 0; + } + + public virtual string EvaluateAsString (XPathSequence iter) + { + XPathAtomicValue v = Atomize (Evaluate (iter)); + return v != null ? v.Value : String.Empty; + } + + public static XPathAtomicValue Atomize (XPathItem item) + { + XPathNavigator nav = item as XPathNavigator; + if (nav != null) { + if (nav.SchemaInfo != null) { + XmlSchemaType type = nav.SchemaInfo.SchemaType; + XmlSchemaComplexType ct = type as XmlSchemaComplexType; + if (ct != null && ct.ContentType == XmlSchemaContentType.ElementOnly) + throw new XmlQueryException ("An attempt to get atomized value against element-only node happend."); + switch (type.TypeCode) { + case XmlTypeCode.Item: +// case XmlTypeCode.Untyped: + type = XmlSchemaType.GetBuiltInSimpleType (XmlTypeCode.UntypedAtomic); + break; + } + return new XPathAtomicValue (nav.TypedValue, type); + } + else + return new XPathAtomicValue (nav.Value, InternalPool.XdtUntypedAtomic); + } + else + return (XPathAtomicValue) item; + } + + // FIXME: What if iter contains list value? + public static XPathAtomicValue Atomize (XPathSequence iter) + { + if (!iter.MoveNext ()) + return null; + XPathNavigator nav = iter.Current as XPathNavigator; + if (nav != null) { + // FIXME: is it really always untypedAtomic? + // It might be complex content. + XmlSchemaType type = nav.SchemaInfo == null ? InternalPool.XdtUntypedAtomic : nav.SchemaInfo.SchemaType; + return new XPathAtomicValue (nav.TypedValue, type); + } + else + return (XPathAtomicValue) iter.Current; + } + + public virtual XPathAtomicValue EvaluateAsAtomic (XPathSequence iter) + { + return Atomize (Evaluate (iter)); + } + + public virtual bool RequireSorting { + get { return false; } + } +#endregion + } + + // FLWORExpr + + internal partial class FLWORExpr : ExprSingle + { + public FLWORExpr (ForLetClauseCollection forlet, ExprSequence whereClause, OrderSpecList orderBy, ExprSingle ret) + { + this.fl = forlet; + if (whereClause != null) + this.whereClause = new ParenthesizedExpr (whereClause); + this.orderBy = orderBy; + this.ret = ret; + } + + ForLetClauseCollection fl; + ExprSingle whereClause; + OrderSpecList orderBy; + ExprSingle ret; + + public ForLetClauseCollection ForLetClauses { + get { return fl; } + } + + public ExprSingle WhereClause { + get { return whereClause; } + } + + public OrderSpecList OrderBy { + get { return orderBy; } + } + + public ExprSingle ReturnExpr { + get { return ret; } + set { ret = value; } + } + + // ExprSingle Overrides + + internal override void CheckReference (XQueryASTCompiler compiler) + { + foreach (ForLetClause flc in fl) + foreach (ForLetSingleBody single in flc) + single.CheckReference (compiler); + if (whereClause != null) + whereClause.CheckReference (compiler); + if (orderBy != null) + foreach (OrderSpec os in orderBy) + os.Expression.CheckReference (compiler); + ret.CheckReference (compiler); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + foreach (ForLetClause flc in ForLetClauses) { + foreach (ForLetSingleBody flsb in flc) { + flsb.Expression = flsb.Expression.Compile (compiler); + if (flsb.ReturnType != null) + compiler.CheckType (flsb.Expression, flsb.ReturnType); + } + } + if (WhereClause != null) + whereClause = whereClause.Compile (compiler); + if (OrderBy != null) + foreach (OrderSpec os in OrderBy) + os.Expression = os.Expression.Compile (compiler); + ReturnExpr = ReturnExpr.Compile (compiler); + + return this; + } + + public override SequenceType StaticType { + get { return ReturnExpr.StaticType; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return new FLWORIterator (iter, this); + } +#endregion + } + + internal class ForLetClauseCollection : CollectionBase + { + public void Add (ForLetClause clause) + { + List.Add (clause); + } + + public void Insert (int pos, ForLetClause clause) + { + List.Insert (pos, clause); + } + + public ForLetClause this [int i] { + get { return (ForLetClause) List [i]; } + } + } + + internal class OrderSpecList : CollectionBase + { + bool isStable; + + public OrderSpecList () + { + } + + public bool IsStable { + get { return isStable; } + set { isStable = value; } + } + + public void Insert (int pos, OrderSpec os) + { + List.Insert (pos, os); + } + + public void Add (OrderSpec spec) + { + List.Add (spec); + } + + public OrderSpec this [int i] { + get { return (OrderSpec) List [i]; } + } + } + + internal class OrderSpec + { + public OrderSpec (ExprSingle expr, OrderModifier modifier) + { + this.expr = expr; + this.mod = modifier; + } + + ExprSingle expr; + OrderModifier mod; + + public ExprSingle Expression { + get {return expr; } + set { expr = value; } + } + + public OrderModifier Modifier { + get { return mod; } + set { mod = value; } + } + } + + internal class OrderModifier + { + public OrderModifier (XmlSortOrder order, XmlSortOrder emptyOrder, string collation) + { + this.sortOrder = sortOrder; + this.emptyOrder = emptyOrder; + if (collation != null) + this.coll = new CultureInfo (collation); + } + + XmlSortOrder sortOrder; + XmlSortOrder emptyOrder; + CultureInfo coll; + + public XmlSortOrder SortOrder { + get { return sortOrder; } + } + + public XmlSortOrder EmptyOrder { + get { return emptyOrder; } + } + + public CultureInfo Collation { + get { return coll; } + } + } + + internal class ForLetClause : CollectionBase + { + public ForLetSingleBody this [int i] { + get { return (ForLetSingleBody) List [i]; } + } + } + + internal class ForClause : ForLetClause + { + public ForClause () + { + } + + public void Insert (int pos, ForSingleBody body) + { + List.Insert (pos, body); + } + + public void Add (ForSingleBody body) + { + List.Add (body); + } + } + + internal class LetClause : ForLetClause + { + public LetClause () + { + } + + public void Insert (int pos, LetSingleBody body) + { + List.Insert (pos, body); + } + + public void Add (LetSingleBody body) + { + List.Add (body); + } + } + + internal abstract class ForLetSingleBody + { + XmlQualifiedName varName; + SequenceType type; + ExprSingle expr; + + public ForLetSingleBody (XmlQualifiedName varName, SequenceType type, ExprSingle expr) + { + this.varName = varName; + this.type = type; + this.expr = expr; + } + + public XmlQualifiedName VarName { + get { return varName; } + } + + public SequenceType ReturnType { + get { return type; } + } + + public ExprSingle Expression { + get { return expr; } + set { expr = value; } + } + + internal void CheckReference (XQueryASTCompiler compiler) + { + if (type != null) + compiler.CheckSchemaType (type); + expr.CheckReference (compiler); + } + } + + internal class ForSingleBody : ForLetSingleBody + { + public ForSingleBody (XmlQualifiedName varName, SequenceType type, XmlQualifiedName positionalVar, ExprSingle expr) + : base (varName, type, expr) + { + this.positionalVar = positionalVar; + } + + XmlQualifiedName positionalVar; + + public XmlQualifiedName PositionalVar { + get { return positionalVar; } + } + } + + internal class LetSingleBody : ForLetSingleBody + { + public LetSingleBody (XmlQualifiedName varName, SequenceType type, ExprSingle expr) + : base (varName, type, expr) + { + } + } + + // QuantifiedExpr + + internal class QuantifiedExpr : ExprSingle + { + QuantifiedExprBodyList body; + ExprSingle satisfies; + bool every; + + public QuantifiedExpr (bool every, QuantifiedExprBodyList body, ExprSingle satisfies) + { + this.every = every; + this.body = body; + this.satisfies = satisfies; + } + + public bool Every { + get { return every; } + } + + public QuantifiedExprBodyList BodyList { + get { return body; } + } + + public ExprSingle Satisfies { + get { return satisfies; } + set { satisfies = value; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + foreach (QuantifiedExprBody one in body) { + if (one.Type != null) + compiler.CheckSchemaType (one.Type); + one.Expression.CheckReference (compiler); + } + Satisfies.CheckReference (compiler); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + Satisfies = Satisfies.Compile (compiler); + for (int i = 0; i < BodyList.Count; i++) { + BodyList [i].Expression = BodyList [i].Expression.Compile (compiler); + if (BodyList [i].Type != null) + compiler.CheckType (BodyList [i].Expression, BodyList [i].Type); + } + return this; + } + + public override SequenceType StaticType { + get { return SequenceType.Boolean; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return new SingleItemIterator (EvaluateAsBoolean (iter) ? AtomicTrue : AtomicFalse, iter.Context); + } + + public override bool EvaluateAsBoolean (XPathSequence iter) + { + return EvaluateQuantification (iter, BodyList.GetEnumerator ()); + } + + private bool EvaluateQuantification (XPathSequence iter, IEnumerator bodies) + { + if (bodies.MoveNext ()) { + QuantifiedExprBody qb = bodies.Current as QuantifiedExprBody; + XPathSequence seq = qb.Expression.Evaluate (iter); + bool passed = false; + foreach (XPathItem item in seq) { + passed = true; + // FIXME: consider qb.Type + try { + iter.Context.PushVariable (qb.VarName, item); + if (EvaluateQuantification (iter, bodies)) { + if (!Every) + return true; + } + else if (Every) + return false; + } finally { + iter.Context.PopVariable (); + } + } + return passed; + } + return Satisfies.EvaluateAsBoolean (iter); + } +#endregion + } + + internal class QuantifiedExprBodyList : CollectionBase + { + public QuantifiedExprBodyList () + { + } + + public void Add (QuantifiedExprBody body) + { + List.Add (body); + } + + public void Insert (int pos, QuantifiedExprBody body) + { + List.Insert (pos, body); + } + + public QuantifiedExprBody this [int i] { + get { return (QuantifiedExprBody) List [i]; } + } + } + + internal class QuantifiedExprBody + { + private XmlQualifiedName varName; + private SequenceType type; + private ExprSingle expr; + + public QuantifiedExprBody (XmlQualifiedName varName, + SequenceType type, ExprSingle expr) + { + this.varName = varName; + this.type = type ; + this.expr = expr; + } + + public XmlQualifiedName VarName { + get { return varName; } + } + + public SequenceType Type { + get { return type; } + } + + public ExprSingle Expression { + get { return expr; } + set { expr = value; } + } + } + + // TypeswitchExpr + + internal class TypeswitchExpr : ExprSingle + { + ExprSequence switchExpr; + CaseClauseList caseList; + XmlQualifiedName defaultVarName; + ExprSingle defaultReturn; + + public TypeswitchExpr (ExprSequence switchExpr, CaseClauseList caseList, XmlQualifiedName defaultVarName, ExprSingle defaultReturn) + { + this.switchExpr = switchExpr; + this.caseList = caseList; + this.defaultVarName = defaultVarName; + this.defaultReturn = defaultReturn; + } + + public ExprSequence SwitchExpr { + get { return switchExpr; } + } + + public CaseClauseList Cases { + get { return caseList; } + } + + public XmlQualifiedName DefaultVarName { + get { return defaultVarName; } + } + + public ExprSingle DefaultReturn { + get { return defaultReturn; } + set { defaultReturn = value; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + switchExpr.CheckReference (compiler); + foreach (CaseClause cc in caseList) { + compiler.CheckSchemaType (cc.Type); + cc.Expr.CheckReference (compiler); + } + defaultReturn.CheckReference (compiler); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + for (int i = 0; i < SwitchExpr.Count; i++) + SwitchExpr [i] = SwitchExpr [i].Compile (compiler); + foreach (CaseClause cc in Cases) + cc.Expr = cc.Expr.Compile (compiler); + DefaultReturn = DefaultReturn.Compile (compiler); + return this; + } + + // FIXME: it can be optimized by checking all case clauses. + public override SequenceType StaticType { + get { return SequenceType.AnyType; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + // FIXME: should move to iterator? + XPathSequence cond = new ExprSequenceIterator (iter, SwitchExpr); + XPathSequence ret = null; + + foreach (CaseClause ccc in Cases) { + if (ccc.Type.Matches (cond)) { + if (ccc.VarName != XmlQualifiedName.Empty) + iter.Context.PushVariable (ccc.VarName, cond); + ret = ccc.Expr.Evaluate (iter); + // FIXME: The design should make sure that in-scope variables are held on actual iteration. + if (ccc.VarName != XmlQualifiedName.Empty) + iter.Context.PopVariable (); + return ret; + } + } + + if (DefaultVarName != XmlQualifiedName.Empty) + iter.Context.PushVariable (DefaultVarName, cond); + ret = DefaultReturn.Evaluate (iter); + if (DefaultVarName != XmlQualifiedName.Empty) + iter.Context.PopVariable (); + return ret; + } +#endregion + } + + internal class CaseClauseList : CollectionBase + { + public void Insert (int pos, CaseClause cc) + { + List.Insert (pos, cc); + } + + public void Add (CaseClause cc) + { + List.Add (cc); + } + + public CaseClause this [int i] { + get { return (CaseClause) List [i]; } + } + } + + internal class CaseClause + { + public CaseClause (SequenceType type, ExprSingle expr, XmlQualifiedName varName) + { + this.type = type; + this.expr = expr; + this.varName = varName; + } + + SequenceType type; + ExprSingle expr; + XmlQualifiedName varName; + + public SequenceType Type { + get { return type; } + } + + public ExprSingle Expr { + get { return expr; } + set { expr = value; } + } + + public XmlQualifiedName VarName { + get { return varName; } + set { varName = value; } + } + } + + // IfExpr + + internal class IfExpr : ExprSingle + { + public IfExpr (ExprSequence condition, ExprSingle trueExpr, ExprSingle falseExpr) + { + this.condition = new ParenthesizedExpr (condition); + this.trueExpr = trueExpr; + this.falseExpr = falseExpr; + } + + ExprSingle condition; + ExprSingle trueExpr; + ExprSingle falseExpr; + + public ExprSingle Condition { + get { return condition; } + set { condition = value; } + } + + public ExprSingle TrueExpr { + get { return trueExpr; } + set { trueExpr = value; } + } + + public ExprSingle FalseExpr { + get { return falseExpr; } + set { falseExpr = value; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + condition.CheckReference (compiler); + trueExpr.CheckReference (compiler); + falseExpr.CheckReference (compiler); + } + +#region CompileAndEvaluate + SequenceType computedReturnType; + + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + condition = condition.Compile (compiler); + // FIXME: check if condition is constant, and returns trueExpr or falseExpr + TrueExpr = TrueExpr.Compile (compiler); + FalseExpr = FalseExpr.Compile (compiler); + return this; + } + + public override SequenceType StaticType { + get { + if (Context == null) + return SequenceType.AnyType; + if (computedReturnType == null) + computedReturnType = SequenceType.ComputeCommonBase (TrueExpr.StaticType, FalseExpr.StaticType); + return computedReturnType; + } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + if (condition.EvaluateAsBoolean (iter)) + return TrueExpr.Evaluate (iter); + return FalseExpr.Evaluate (iter); + } +#endregion + + } + + // logical expr + + internal abstract class BinaryOperationExpr : ExprSingle + { + protected BinaryOperationExpr (ExprSingle left, ExprSingle right) + { + this.left = left; + this.right = right; + } + + ExprSingle left, right; + + public ExprSingle Left { + get { return left; } + set { left = value; } + } + + public ExprSingle Right{ + get { return right; } + set { right = value; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + left.CheckReference (compiler); + right.CheckReference (compiler); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + Left = Left.Compile (compiler); + Right = Right.Compile (compiler); + return this; + } +#endregion + + } + + internal class OrExpr : BinaryOperationExpr + { + public OrExpr (ExprSingle left, ExprSingle right) + : base (left, right) + { + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + base.CompileCore (compiler); + // FIXME: check constant value and return true or false + return this; + } + + public override SequenceType StaticType { + get { return SequenceType.Boolean; } + } + + public override bool EvaluateAsBoolean (XPathSequence iter) + { + return Left.EvaluateAsBoolean (iter) || Right.EvaluateAsBoolean (iter); + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return new SingleItemIterator (EvaluateAsBoolean (iter) ?AtomicTrue : AtomicFalse, iter.Context); + } + + /* + - compiler - + return leftExprBool (context) || rightExprBool (context); + */ +#endregion + } + + internal class AndExpr : BinaryOperationExpr + { + public AndExpr (ExprSingle left, ExprSingle right) + : base (left, right) + { + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + base.CompileCore (compiler); + // FIXME: check constant value and return true or false + return this; + } + + public override SequenceType StaticType { + get { return SequenceType.Boolean; } + } + + public override bool EvaluateAsBoolean (XPathSequence iter) + { + return Left.EvaluateAsBoolean (iter) && Right.EvaluateAsBoolean (iter); + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return new SingleItemIterator (EvaluateAsBoolean (iter) ? AtomicTrue : AtomicFalse, iter.Context); + } + + /* + - compiler - + return leftExprBool (context) && rightExprBool (context); + */ +#endregion + } + + // TypeOperation expr + + internal abstract class TypeOperationExpr : ExprSingle + { + protected TypeOperationExpr (ExprSingle expr, SequenceType type) + { + this.expr = expr; + this.type = type; + } + + ExprSingle expr; + SequenceType type; + + public ExprSingle Expr { + get { return expr; } + set { expr = value; } + } + + public SequenceType TargetType { + get { return type; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + expr.CheckReference (compiler); + compiler.CheckSchemaType (type); + } + } + + internal abstract class AtomicTypeOperationExpr : ExprSingle + { + protected AtomicTypeOperationExpr (ExprSingle expr, XmlTypeCode type, bool optional) + { + this.expr = expr; + this.targetType = SequenceType.Create (type, optional ? Occurence.Optional : Occurence.One); + } + + ExprSingle expr; + SequenceType targetType; + + internal ExprSingle Expr { + get { return expr; } + set { expr = value; } + } + +/* + public XmlTypeCode TypeCode { + get { return typeCode; } + } + + public bool Optional { + get { return optional; } + } +*/ + internal SequenceType TargetType { + get { return targetType; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + expr.CheckReference (compiler); + } + } + + internal class InstanceOfExpr : TypeOperationExpr + { + public InstanceOfExpr (ExprSingle expr, SequenceType type) + : base (expr, type) + { + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + Expr = Expr.Compile (compiler); + // FIXME: check return type and if it never matches then return false + return this; + } + + public override SequenceType StaticType { + get { return SequenceType.Boolean; } + } + + public override bool EvaluateAsBoolean (XPathSequence iter) + { + bool occured = false; + bool onlyOnce = (TargetType.Occurence == Occurence.One || TargetType.Occurence == Occurence.Optional); + bool required = (TargetType.Occurence == Occurence.One || TargetType.Occurence == Occurence.OneOrMore); + foreach (XPathItem item in iter) { + if (occured && onlyOnce) + return false; + if (!TargetType.IsInstance (item)) + return false; + } + return occured || !required; + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return new SingleItemIterator (EvaluateAsBoolean (iter) ? AtomicTrue : AtomicFalse, iter.Context); + } +#endregion + } + + internal class TreatExpr : TypeOperationExpr + { + public TreatExpr (ExprSingle expr, SequenceType type) + : base (expr, type) + { + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + Expr = Expr.Compile (compiler); + // FIXME: check return type and if it never matches then return false + return this; + } + + public override SequenceType StaticType { + get { return SequenceType.AnyType; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + if (TargetType.CanConvert (iter)) + return iter; + else + throw new XmlQueryException (String.Format ("Cannot treat as {1}", TargetType)); + } +#endregion + } + + internal class CastableExpr : AtomicTypeOperationExpr + { + public CastableExpr (ExprSingle expr, XmlTypeCode atomicType, bool optional) + : base (expr, atomicType, optional) + { + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + Expr = Expr.Compile (compiler); + // FIXME: check return type and if it never matches then return boolean + return this; + } + + public override SequenceType StaticType { + get { return SequenceType.Boolean; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return new SingleItemIterator (new XPathAtomicValue (EvaluateAsBoolean (iter), InternalPool.XsBoolean), iter.Context); + } + + public override bool EvaluateAsBoolean (XPathSequence iter) + { + bool occured = false; + bool onlyOnce = (TargetType.Occurence == Occurence.One || TargetType.Occurence == Occurence.Optional); + bool required = (TargetType.Occurence == Occurence.One || TargetType.Occurence == Occurence.OneOrMore); + foreach (XPathItem item in iter) { + if (occured && onlyOnce) + return false; + if (!TargetType.CanConvert (item)) + return false; + } + return occured || !required; + } +#endregion + } + + internal class CastExpr : AtomicTypeOperationExpr + { + public CastExpr (ExprSingle expr, XmlTypeCode atomicType, bool optional) + : base (expr, atomicType, optional) + { + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + Expr = Expr.Compile (compiler); + // FIXME: check return type and if it never matches then return boolean + return this; + } + + public override SequenceType StaticType { + get { return TargetType; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + if (TargetType.CanConvert (iter)) + return new ConvertingIterator (iter, TargetType); + else + throw new XmlQueryException (String.Format ("Cannot cast as {1}", TargetType)); + } +#endregion + } + + // ComparisonExpr + + internal class ComparisonExpr : BinaryOperationExpr + { + public ComparisonExpr (ExprSingle left, ExprSingle right, ComparisonOperator oper) + : base (left, right) + { + this.oper = oper; + } + + ComparisonOperator oper; + + public ComparisonOperator Operation { + get { return oper; } + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + Left = Left.Compile (compiler); + Right = Right.Compile (compiler); + // FIXME: check return type and if it never matches then return boolean + return this; + } + + public override SequenceType StaticType { + get { return SequenceType.Boolean; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + bool isEmpty; + bool result = EvaluateAsBoolean (iter, out isEmpty); + if (isEmpty) + return new XPathEmptySequence (iter.Context); + return new SingleItemIterator (result ? AtomicTrue : AtomicFalse, iter.Context); + } + + public override bool EvaluateAsBoolean (XPathSequence iter) + { + bool isEmpty; + return EvaluateAsBoolean (iter, out isEmpty); + } + + private bool EvaluateAsBoolean (XPathSequence iter, out bool isEmpty) + { + XPathSequence lseq, rseq; + isEmpty = false; + + switch (Operation) { + // FIXME: it is curious but currently gmcs requires full typename. + case Mono.Xml.XPath2.ComparisonOperator.ValueEQ: + case Mono.Xml.XPath2.ComparisonOperator.ValueNE: + case Mono.Xml.XPath2.ComparisonOperator.ValueLT: + case Mono.Xml.XPath2.ComparisonOperator.ValueLE: + case Mono.Xml.XPath2.ComparisonOperator.ValueGT: + case Mono.Xml.XPath2.ComparisonOperator.ValueGE: + XPathItem itemVL = ExamineOneItem (Left.Evaluate (iter)); + XPathItem itemVR = ExamineOneItem (Right.Evaluate (iter)); + if (itemVL == null || itemVR == null) { + isEmpty = true; + return false; + } + return CompareAtomic (itemVL, itemVR); + + case Mono.Xml.XPath2.ComparisonOperator.GeneralEQ: + case Mono.Xml.XPath2.ComparisonOperator.GeneralNE: + case Mono.Xml.XPath2.ComparisonOperator.GeneralLT: + case Mono.Xml.XPath2.ComparisonOperator.GeneralLE: + case Mono.Xml.XPath2.ComparisonOperator.GeneralGT: + case Mono.Xml.XPath2.ComparisonOperator.GeneralGE: + lseq = Left.Evaluate (iter); + rseq = Right.Evaluate (iter); + foreach (XPathItem itemGL in lseq) { + foreach (XPathItem itemGR in rseq.Clone ()) { + if (CompareAtomic (itemGL, itemGR)) + return true; + } + } + return false; + + case Mono.Xml.XPath2.ComparisonOperator.NodeIs: + case Mono.Xml.XPath2.ComparisonOperator.NodeFWD: + case Mono.Xml.XPath2.ComparisonOperator.NodeBWD: + XPathNavigator lnav = ExamineOneNode (Left.Evaluate (iter)); + XPathNavigator rnav = ExamineOneNode (Right.Evaluate (iter)); + if (lnav == null || rnav == null) { + isEmpty = true; + return false; + } + switch (Operation) { + case Mono.Xml.XPath2.ComparisonOperator.NodeIs: + return lnav.IsSamePosition (rnav); + case Mono.Xml.XPath2.ComparisonOperator.NodeFWD: + return lnav.ComparePosition (rnav) == XmlNodeOrder.Before; + case Mono.Xml.XPath2.ComparisonOperator.NodeBWD: + return lnav.ComparePosition (rnav) == XmlNodeOrder.After; + } + break; + } + throw new SystemException ("XQuery internal error: should not happen."); + } + + // returns null if sequence was empty + private XPathItem ExamineOneItem (XPathSequence seq) + { + if (!seq.MoveNext ()) + return null; + XPathItem item = seq.Current; + if (seq.MoveNext ()) + throw new XmlQueryException ("Operand of value comparison expression must be evaluated as a sequence that contains exactly one item."); + return item; + } + + // returns null if sequence was empty + private XPathNavigator ExamineOneNode (XPathSequence seq) + { + if (!seq.MoveNext ()) + return null; + XPathNavigator nav = seq.Current as XPathNavigator; + if (nav == null || seq.MoveNext ()) + throw new XmlQueryException ("Operand of node comparison expression must be evaluated as a sequence that contains exactly one node."); + return nav; + } + + private bool CompareAtomic (XPathItem itemL, XPathItem itemR) + { + XmlSchemaSimpleType ua = InternalPool.XdtUntypedAtomic; + XmlSchemaSimpleType str = InternalPool.XsString; + // FIXME: XPathNavigator might be complex content. + bool uaL = itemL.XmlType == null || itemL.XmlType == ua; + bool uaR = itemR.XmlType == null || itemR.XmlType == ua; + bool bothUA = uaL && uaR; + XPathAtomicValue avL = + (uaL) ? + bothUA ? new XPathAtomicValue (itemL.Value, str) : + new XPathAtomicValue (itemL.Value, itemR.XmlType) : + Atomize (itemL); + XPathAtomicValue avR = + uaR ? + bothUA ? new XPathAtomicValue (itemR.Value, str) : + new XPathAtomicValue (itemR.Value, itemL.XmlType) : + Atomize (itemR); + + switch (Operation) { + // FIXME: it is curious but currently gmcs requires full typename. + case Mono.Xml.XPath2.ComparisonOperator.ValueEQ: + case Mono.Xml.XPath2.ComparisonOperator.GeneralEQ: + return XQueryComparisonOperator.ValueEQ (avL, avR); + case Mono.Xml.XPath2.ComparisonOperator.ValueNE: + case Mono.Xml.XPath2.ComparisonOperator.GeneralNE: + return XQueryComparisonOperator.ValueNE (avL, avR); + case Mono.Xml.XPath2.ComparisonOperator.ValueLT: + case Mono.Xml.XPath2.ComparisonOperator.GeneralLT: + return XQueryComparisonOperator.ValueLT (avL, avR); + case Mono.Xml.XPath2.ComparisonOperator.ValueLE: + case Mono.Xml.XPath2.ComparisonOperator.GeneralLE: + return XQueryComparisonOperator.ValueLE (avL, avR); + case Mono.Xml.XPath2.ComparisonOperator.ValueGT: + case Mono.Xml.XPath2.ComparisonOperator.GeneralGT: + return XQueryComparisonOperator.ValueGT (avL, avR); + case Mono.Xml.XPath2.ComparisonOperator.ValueGE: + case Mono.Xml.XPath2.ComparisonOperator.GeneralGE: + return XQueryComparisonOperator.ValueGE (avL, avR); + } + return false; // should not happen + } +#endregion + } + + public enum ComparisonOperator { + ValueEQ, + ValueNE, + ValueLT, + ValueLE, + ValueGT, + ValueGE, + GeneralEQ, + GeneralNE, + GeneralLT, + GeneralLE, + GeneralGT, + GeneralGE, + NodeIs, + NodeFWD, + NodeBWD + } + + // Range + + internal class RangeExpr : BinaryOperationExpr + { + public RangeExpr (ExprSingle left, ExprSingle right) + : base (left, right) + { + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + Left = Left.Compile (compiler); + Right = Right.Compile (compiler); + return this; + } + + public override SequenceType StaticType { + get { return SequenceType.IntegerList; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + int start = Left.EvaluateAsInt (iter); + int end = Right.EvaluateAsInt (iter); + return new IntegerRangeIterator (iter.Context, start, end); + } + + public override void Serialize (XPathSequence iter) + { + int start = Left.EvaluateAsInt (iter); + int end = Right.EvaluateAsInt (iter); + for (int i = start; i <= end; i++) { + iter.Context.Writer.WriteValue (i); + if (i < end) + iter.Context.Writer.WriteWhitespace (" "); + } + } +#endregion + } + + // arithmetic operation expr + + public enum ArithmeticOperator { + Add, + Sub, + Mul, + Div, + IDiv, + IMod + } + + internal class ArithmeticOperationExpr : BinaryOperationExpr + { + public ArithmeticOperationExpr (ExprSingle left, ExprSingle right, ArithmeticOperator oper) + : base (left, right) + { + this.oper = oper; + } + + ArithmeticOperator oper; + + public ArithmeticOperator Operation { + get { return oper; } + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + Left = Left.Compile (compiler); + Right = Right.Compile (compiler); + return this; + } + + // FIXME: It can be optimized by comparing l/r value types. + public override SequenceType StaticType { + get { return SequenceType.AnyType; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + XPathSequence lseq = Left.Evaluate (iter); + if (!lseq.MoveNext ()) + return new XPathEmptySequence (iter.Context); + XPathSequence rseq = Right.Evaluate (iter); + if (!rseq.MoveNext ()) + return new XPathEmptySequence (iter.Context); + XPathAtomicValue lvalue = Atomize (lseq.Current); + XPathAtomicValue rvalue = Atomize (rseq.Current); + if (lseq.MoveNext ()) + throw new XmlQueryException ("XP0006: Left operand resulted in an sequence that contains more than one item."); + if (rseq.MoveNext ()) + throw new XmlQueryException ("XP0006: Left operand resulted in an sequence that contains more than one item."); + + // FIXME: handle "untypedAtomic to xs:double" casting + + return new SingleItemIterator (Compute (lvalue, rvalue), iter.Context); + } + + private XPathAtomicValue Compute (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + switch (Operation) { + case ArithmeticOperator.Add: + return XQueryArithmeticOperator.Add (lvalue, rvalue); + case ArithmeticOperator.Sub: + return XQueryArithmeticOperator.Subtract (lvalue, rvalue); + case ArithmeticOperator.Mul: + return XQueryArithmeticOperator.Multiply (lvalue, rvalue); + case ArithmeticOperator.Div: + return XQueryArithmeticOperator.Divide (lvalue, rvalue); + case ArithmeticOperator.IDiv: + return XQueryArithmeticOperator.IntDivide (lvalue, rvalue); + case ArithmeticOperator.IMod: + return XQueryArithmeticOperator.Remainder (lvalue, rvalue); + default: + throw new SystemException ("XQuery internal error: should not happen."); + } + } +#endregion + } + + internal class MinusExpr : ExprSingle + { + public MinusExpr (ExprSingle expr) + { + this.expr = expr; + } + + ExprSingle expr; + + public ExprSingle Expr { + get { return expr; } + set { expr = value; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + expr.CheckReference (compiler); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + return new ArithmeticOperationExpr (new DecimalLiteralExpr (-1), Expr, ArithmeticOperator.Mul).Compile (compiler); + } + + public override SequenceType StaticType { + get { return Expr.StaticType; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + throw new SystemException ("XQuery internal error: should not happen."); + } +#endregion + } + + // aggregation expr + + public enum AggregationType { + Union, + Intersect, + Except + } + + internal class GroupExpr : BinaryOperationExpr + { + public GroupExpr (ExprSingle left, ExprSingle right, AggregationType aggrType) + : base (left, right) + { + this.aggrType = aggrType; + } + + AggregationType aggrType; + + public AggregationType AggregationType { + get { return aggrType; } + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + Left = Left.Compile (compiler); + Right = Right.Compile (compiler); + return this; + } + + // FIXME: It can be optimized by comparing l/r value types. + public override SequenceType StaticType { + get { return SequenceType.AnyType; } + } + + // only applicable against node-sets + public override XPathSequence Evaluate (XPathSequence iter) + { + return new GroupIterator (iter, this); + } +#endregion + } + + // validate expr + + internal class ValidateExpr : ExprSingle + { + XmlSchemaContentProcessing schemaMode; + ExprSequence expr; + + public ValidateExpr (XmlSchemaContentProcessing schemaMode, ExprSequence expr) + { + this.schemaMode = schemaMode; + this.expr = expr; + } + + public ExprSequence Expr { + get { return expr; } + } + + public XmlSchemaContentProcessing SchemaMode { + get { return schemaMode; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + expr.CheckReference (compiler); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + for (int i = 0; i < expr.Count; i++) + expr [i] = expr [i].Compile (compiler); + return this; + } + + public override SequenceType StaticType { + get { return SequenceType.AnyType; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + // TBD (see 3.13). + throw new NotImplementedException (); + } +#endregion + } + + // Path expr + + internal abstract class PathExpr : ExprSingle + { + } + + // '/' + internal class PathRootExpr : PathExpr + { + public PathRootExpr () + { + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + return this; + } + + public override SequenceType StaticType { + get { return SequenceType.Document; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + XPathNavigator nav = iter.Context.CurrentItem as XPathNavigator; + if (nav == null) + throw new XmlQueryException ("Context item is not a node when evaluating expression '/'."); + nav = nav.Clone (); + nav.MoveToRoot (); + return new SingleItemIterator (nav, iter.Context); + } +#endregion + } + + internal abstract class PathStepExpr : PathExpr + { + ExprSingle first; + ExprSingle next; + + public PathStepExpr (ExprSingle first, ExprSingle next) + { + this.first = first; + this.next = next; + } + + public ExprSingle First { + get { return first; } + set { first = value; } + } + + public ExprSingle Next { + get { return next; } + set { next = value; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + first.CheckReference (compiler); + next.CheckReference (compiler); + } + + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + first = first.Compile (compiler); + next = next.Compile (compiler); + return this; + } + + } + + // 'foo/bar' + internal class PathSlashExpr : PathStepExpr + { + public PathSlashExpr (ExprSingle first, ExprSingle next) + : base (first, next) + { + } + +#region CompileAndEvaluate + // FIXME: It can be optimized by comparing l/r value types. + public override SequenceType StaticType { + get { return SequenceType.Node; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return new PathStepIterator (First.Evaluate (iter), this); + } +#endregion + } + + // 'foo//bar' + internal class PathSlash2Expr : PathStepExpr + { + public PathSlash2Expr (ExprSingle first, ExprSingle next) + : base (first, next) + { + } + +#region CompileAndEvaluate + // FIXME: It can be optimized by comparing l/r value types. + public override SequenceType StaticType { + get { return SequenceType.Node; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + XPathSequence seq = First.Evaluate (iter); + if (!seq.MoveNext ()) + return new XPathEmptySequence (iter.Context); + return new PathStepIterator ( + new DescendantOrSelfIterator (seq.Current as XPathNavigator, seq.Context), this); + } +#endregion + } + + internal class AxisStepExpr : PathExpr + { + public AxisStepExpr (XPathAxis axis, XPath2NodeTest test) + { + this.axis = axis; + if (test == null) + nameTest = XmlQualifiedName.Empty; + else { + if (test.NameTest != null) + this.nameTest = test.NameTest; + else + this.kindTest = test.KindTest; + } + } + + XPathAxis axis; + XmlQualifiedName nameTest; + KindTest kindTest; + + public XPathAxis Axis { + get { return axis; } + } + + public XmlQualifiedName NameTest { + get { return nameTest; } + set { nameTest = value; } + } + + public KindTest KindTest { + get { return kindTest; } + set { kindTest = value; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + if (KindTest != null) + KindTest.CheckReference (compiler); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + if (KindTest != null) + KindTest.Compile (compiler); + return this; + } + + public override SequenceType StaticType { + get { + switch (Axis.AxisType) { + case XPathAxisType.Attribute: + return SequenceType.Attribute; + case XPathAxisType.Namespace: + return SequenceType.Namespace; + } + // FIXME: we can more filtering by KindTest + return SequenceType.Node; + } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + XQueryContext ctx = iter.Context; + + if (iter.Position == 0) { + iter = iter.Clone (); + if (!iter.MoveNext ()) + return new XPathEmptySequence (iter.Context); + } + + XPathNavigator nav = iter.Current as XPathNavigator; + if (nav == null) + throw new XmlQueryException ("Node set is expected."); + + NodeIterator argIter = null; + + switch (Axis.AxisType) { + case XPathAxisType.Child: + argIter = new ChildIterator (nav, ctx); break; + case XPathAxisType.Descendant: + argIter = new DescendantIterator (nav, ctx); break; + case XPathAxisType.Attribute: + argIter = new AttributeIterator (nav, ctx); break; + case XPathAxisType.Self: + argIter = new SelfIterator (nav, ctx); break; + case XPathAxisType.DescendantOrSelf: + argIter = new DescendantOrSelfIterator (nav, ctx); break; + case XPathAxisType.FollowingSibling: + argIter = new FollowingSiblingIterator (nav, ctx); break; + case XPathAxisType.Following: + argIter = new FollowingIterator (nav, ctx); break; + case XPathAxisType.Parent: + argIter = new ParentIterator (nav, ctx); break; + case XPathAxisType.Ancestor: + argIter = new AncestorIterator (nav, ctx); break; + case XPathAxisType.PrecedingSibling: + argIter = new PrecedingSiblingIterator (nav, ctx); break; + case XPathAxisType.Preceding: + argIter = new PrecedingIterator (nav, ctx); break; + case XPathAxisType.AncestorOrSelf: + argIter = new AncestorOrSelfIterator (nav, ctx); break; + case XPathAxisType.Namespace: // only applicable under XPath 2.0: not XQuery 1.0 + argIter = new NamespaceIterator (nav, ctx); break; + } + return new AxisIterator (argIter, this); + } + + internal bool Matches (XPathNavigator nav) + { + if (nameTest != null) + return nameTest == XmlQualifiedName.Empty || + ((nameTest.Name == nav.LocalName || nameTest.Name == "*") && + (nameTest.Namespace == nav.NamespaceURI || nameTest.Namespace == "*")); + else + return kindTest.Matches (nav); + } +#endregion + } + + internal class FilterStepExpr : PathExpr + { + public FilterStepExpr (ExprSingle expr, ExprSequence predicate) + { + this.expr = expr; + this.predicate = predicate; + } + + ExprSingle expr; + ExprSequence predicate; + + public ExprSingle Expr { + get { return expr; } + set { expr = value; } + } + + public ExprSequence Predicate { + get { return predicate; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + expr.CheckReference (compiler); + predicate.CheckReference (compiler); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + Expr = Expr.Compile (compiler); + for (int i = 0; i < predicate.Count; i++) + predicate [i] = predicate [i].Compile (compiler); + return this; + } + + public override SequenceType StaticType { + get { return Expr.StaticType; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return new FilteredIterator (iter, this); + } +#endregion + } + +/* + // predicates == exprsequence list == list of list of exprsingle + internal class PredicateList : CollectionBase + { + public void Add (ExprSequence expr) + { + List.Add (expr); + } + + public void Insert (int pos, ExprSequence expr) + { + List.Insert (pos, expr); + } + + public ExprSequence this [int i] { + get { return (ExprSequence) List [i]; } + } + } +*/ + + internal class XPath2NodeTest + { + public XPath2NodeTest (XmlQualifiedName nameTest) + { + this.NameTest = nameTest; + } + + public XPath2NodeTest (KindTest kindTest) + { + this.KindTest = kindTest; + } + + public XmlQualifiedName NameTest; + + public KindTest KindTest; + } + + internal class EnclosedExpr : ExprSingle + { + ExprSequence expr; + + public EnclosedExpr (ExprSequence expr) + { + this.expr = expr; + } + + public ExprSequence Expr { + get { return expr; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + expr.CheckReference (compiler); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + if (Expr.Count == 1) + return Expr [0].Compile (compiler); + for (int i = 0; i < Expr.Count; i++) + Expr [i] = Expr [i].Compile (compiler); + return this; + } + + // FIXME: can be optimized by checking all items in Expr + public override SequenceType StaticType { + get { return SequenceType.AnyType; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return new ExprSequenceIterator (iter, Expr); + } +#endregion + } + + // PrimaryExpr + + internal abstract class PrimaryExpr : ExprSingle + { + internal override void CheckReference (XQueryASTCompiler compiler) + { + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + return this; + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return new SingleItemIterator (EvaluateAsAtomic (iter), iter.Context); + } +#endregion + } + + internal class StringLiteralExpr : PrimaryExpr + { + string literal; + + public StringLiteralExpr (string literal) + { + this.literal = literal; + } + + public string Literal { + get { return literal; } + } + +#region CompileAndEvaluate + XmlSchemaSimpleType stringType = XmlSchemaType.GetBuiltInSimpleType (new XmlQualifiedName ("string", XmlSchema.Namespace)); + + public override SequenceType StaticType { + get { return SequenceType.AtomicString; } + } + + public override string EvaluateAsString (XPathSequence iter) + { + return Literal; + } + + public override XPathAtomicValue EvaluateAsAtomic (XPathSequence iter) + { + return new XPathAtomicValue (Literal, stringType); + } +#endregion + } + + internal class DecimalLiteralExpr : PrimaryExpr + { + decimal value; + + public DecimalLiteralExpr (decimal value) + { + this.value = value; + } + + public decimal Value { + get { return value; } + } + +#region CompileAndEvaluate + XmlSchemaSimpleType decimalType = XmlSchemaType.GetBuiltInSimpleType (new XmlQualifiedName ("decimal", XmlSchema.Namespace)); + + public override SequenceType StaticType { + get { return SequenceType.Decimal; } + } + + public override XPathAtomicValue EvaluateAsAtomic (XPathSequence iter) + { + return new XPathAtomicValue (Value, decimalType); + } +#endregion + } + + internal class DoubleLiteralExpr : PrimaryExpr + { + double value; + + public DoubleLiteralExpr (double value) + { + this.value = value; + } + + public double Value { + get { return value; } + } + +#region CompileAndEvaluate + XmlSchemaSimpleType doubleType = XmlSchemaType.GetBuiltInSimpleType (new XmlQualifiedName ("double", XmlSchema.Namespace)); + + public override SequenceType StaticType { + get { return SequenceType.Double; } + } + + public override XPathAtomicValue EvaluateAsAtomic (XPathSequence iter) + { + return new XPathAtomicValue (Value, doubleType); + } +#endregion + } + + internal class VariableReferenceExpr : PrimaryExpr + { + XmlQualifiedName varName; + + public VariableReferenceExpr (XmlQualifiedName varName) + { + this.varName = varName; + } + + public XmlQualifiedName VariableName { + get { return varName; } + } + + // FIXME: variable name must be stacked in any area + // whereever variables are defined. + internal override void CheckReference (XQueryASTCompiler compiler) + { + compiler.CheckVariableName (varName); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + // FIXME: try to resolve static context variable and return the actual value expression + return this; + } + + public override SequenceType StaticType { + get { return SequenceType.AnyType; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + XPathSequence variable = iter.Context.ResolveVariable (VariableName); + // FIXME: if Evaluate() accepts XPathSequence, then XPathSequence must be public class (to make IXPath2Variable public). + return variable; + } +#endregion + } + + internal class ParenthesizedExpr : PrimaryExpr + { + ExprSequence expr; + + public ParenthesizedExpr (ExprSequence expr) + { + if (expr == null) + expr = new ExprSequence (); + this.expr = expr; + } + + ExprSequence Expr { + get { return expr; } + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + if (Expr.Count == 1) + return Expr [0].Compile (compiler); + for (int i = 0; i < Expr.Count; i++) + Expr [i] = Expr [i].Compile (compiler); + return this; + } + + // FIXME: can be optimized by checking all items in Expr + public override SequenceType StaticType { + get { return SequenceType.AnyType; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + switch (Expr.Count) { + case 0: + return new XPathEmptySequence (iter.Context); + case 1: + return Expr [0].Evaluate (iter); + default: + return new ExprSequenceIterator (iter, Expr); + } + } +#endregion + } + + // "." + internal class ContextItemExpr : PrimaryExpr + { + public ContextItemExpr () + { + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + return this; + } + + public override SequenceType StaticType { + get { return SequenceType.AnyType; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return new SingleItemIterator (iter.Context.CurrentItem, iter.Context); + } +#endregion + } + + internal abstract class FunctionCallExprBase : PrimaryExpr + { + XmlQualifiedName name; + ExprSequence args; + + public FunctionCallExprBase (XmlQualifiedName name, ExprSequence args) + { + if (args == null) + throw new ArgumentNullException (String.Format ("Function argument expressions for {0} is null.", name)); + this.name = name; + this.args = args; + } + + public XmlQualifiedName Name { + get { return name; } + } + + public ExprSequence Args { + get { return args; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + compiler.CheckFunctionName (name); + } + +#region CompileAndEvaluate + /* + internal static DefaultFunctionCall Create ( + XmlQualifiedName name, + ExprSingle [] args, + XQueryStaticContext ctx) + { + switch (name.Namespace) { + case XQueryFunction.Namespace: + switch (name.Name) { + case "node-name": + return new FnNodeNameCall (ctx, args); + case "nilled": + return new FnNilledCall (ctx, args); + case "string": + return new FnStringCall (ctx, args); + case "data": + return new FnDataCall (ctx, args); + case "base-uri": + return new FnBaseUriCall (ctx, args); + case "document-uri": + return new FnDocumentUriCall (ctx, args); + case "error": + return new FnErrorCall (ctx, args); + case "trace": + return new FnTraceCall (ctx, args); + case "abs": + return new FnAbsCall (ctx, args); + case "ceiling": + return new FnCeilingCall (ctx, args); + case "floor": + return new FnFloorCall (ctx, args); + case "round": + return new FnRoundCall (ctx, args); + case "round-half-to-even": + return new FnRoundHalfToEvenCall (ctx, args); + case "codepoints-to-string": + return new FnCodepointsToStringCall (ctx, args); + case "string-to-codepoints": + return new FnStringCallToCodepointsCall (ctx, args); + } + goto default; + case InternalPool.XdtNamespace: + case XmlSchema.Namespace: + XmlSchemaType type = XmlSchemaType.GetBuiltInSimpleType (name); + if (type != null) + return new AtomicConstructorCall (ctx, SequenceType.Create (type, Occurence.One), args); + type = XmlSchemaType.GetBuiltInComplexType (name); + if (type == null) + goto default; + return null; + default: + XQueryFunction func = ctx.CompileContext.InEffectFunctions [name]; + if (func != null) + return new CustomFunctionCallExpression (ctx, args, func); + return null; + } + } + */ + + internal void CheckArguments (XQueryASTCompiler compiler) + { + if (args.Count < MinArgs || args.Count > MaxArgs) + // FIXME: add more info + throw new XmlQueryCompileException (String.Format ("{0} is invalid for the number of {1} function argument. MinArgs = {2}, MaxArgs = {3}.", args.Count, name, MinArgs, MaxArgs)); + } + + public abstract int MinArgs { get; } + public abstract int MaxArgs { get; } +#endregion + } + + internal class FunctionCallExpr : FunctionCallExprBase + { + public FunctionCallExpr (XmlQualifiedName name, ExprSequence args) + : base (name, args) + { + } + + XQueryFunction function; + + public XQueryFunction Function { + get { return function; } + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + // resolve function + function = compiler.ResolveFunction (Name); + CheckArguments (compiler); + for (int i = 0; i < Args.Count; i++) + Args [i] = Args [i].Compile (compiler); + return this; + } + + public override int MinArgs { + get { return function.MinArgs; } + } + + public override int MaxArgs { + get { return function.MaxArgs; } + } + + public override SequenceType StaticType { + get { return function.ReturnType; } + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return Function.Evaluate (iter, Args); + } + + // FIXME: add all overrides that delegates to XQueryFunction +#endregion + } + +/* +#region CompileAndEvaluate + + // It is instantiated per function call expression. + // (e.g. the example below contains 4 FunctionCallExpression instances: + // "replace(node-name (node-before(/*)), 'foo', node-name($var))" + internal class CustomFunctionCallExpr : FunctionCallExprBase + { + public CustomFunctionCallExpr (ExprSequence args, XQueryFunction function) + : base (function.Name, args) + { + this.function = function; + } + + XQueryFunction function; + + public XQueryFunction Function { + get { return function; } + } + + public override int MinArgs { + get { return function.MinArgs; } + } + + public override int MaxArgs { + get { return function.MaxArgs; } + } + + public override SequenceType StaticType { + get { return function.ReturnType; } + } + + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + CheckArguments (compiler); + for (int i = 0; i < Args.Count; i++) + Args [i] = Args [i].Compile (compiler); + return this; + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return Function.Evaluate (iter, Args); + } + + // FIXME: add all overrides that delegates to XQueryFunction + } +#endregion +*/ + + // Ordered / Unordered + internal class OrderSpecifiedExpr : ExprSingle + { + bool ordered; + ExprSequence expr; + + public OrderSpecifiedExpr (ExprSequence expr, bool ordered) + { + this.ordered = ordered; + this.expr = expr; + } + + public ExprSequence Expr { + get { return expr; } + } + + public bool Ordered { + get { return ordered; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + expr.CheckReference (compiler); + } + +#region CompileAndEvaluate + public override SequenceType StaticType { + // FIXME: could be optimized by checking all the expressions + get { return SequenceType.AnyType; } + } + + public override bool RequireSorting { + get { return Ordered; } + } + + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + for (int i = 0; i < Expr.Count; i++) + Expr [i] = Expr [i].Compile (compiler); + return this; + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + throw new NotImplementedException (); + } +#endregion + } +} + +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XPathSequence.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XPathSequence.cs new file mode 100755 index 00000000000..602e09d6aa1 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XPathSequence.cs @@ -0,0 +1,1779 @@ +// +// XPathSequence.cs - represents XPath sequence iterator +// +// Author: +// Atsushi Enomoto +// +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// + +#if NET_2_0 +using System; +using System.Collections; +using System.Globalization; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Query; +using System.Xml.XPath; + +namespace Mono.Xml.XPath2 +{ + public abstract class XPathSequence : IEnumerable, ICloneable + { + XQueryContext ctx; + int countCache = -1; + int position = 0; + + internal XPathSequence (XQueryContext ctx) + { + this.ctx = ctx; + } + + internal XPathSequence (XPathSequence original) + { + ctx = original.ctx; + position = original.position; + } + + internal XQueryContext Context { +// get { return ctx; } + get { return ctx.ContextManager.CurrentContext; } + } + + public virtual int Count { + get { + if (countCache >= 0) + return countCache; + XPathSequence clone = Clone (); + while (clone.MoveNext ()) + ; + countCache = clone.Position; + return countCache; + } + } + + public XPathItem Current { + get { + if (Position == 0) + throw new InvalidOperationException ("XQuery internal error (should not happen)"); + return CurrentCore; + } + } + + public abstract XPathItem CurrentCore { get; } + + // Returns 0 if not started, otherwise returns XPath positional integer. + public virtual int Position { + get { return position; } + } + + public virtual bool MoveNext () + { + if (!MoveNextCore ()) + return false; + position++; + return true; + } + + protected abstract bool MoveNextCore (); + + public abstract XPathSequence Clone (); + + object ICloneable.Clone () + { + return this.Clone (); + } + + public virtual IEnumerator GetEnumerator () + { + while (MoveNext ()) + yield return CurrentCore; + } + + } + + // empty iterator (still required since it contains XQueryContext) + class XPathEmptySequence : XPathSequence + { + internal XPathEmptySequence (XQueryContext ctx) + : base (ctx) + { + } + + public override int Count { + get { return 0; } + } + + protected override bool MoveNextCore () + { + return false; + } + + public override XPathItem CurrentCore { + get { throw new InvalidOperationException ("Should not happen. In XPathEmptySequence.Current."); } + } + + // Don't return clone. It's waste of resource. + public override XPathSequence Clone () + { + return this; + } + } + + // single item iterator + + internal class SingleItemIterator : XPathSequence + { + XPathItem item; + XPathItem current; + + // for XQuery execution start point + internal SingleItemIterator (XPathItem item, XQueryContext ctx) + : base (ctx) + { + this.item = item; + } + + private SingleItemIterator (SingleItemIterator other) + : base (other) + { + this.item = other.item; + this.current = other.current; + } + + public override XPathSequence Clone () + { + return new SingleItemIterator (this); + } + + protected override bool MoveNextCore () + { + if (current == null) { + current = item; + return true; + } + return false; + } + + public override XPathItem CurrentCore { + get { + return current; + } + } + } + + // RangeExpr iterator + + internal class IntegerRangeIterator : XPathSequence + { + static XmlSchemaSimpleType intType = XmlSchemaType.GetBuiltInSimpleType (new XmlQualifiedName ("int", XmlSchema.Namespace)); + + int start; + int end; + int next; + XPathItem current; + + public IntegerRangeIterator (XQueryContext ctx, int start, int end) + : base (ctx) + { + this.start = start; + this.end = end; + } + + private IntegerRangeIterator (IntegerRangeIterator other) + : base (other) + { + this.start = other.start; + this.end = other.end; + this.next = other.next; + this.current = other.current; + } + + public override XPathSequence Clone () + { + return new IntegerRangeIterator (this); + } + + protected override bool MoveNextCore () + { + if (current == null) + next = start; + if (next > end) + return false; + current = new XPathAtomicValue (next++, intType); + return true; + } + + public override XPathItem CurrentCore { + get { + return current; + } + } + } + + // Slash iterator + // + internal class PathStepIterator : XPathSequence + { + XPathSequence left; + XPathSequence right; + PathStepExpr step; + ArrayList nodeStore; + SortedList storedIterators; + bool finished; + XPathSequence nextRight; + + public PathStepIterator (XPathSequence iter, PathStepExpr source) + : base (iter.Context) + { + left = iter; + step = source; + } + + private PathStepIterator (PathStepIterator other) + : base (other) + { + left = other.left.Clone (); + step = other.step; + if (other.right != null) + right = other.right.Clone (); + if (other.nodeStore != null) + nodeStore = (ArrayList) other.nodeStore.Clone (); + if (other.storedIterators != null) + storedIterators = (SortedList) other.storedIterators.Clone (); + if (other.nextRight != null) + nextRight = other.nextRight.Clone (); + } + + public override XPathSequence Clone () + { + return new PathStepIterator (this); + } + + protected override bool MoveNextCore () + { + if (finished) + return false; + if (step.RequireSorting) { + // Mainly '//' ('/descendant-or-self::node()/') + if (nodeStore == null) { + CollectResults (); + if (nodeStore.Count == 0) { + finished = true; + return false; + } else + // Initially it must not go to + // the while loop below + // (.Position -1 is -1). + return true; + } + if (nodeStore.Count == Position) { + finished = true; + return false; + } + while (nodeStore.Count > Position) { + if (((XPathNavigator) nodeStore [Position]).ComparePosition ( + (XPathNavigator) nodeStore [Position - 1]) == XmlNodeOrder.Same) + nodeStore.RemoveAt (Position); + else + break; + } + + return true; + } else { // Sorting not required + if (right == null) { // First time + if (!left.MoveNext ()) + return false; + right = step.Next.Evaluate (left); + storedIterators = new SortedList (XPathSequenceComparer.Instance); + } + + while (true) { + while (!right.MoveNext ()) { + if (storedIterators.Count > 0) { + int last = storedIterators.Count - 1; + XPathSequence tmpIter = (XPathSequence) storedIterators.GetByIndex (last); + storedIterators.RemoveAt (last); + switch (((XPathNavigator) tmpIter.Current).ComparePosition ((XPathNavigator) right.Current)) { + case XmlNodeOrder.Same: + case XmlNodeOrder.Before: + right = tmpIter; + continue; + default: + right = tmpIter; + break; + } + break; + } else if (nextRight != null) { + right = nextRight; + nextRight = null; + break; + } else if (!left.MoveNext ()) { + finished = true; + return false; + } + else + right = step.Next.Evaluate (left); + } + bool loop = true; + while (loop) { + loop = false; + if (nextRight == null) { + bool noMoreNext = false; + while (nextRight == null || !nextRight.MoveNext ()) { + if(left.MoveNext ()) + nextRight = step.Next.Evaluate (left); + else { + noMoreNext = true; + break; + } + } + if (noMoreNext) + nextRight = null; // FIXME: More efficient code. Maybe making noMoreNext class scope would be better. + } + if (nextRight != null) { + switch (((XPathNavigator) right.Current).ComparePosition ((XPathNavigator) nextRight.Current)) { + case XmlNodeOrder.After: + storedIterators.Add (storedIterators.Count, right); + right = nextRight; + nextRight = null; + loop = true; + break; + case XmlNodeOrder.Same: + if (!nextRight.MoveNext ()) + nextRight = null; + + else { + int last = storedIterators.Count; + if (last > 0) { + storedIterators.Add (last, nextRight); + nextRight = (XPathSequence) storedIterators.GetByIndex (last); + storedIterators.RemoveAt (last); + } + } + + loop = true; + break; + } + } + } + return true; + } + } + } + + private void CollectResults () + { + if (nodeStore != null) + return; + nodeStore = new ArrayList (); + while (true) { + while (right == null || !right.MoveNext ()) { + if (!left.MoveNext ()) { + nodeStore.Sort (XPathNavigatorComparer2.Instance); + return; + } + right = step.Next.Evaluate (left); + } + XPathNavigator nav = (XPathNavigator) right.Current; + nodeStore.Add (nav); + } + } + + public override XPathItem CurrentCore { + get { + if (Position <= 0) return null; + if (step.RequireSorting) { + return (XPathNavigator) nodeStore [Position - 1]; + } else { + return right.Current; + } + } + } + + public override int Count { + get { + if (nodeStore == null) + return base.Count; + else + return nodeStore.Count; + } + } + + + internal class XPathSequenceComparer : IComparer + { + public static XPathSequenceComparer Instance = new XPathSequenceComparer (); + private XPathSequenceComparer () + { + } + + public int Compare (object o1, object o2) + { + XPathSequence nav1 = o1 as XPathSequence; + XPathSequence nav2 = o2 as XPathSequence; + if (nav1 == null) + return -1; + if (nav2 == null) + return 1; + switch (((XPathNavigator) nav1.Current).ComparePosition ((XPathNavigator) nav2.Current)) { + case XmlNodeOrder.Same: + return 0; + case XmlNodeOrder.After: + return -1; + default: + return 1; + } + } + } + + internal class XPathNavigatorComparer2 : IComparer + { + public static XPathNavigatorComparer2 Instance = new XPathNavigatorComparer2 (); + private XPathNavigatorComparer2 () + { + } + + public int Compare (object o1, object o2) + { + XPathNavigator nav1 = o1 as XPathNavigator; + XPathNavigator nav2 = o2 as XPathNavigator; + if (nav1 == null) + return -1; + if (nav2 == null) + return 1; + switch (nav1.ComparePosition (nav2)) { + case XmlNodeOrder.Same: + return 0; + case XmlNodeOrder.After: + return 1; + default: + return -1; + } + } + } + } + // + + // Filter step iterator + internal class FilteredIterator : XPathSequence + { + XPathSequence left; + ExprSequence filter; + + public FilteredIterator (XPathSequence iter, FilterStepExpr source) + : base (iter.Context) + { + left = source.Expr.Evaluate (iter); + filter = source.Predicate; + } + + private FilteredIterator (FilteredIterator other) + : base (other) + { + left = other.left.Clone (); + filter = other.filter; + } + + public override XPathSequence Clone () + { + return new FilteredIterator (this); + } + + protected override bool MoveNextCore () + { + // FIXME: as for numeric predicates, it is MUCH faster + // when it skips apparent non-candidates, with possible + // method implementation "XPathSequence.SkipTo (int)". + // When it comes true, iteration won't be done first. + while (left.MoveNext ()) { + bool doesntPass = true; + // Treat as OK if any of filter expr passed. + // FIXME: handle numeric predicate. + foreach (ExprSingle single in filter) { + XPathAtomicValue av = single.EvaluateAsAtomic (left); + if (av == null) + continue; + if (SequenceType.IsNumeric (av.XmlType.TypeCode)) { + // numeric filter + if (av.ValueAsInt32 == left.Position) { + doesntPass = false; + break; + } + } + else if (single.EvaluateAsBoolean (left)) { + doesntPass = false; + break; + } + } + if (doesntPass) + continue; + return true; + } + return false; + } + + public override XPathItem CurrentCore { + get { return left.Current; } + } + } + + // AxisIterator + internal class AxisIterator : XPathSequence + { + NodeIterator iter; + AxisStepExpr source; + + public AxisIterator (NodeIterator iter, AxisStepExpr source) + : base (iter.Context) + { + this.iter = iter; + this.source = source; + } + + private AxisIterator (AxisIterator other) + : base (other) + { + iter = (NodeIterator) other.iter.Clone (); + source = other.source; + } + + public override XPathSequence Clone () + { + return new AxisIterator (this); + } + + protected override bool MoveNextCore () + { + while (iter.MoveNext ()) { + if (source.Matches (iter.Current as XPathNavigator)) + return true; + } + return false; + } + + public override XPathItem CurrentCore { + get { return iter.Current; } + } + } + + internal abstract class NodeIterator : XPathSequence + { + XPathNavigator node; + XPathNavigator current; + bool emptyInput; + + public NodeIterator (XPathNavigator nav, XQueryContext ctx) + : base (ctx) + { + this.node = nav.Clone (); + } + + internal NodeIterator (NodeIterator other, bool cloneFlag) + : base (other) + { + if (other.emptyInput) + emptyInput = true; + else + node = other.node.Clone (); + } + + internal XPathNavigator Node { + get { return node; } + } + + public override bool MoveNext () + { + if (emptyInput) + return false; + if (!base.MoveNext ()) + return false; + current = null; + return true; + } + + public override XPathItem CurrentCore { + get { + if (current == null) + current = node.Clone (); + return current; + } + } + + public virtual bool ReverseAxis { + get { return false; } + } + } + + // + + internal class SelfIterator : NodeIterator + { + public SelfIterator (XPathNavigator nav, XQueryContext ctx) + : base (nav, ctx) + { + } + + private SelfIterator (SelfIterator other, bool cloneFlag) + : base (other, true) + { + } + + public override XPathSequence Clone () + { + return new SelfIterator (this, true); + } + + protected override bool MoveNextCore () + { + if (Position == 0) + return true; + return false; + } + } + + internal class ParentIterator : NodeIterator + { + public ParentIterator (XPathNavigator nav, XQueryContext ctx) + : base (nav, ctx) + { + } + + private ParentIterator (ParentIterator other, bool cloneFlag) + : base (other, true) + { + } + + public override XPathSequence Clone () + { + return new ParentIterator (this, true); + } + + protected override bool MoveNextCore () + { + if (Position == 0 && Node.MoveToParent ()) + return true; + return false; + } + + public override bool ReverseAxis { + get { return true; } + } + } + + internal class ChildIterator : NodeIterator + { + public ChildIterator (XPathNavigator nav, XQueryContext ctx) + : base (nav, ctx) + { + } + + private ChildIterator (ChildIterator other, bool cloneFlag) + : base (other, true) + { + } + + public override XPathSequence Clone () + { + return new ChildIterator (this, true); + } + + protected override bool MoveNextCore () + { + if (Position == 0) + return Node.MoveToFirstChild (); + else + return Node.MoveToNext (); + } + } + + internal class FollowingSiblingIterator : NodeIterator + { + public FollowingSiblingIterator (XPathNavigator nav, XQueryContext ctx) + : base (nav, ctx) + { + } + + private FollowingSiblingIterator (FollowingSiblingIterator other, bool cloneFlag) + : base (other, true) + { + } + + public override XPathSequence Clone () + { + return new FollowingSiblingIterator (this, true); + } + + protected override bool MoveNextCore () + { + return Node.MoveToNext (); + } + } + + internal class PrecedingSiblingIterator : NodeIterator + { + bool finished; + bool started; + XPathNavigator startPosition; + + public PrecedingSiblingIterator (XPathNavigator nav, XQueryContext ctx) + : base (nav, ctx) + { + startPosition = Node.Clone (); + } + + private PrecedingSiblingIterator (PrecedingSiblingIterator other, bool cloneFlag) + : base (other, true) + { + startPosition = other.startPosition; + started = other.started; + finished = other.finished; + } + + public override XPathSequence Clone () + { + return new PrecedingSiblingIterator (this, true); + } + + protected override bool MoveNextCore () + { + if (finished) + return false; + if (!started) { + started = true; + Node.MoveToFirst (); + } else { + Node.MoveToNext (); + } + if (Node.ComparePosition (startPosition) == XmlNodeOrder.Same) { + finished = true; + return false; + } + else + return true; + } + + public override bool ReverseAxis { + get { return true; } + } + } + + internal class AncestorIterator : NodeIterator + { + bool finished; + ArrayList nodes = new ArrayList (); + + public AncestorIterator (XPathNavigator nav, XQueryContext ctx) + : base (nav, ctx) + { + } + + private AncestorIterator (AncestorIterator other, bool cloneFlag) + : base (other, true) + { + finished = other.finished; + nodes = other.nodes; + } + + public override XPathSequence Clone () + { + return new AncestorIterator (this, true); + } + + protected override bool MoveNextCore () + { + if (finished) + return false; + if (nodes != null) { + nodes = new ArrayList (); + while (Node.MoveToParent () && Node.NodeType != XPathNodeType.Root) + nodes.Add (Node.Clone ()); + nodes.Reverse (); + } + if (nodes.Count >= Position) + return false; + Node.MoveTo (nodes [Position] as XPathNavigator); + return true; + } + + public override bool ReverseAxis { + get { return true; } + } + + public override int Count { + get { + if (Position == 0) + return base.Count; + return nodes.Count; + } + } + } + + internal class AncestorOrSelfIterator : NodeIterator + { + bool finished; + ArrayList nodes = new ArrayList (); + + public AncestorOrSelfIterator (XPathNavigator nav, XQueryContext ctx) + : base (nav, ctx) + { + } + + private AncestorOrSelfIterator (AncestorOrSelfIterator other, bool cloneFlag) + : base (other, true) + { + finished = other.finished; + nodes = other.nodes; + } + + public override XPathSequence Clone () + { + return new AncestorOrSelfIterator (this, true); + } + + protected override bool MoveNextCore () + { + if (finished) + return false; + if (nodes != null) { + nodes = new ArrayList (); + do { + nodes.Add (Node.Clone ()); + } while (Node.MoveToParent () && Node.NodeType != XPathNodeType.Root); + nodes.Reverse (); + } + if (nodes.Count >= Position) + return false; + Node.MoveTo (nodes [Position] as XPathNavigator); + return true; + } + + public override bool ReverseAxis { + get { return true; } + } + + public override int Count { + get { + if (Position == 0) + return base.Count; + return nodes.Count; + } + } + } + + internal class DescendantIterator : NodeIterator + { + private int depth; + private bool finished; + + public DescendantIterator (XPathNavigator nav, XQueryContext ctx) + : base (nav, ctx) + { + } + + private DescendantIterator (DescendantIterator other, bool cloneFlag) + : base (other, true) + { + finished = other.finished; + depth = other.depth; + } + + public override XPathSequence Clone () + { + return new DescendantIterator (this, true); + } + + protected override bool MoveNextCore () + { + if (finished) + return false; + + if (Node.MoveToFirstChild ()) { + depth ++; + return true; + } + while (depth != 0) { + if (Node.MoveToNext ()) + return true; + + if (!Node.MoveToParent ()) // should NEVER fail! + throw new XmlQueryException ("There seems some bugs on the XPathNavigator implementation class."); + depth --; + } + finished = true; + return false; + } + } + + internal class DescendantOrSelfIterator : NodeIterator + { + protected int depth; + private bool finished; + + public DescendantOrSelfIterator (XPathNavigator nav, XQueryContext ctx) + : base (nav, ctx) + { + } + + protected DescendantOrSelfIterator (DescendantOrSelfIterator other, bool cloneFlag) + : base (other, true) + { + depth = other.depth; + finished = other.finished; + } + + public override XPathSequence Clone () + { + return new DescendantOrSelfIterator (this, true); + } + + protected override bool MoveNextCore () + { + if (finished) + return false; + + if (Position == 0) + return true; // Self + + + if (Node.MoveToFirstChild ()) { + depth ++; + return true; + } + while (depth != 0) { + if (Node.MoveToNext ()) + return true; + + if (!Node.MoveToParent ()) // should NEVER fail! + throw new XmlQueryException ("There seems some bugs on the XPathNavigator implementation class."); + depth --; + } + finished = true; + return false; + } + } + + internal class FollowingIterator : NodeIterator + { + private bool finished; + + public FollowingIterator (XPathNavigator nav, XQueryContext ctx) + : base (nav, ctx) + { + } + + protected FollowingIterator (FollowingIterator other, bool cloneFlag) + : base (other, true) + { + finished = other.finished; + } + + public override XPathSequence Clone () + { + return new FollowingIterator (this, true); + } + + protected override bool MoveNextCore () + { + if (finished) + return false; + if (Position == 0) { + // At first, it should not iterate children. + if (Node.MoveToNext ()) + return true; + else { + while (Node.MoveToParent ()) + if (Node.MoveToNext ()) + return true; + } + } else { + if (Node.MoveToFirstChild ()) + return true; + do { + if (Node.MoveToNext ()) + return true; + } while (Node.MoveToParent ()); + } + finished = true; + return false; + } + } + + internal class PrecedingIterator : NodeIterator + { + bool finished; + bool started; + XPathNavigator startPosition; + + public PrecedingIterator (XPathNavigator nav, XQueryContext ctx) + : base (nav, ctx) + { + startPosition = Node.Clone (); + } + + private PrecedingIterator (PrecedingIterator other, bool cloneFlag) + : base (other, true) + { + startPosition = other.startPosition; + started = other.started; + finished = other.finished; + } + + public override XPathSequence Clone () + { + return new PrecedingIterator (this, true); + } + + protected override bool MoveNextCore () + { + if (finished) + return false; + if (!started) { + started = true; + Node.MoveToRoot (); + } + bool loop = true; + while (loop) { + while (!Node.MoveToFirstChild ()) { + while (!Node.MoveToNext ()) { + if (!Node.MoveToParent ()) { // Should not finish, at least before startPosition. + finished = true; + return false; + } + } + break; + } + if (Node.IsDescendant (startPosition)) + continue; + loop = false; + break; + } + if (Node.ComparePosition (startPosition) != XmlNodeOrder.Before) { + // Note that if _nav contains only 1 node, it won't be Same. + finished = true; + return false; + } + else + return true; + } + + public override bool ReverseAxis { + get { return true; } + } + } + + internal class NamespaceIterator : NodeIterator + { + public NamespaceIterator (XPathNavigator nav, XQueryContext ctx) + : base (nav, ctx) + { + } + + private NamespaceIterator (NamespaceIterator other, bool cloneFlag) + : base (other, true) + { + } + + public override XPathSequence Clone () + { + return new NamespaceIterator (this, true); + } + + protected override bool MoveNextCore () + { + if (Position == 0) { + if (Node.MoveToFirstNamespace ()) + return true; + } + else if (Node.MoveToNextNamespace ()) + return true; + return false; + } + + public override bool ReverseAxis { get { return true; } } + } + + internal class AttributeIterator : NodeIterator + { + public AttributeIterator (XPathNavigator nav, XQueryContext ctx) + : base (nav, ctx) + { + } + + private AttributeIterator (AttributeIterator other, bool cloneFlag) + : base (other, true) + { + } + + public override XPathSequence Clone () + { + return new AttributeIterator (this, true); + } + + protected override bool MoveNextCore () + { + if (Position == 0) { + if (Node.MoveToFirstAttribute ()) + return true; + } + else if (Node.MoveToNextAttribute ()) + return true; + return false; + } + } + + // + + internal class ExprSequenceIterator : XPathSequence + { + XPathSequence contextSequence; + XPathSequence iter; + ExprSequence expr; + int currentExprIndex; + + public ExprSequenceIterator (XPathSequence iter, ExprSequence expr) + : base (iter.Context) + { + contextSequence = iter; + this.expr = expr; + } + + private ExprSequenceIterator (ExprSequenceIterator other) + : base (other) + { + if (other.iter != null) + iter = other.iter.Clone (); + expr = other.expr; + contextSequence = other.contextSequence; + currentExprIndex = other.currentExprIndex; + } + + public override XPathSequence Clone () + { + return new ExprSequenceIterator (this); + } + + protected override bool MoveNextCore () + { + if (iter != null && iter.MoveNext ()) + return true; + while (currentExprIndex < expr.Count) { + iter = expr [currentExprIndex++].Evaluate (contextSequence); + if (iter.MoveNext ()) + return true; + } + return false; + } + + public override XPathItem CurrentCore { + get { return iter.Current; } + } + } + + // FLWOR - Order By + internal class FLWORIterator : XPathSequence + { + XPathSequence contextSequence; + FLWORExpr expr; + ArrayList forStack = new ArrayList (); + IEnumerator en; + bool finished; + + public FLWORIterator (XPathSequence iter, FLWORExpr expr) + : base (iter.Context) + { + this.contextSequence = iter; + this.expr = expr; + } + + private FLWORIterator (FLWORIterator other) + : base (other) + { + contextSequence = other.contextSequence; + expr = other.expr; + forStack = other.forStack.Clone () as ArrayList; + if (en != null) + en = ((ICloneable) other.en).Clone () as IEnumerator; + finished = other.finished; + } + + public override XPathSequence Clone () + { + return new FLWORIterator (this); + } + + protected override bool MoveNextCore () + { + if (en == null) + en = GetEnumerator (); + return en.MoveNext (); + } + + public override IEnumerator GetEnumerator () + { + return EvaluateRemainingForLet (0); + } + + private IEnumerator EvaluateRemainingForLet (int flcPosition) + { + // Prepare iteration stack + if (flcPosition < expr.ForLetClauses.Count) { + IEnumerator items = EvaluateRemainingSingleItem (flcPosition, 0); + while (items.MoveNext ()) + yield return items.Current; + } else { + bool passedFilter = expr.WhereClause == null; + if (!passedFilter) + passedFilter = expr.WhereClause.EvaluateAsBoolean (contextSequence); + if (passedFilter) { + IEnumerator ie = expr.ReturnExpr.Evaluate (contextSequence).GetEnumerator (); + while (ie.MoveNext ()) + yield return (XPathItem) ie.Current; + } + } + } + + private IEnumerator EvaluateRemainingSingleItem (int flcPosition, int singlePosition) + { + if (singlePosition < expr.ForLetClauses [flcPosition].Count) { + ForLetSingleBody sb = expr.ForLetClauses [flcPosition] [singlePosition]; + ForSingleBody fsb = sb as ForSingleBody; + if (fsb != null) { + XPathSequence backup = contextSequence; + contextSequence = fsb.Expression.Evaluate (Context.CurrentSequence); + Context.ContextManager.PushCurrentSequence (contextSequence); + while (contextSequence.MoveNext ()) { + XPathItem forItem = (XPathItem) contextSequence.Current; + Context.PushVariable (fsb.PositionalVar, contextSequence.Position); + Context.PushVariable (sb.VarName, forItem); + // recurse here (including following bindings) + IEnumerator items = EvaluateRemainingSingleItem (flcPosition, singlePosition + 1); + while (items.MoveNext ()) + yield return (XPathItem) items.Current; + Context.PopVariable (); + Context.PopVariable (); + } + Context.ContextManager.PopCurrentSequence (); + contextSequence = backup; + } else { + Context.PushVariable (sb.VarName, sb.Expression.Evaluate (contextSequence)); + // recurse here (including following bindings) + IEnumerator items = EvaluateRemainingSingleItem (flcPosition, singlePosition + 1); + while (items.MoveNext ()) + yield return (XPathItem) items.Current; + Context.PopVariable (); + } + } else { + // evaluate next binding + IEnumerator items = EvaluateRemainingForLet (flcPosition + 1); + while (items.MoveNext ()) + yield return (XPathItem) items.Current; + } + } + + public override XPathItem CurrentCore { + get { return (XPathItem) en.Current; } + } + } + + internal class GroupIterator : XPathSequence + { + GroupExpr expr; + XPathSequence lseq; + XPathSequence rseq; + bool started; + bool left; + bool leftFinished; + bool rightFinished; + + public GroupIterator (XPathSequence iter, GroupExpr expr) + : base (iter.Context) + { + this.expr = expr; + left = true; + lseq = expr.Left.EvaluateOrdered (iter); + rseq = expr.Right.EvaluateOrdered (iter); + } + + private GroupIterator (GroupIterator other) + : base (other) + { + this.expr = other.expr; + this.started = other.started; + this.left = other.left; + this.leftFinished = other.leftFinished; + this.rightFinished = other.rightFinished; + this.lseq = other.lseq.Clone (); + this.rseq = other.rseq.Clone (); + } + + public override XPathSequence Clone () + { + return new GroupIterator (this); + } + + protected override bool MoveNextCore () + { + if (leftFinished && rightFinished) + return false; + bool proceeded = false; + if (started) { + if (left) { + if (!leftFinished && lseq.MoveNext ()) + proceeded = true; + else + leftFinished = true; + } else { + if (rightFinished && rseq.MoveNext ()) + proceeded = true; + else + rightFinished = true; + } + } else { + started = true; + if (!lseq.MoveNext ()) { + leftFinished = true; + if (!rseq.MoveNext ()) { + rightFinished = true; + return false; + } + left = false; + return true; + } + proceeded = true; + if (!rseq.MoveNext ()) { + rightFinished = true; + return true; + } + } + if (!proceeded) { + if (expr.AggregationType == AggregationType.Intersect) + return false; + left = !leftFinished; + return !leftFinished || !rightFinished; + } + + XPathNavigator lnav = lseq.Current as XPathNavigator; + XPathNavigator rnav = rseq.Current as XPathNavigator; + if (lnav == null || rnav == null) + throw new XmlQueryException ("XP0006: Evaluation against union, intersect, except expressions must result in nodes."); + XmlNodeOrder order = lnav.ComparePosition (rnav); + switch (order) { + case XmlNodeOrder.Same: + switch (expr.AggregationType) { + case AggregationType.Union: + left = false; + if (!lseq.MoveNext ()) + leftFinished = true; + return true; + case AggregationType.Intersect: + return true; + case AggregationType.Except: + default: + return MoveNext (); + } + case XmlNodeOrder.Before: + left = true; + if (expr.AggregationType == AggregationType.Intersect) + return MoveNext (); + return true; + default: // After, Unknown + left = false; + if (expr.AggregationType == AggregationType.Intersect) + return MoveNext (); + return true; + } + } + + public override XPathItem CurrentCore { + get { return left ? lseq.Current : rseq.Current; } + } + } + + internal class AtomizingIterator : XPathSequence + { + XPathSequence iter; + + public AtomizingIterator (XPathSequence iter) + : base (iter.Context) + { + this.iter = iter; + } + + private AtomizingIterator (AtomizingIterator other) + : base (other) + { + iter = other.iter.Clone (); + } + + public override XPathSequence Clone () + { + return new AtomizingIterator (this); + } + + protected override bool MoveNextCore () + { + return iter.MoveNext (); + } + + public override XPathItem CurrentCore { + get { + XPathNavigator nav = iter.Current as XPathNavigator; + if (nav == null) + return (XPathAtomicValue) iter.Current; + if (nav.SchemaInfo != null) + return new XPathAtomicValue ( + nav.TypedValue, + nav.SchemaInfo.SchemaType); + else + return new XPathAtomicValue (nav.Value, null); + } + } + } + + internal class ConvertingIterator : XPathSequence + { + XPathSequence iter; + SequenceType type; + + public ConvertingIterator (XPathSequence iter, SequenceType type) + : base (iter.Context) + { + this.iter = iter; + this.type = type; + } + + private ConvertingIterator (ConvertingIterator other) + : base (other) + { + iter = other.iter.Clone (); + type = other.type; + } + + public override XPathSequence Clone () + { + return new ConvertingIterator (this); + } + + protected override bool MoveNextCore () + { + return iter.MoveNext (); + } + + public override XPathItem CurrentCore { + get { return type.Convert (iter.Current); } + } + } + + internal class TracingIterator : XPathSequence + { + XPathSequence iter; + string format; + + public TracingIterator (XPathSequence iter, string format) + : base (iter.Context) + { + this.iter = iter; + this.format = format; + } + + private TracingIterator (TracingIterator other) + : base (other) + { + iter = other.iter.Clone (); + format = other.format; + } + + public override XPathSequence Clone () + { + return new TracingIterator (this); + } + + protected override bool MoveNextCore () + { + if (!iter.MoveNext ()) + return false; + // FIXME: use OnMessageEvent + string output = String.Format (format, iter.Current.TypedValue); + Context.StaticContext.OnMessageEvent (iter.Current, new QueryEventArgs (output)); + return true; + } + + public override XPathItem CurrentCore { + get { return iter.Current; } + } + } + + internal class QueryEventArgs + { + string msg; + + public QueryEventArgs (string msg) + { + this.msg = msg; + } + + public string Message { + get { return msg; } + } + } + + internal class ListIterator : XPathSequence + { + IList list; + + public ListIterator (XQueryContext ctx, IList list) + : base (ctx) + { + if (list is ICloneable) + this.list = list; + else + throw new InvalidOperationException (String.Format ("XQuery internal error: target list is not cloneable. List is {0}.", list != null ? list.GetType ().ToString () : "null argument")); + } + + private ListIterator (ListIterator other) + : base (other) + { + this.list = (IList) ((ICloneable) other.list).Clone (); + } + + public override XPathSequence Clone () + { + return new ListIterator (this); + } + + protected override bool MoveNextCore () + { + return (Position < list.Count); + } + + public override XPathItem CurrentCore { + get { return (XPathItem) list [Position - 1]; } + } + } + + internal class EnumeratorIterator : XPathSequence + { + IEnumerator list; + + public EnumeratorIterator (XQueryContext ctx, IEnumerable en) + : base (ctx) + { + list = en.GetEnumerator (); + if (list is ICloneable) + this.list = list; + else + throw new InvalidOperationException (String.Format ("XQuery internal error: target list's enumerator is not cloneable. List is {0}.", en != null ? en.GetType ().ToString () : "null argument")); + } + + private EnumeratorIterator (EnumeratorIterator other) + : base (other) + { + this.list = (IEnumerator) ((ICloneable) other.list).Clone (); + } + + public override XPathSequence Clone () + { + return new EnumeratorIterator (this); + } + + protected override bool MoveNextCore () + { + return list.MoveNext (); + } + + public override XPathItem CurrentCore { + get { return (XPathItem) list.Current; } + } + } + + internal abstract class WrapperIterator : XPathSequence + { + XPathSequence source; + + public WrapperIterator (XPathSequence source) + : base (source.Context) + { + this.source = source; + } + + protected WrapperIterator (WrapperIterator other, bool flag) + : base (other) + { + source = other.source.Clone (); + } + + public XPathSequence Source { + get { return source; } + } + + public override XPathItem CurrentCore { + get { return source.Current; } + } + } + + internal class RemovalIterator : WrapperIterator + { + int position; + + public RemovalIterator (XPathSequence source, int position) + : base (source) + { + this.position = position; + } + + protected RemovalIterator (RemovalIterator other) + : base (other, true) + { + position = other.position; + } + + public override XPathSequence Clone () + { + return new RemovalIterator (this); + } + + protected override bool MoveNextCore () + { + if (!Source.MoveNext ()) + return false; + else if (Source.Position == position) // skip target + return Source.MoveNext (); + else + return true; + } + } + + internal class InsertingIterator : WrapperIterator + { + int position; + XPathSequence inserts; + bool sourceFinished; + bool insertsFinished; + XPathSequence currentSequence; + + public InsertingIterator (XPathSequence target, int position, XPathSequence inserts) + : base (target) + { + this.position = position; + this.inserts = inserts; + currentSequence = target; + } + + protected InsertingIterator (InsertingIterator other) + : base (other) + { + position = other.position; + inserts = other.inserts.Clone (); + sourceFinished = other.sourceFinished; + insertsFinished = other.insertsFinished; + currentSequence = + other.inserts == other.currentSequence ? + inserts : Source; + } + + public override XPathSequence Clone () + { + return new InsertingIterator (this); + } + + protected override bool MoveNextCore () + { + if (insertsFinished && sourceFinished) + return false; + if (sourceFinished) { // position >= source.Count + currentSequence = inserts; + if (inserts.MoveNext ()) + return true; + insertsFinished = true; + return false; + } + else if (insertsFinished) { // after insertion + if (Source.MoveNext ()) + return true; + sourceFinished = true; + return false; + } + else if (Position >= position - 1) { + currentSequence = inserts; + if (inserts.MoveNext ()) + return true; + currentSequence = Source; + insertsFinished = true; + } + if (Source.MoveNext ()) + return true; + sourceFinished = true; + return MoveNextCore (); + } + + public override XPathItem CurrentCore { + get { return currentSequence.Current; } + } + } + + internal class DistinctValueIterator : XPathSequence + { + XPathSequence items; + CultureInfo collation; + Hashtable table = new Hashtable (); + + public DistinctValueIterator (XQueryContext ctx, XPathSequence items, CultureInfo collation) + : base (ctx) + { + this.items = items; + this.collation = collation; + } + + protected DistinctValueIterator (DistinctValueIterator other) + : base (other) + { + items = other.items.Clone (); + collation = other.collation; + table = (Hashtable) other.table.Clone (); + } + + public override XPathSequence Clone () + { + return new DistinctValueIterator (this); + } + + protected override bool MoveNextCore () + { + if (!items.MoveNext ()) + return false; + // FIXME: use collations + // FIXME: check if it really works (esp. Uri et.al) + if (table.Contains (items.Current.TypedValue)) + return MoveNextCore (); + return true; + } + + public override XPathItem CurrentCore { + get { return items.Current; } + } + } +} + +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryASTCompiler.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryASTCompiler.cs new file mode 100755 index 00000000000..2d18e9e676c --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryASTCompiler.cs @@ -0,0 +1,265 @@ +// +// XQueryASTCompiler.cs - XQuery static context compiler +// +// Author: +// Atsushi Enomoto +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// + +#if NET_2_0 + +using System; +using System.Collections; +using System.Collections.Specialized; +using System.IO; +using System.Security.Policy; +using System.Xml; +using System.Xml.Query; +using System.Xml.Schema; +using Mono.Xml.XQuery; +using Mono.Xml.XQuery.Parser; +using Mono.Xml; + +namespace Mono.Xml.XPath2 +{ + internal class XQueryASTCompiler + { + // Static method + + public static XQueryStaticContext Compile (XQueryModule module, XQueryCompileOptions options, Evidence evidence, XQueryCommandImpl commandImpl) + { + if (options == null) + options = new XQueryCompileOptions (); + return new XQueryASTCompiler (module, options, new XQueryCompileContext (), evidence, commandImpl).Compile (); + } + + // Constructor + + private XQueryASTCompiler (XQueryModule module, XQueryCompileOptions options, XQueryCompileContext compileContext, Evidence evidence, XQueryCommandImpl commandImpl) + { + this.module = module; + this.options = options; + this.compileContext = compileContext; + this.evidence = evidence; + this.commandImpl = commandImpl; + + inScopeSchemas = new XmlSchemaSet (); + localVariables = new Hashtable (); + localFunctions = new XQueryFunctionTable (); + } + + XQueryModule module; + XQueryCompileOptions options; + XQueryCompileContext compileContext; + + IXmlNamespaceResolver nsResolver; + string defaultFunctionNamespace; + + // FIXME: Is it OK for an XmlSchema to be in two or more set? + XmlSchemaSet inScopeSchemas; + ArrayList libModuleContexts = new ArrayList (); + + Hashtable localVariables; + XQueryFunctionTable localFunctions; + + bool preserveWhitespace; // Xml space policy + bool constructionSpace; // construction mode + bool defaultOrdered; // Ordering mode + string baseUri; + Evidence evidence; + XQueryCommandImpl commandImpl; + + // methods. + + private XQueryStaticContext Compile () + { + CompileProlog (); + + XQueryMainModule main = module as XQueryMainModule; + ExprSequence expr = (main != null) ? + CompileExprSequence (main.QueryBody) : null; + + return new XQueryStaticContext ( + options, + compileContext, + expr, + inScopeSchemas, + localVariables, + localFunctions, + module.NSResolver, + module.Prolog.DefaultFunctionNamespace, + preserveWhitespace, + constructionSpace, + defaultOrdered, + baseUri, + evidence, + commandImpl); + } + + private void CompileProlog () + { + Prolog p = module.Prolog; + + // resolve external modules + // FIXME: check if external queries are allowed by default. + // FIXME: check recursion + XmlUrlResolver res = new XmlUrlResolver (); + foreach (ModuleImport modimp in p.ModuleImports) { + foreach (string uri in modimp.Locations) { + Stream s = res.GetEntity (res.ResolveUri (null, uri), null, typeof (Stream)) as Stream; + XQueryLibraryModule ext = XQueryParser.Parse (new StreamReader (s)) as XQueryLibraryModule; + if (ext == null) + throw new XmlQueryCompileException (String.Format ("External module {0} is resolved as a main module, while it should be a library module.")); + XQueryStaticContext sctx = new XQueryASTCompiler (ext, options, compileContext, evidence, commandImpl).Compile (); + libModuleContexts.Add (sctx); + } + } + + // resolve and compile in-scope schemas + foreach (SchemaImport xsimp in p.SchemaImports) { + foreach (string uri in xsimp.Locations) { + XmlSchema schema = inScopeSchemas.Add (xsimp.Namespace, uri); + compileContext.InEffectSchemas.Add (schema); + } + } + inScopeSchemas.Compile (); + + CheckReferences (); + + ResolveVariableReferences (); + + // compile FunctionDeclaration into XQueryFunction + foreach (FunctionDeclaration func in p.Functions.Values) { + XQueryFunction cfunc = CompileFunction (func); + localFunctions.Add (cfunc); + } + } + + private void CheckReferences () + { + XQueryMainModule main = module as XQueryMainModule; + if (main != null) + main.QueryBody.CheckReference (this); + foreach (FunctionDeclaration func in module.Prolog.Functions.Values) { + if (!func.External) + func.FunctionBody.CheckReference (this); + CheckSchemaType (func.ReturnType); + foreach (XQueryFunctionArgument param in func.Parameters) + CheckSchemaType (param.Type); + } + } + + internal void CheckSchemaType (SequenceType type) + { + if (type == null) + return; + type.ItemType.CheckReference (this); + } + + internal void CheckSchemaTypeName (XmlQualifiedName name) + { + XmlSchemaType type = InternalPool.GetBuiltInType (name); + if (type != null) + return; + throw new XmlQueryCompileException (String.Format ("Unresolved schema type name: {0}", name)); + } + + internal void CheckVariableName (XmlQualifiedName name) + { + // This should not be done, since unresolved QName + // may be still valid in context of XmlArgumentList + // which is supplied at dynamic evaluation phase. + /* + if (module.Prolog.Variables [name] != null) + return; + if (localVariables [name] != null) + return; + foreach (XQueryStaticContext ctx in libModuleContexts) + if (ctx.InScopeVariables [name] != null) + return; + throw new XmlQueryCompileException (String.Format ("Unresolved variable name: {0}", name)); + */ + } + + internal void CheckFunctionName (XmlQualifiedName name) + { + if (XQueryFunction.FindKnownFunction (name) != null) + return; + if (module.Prolog.Functions [name] != null) + return; + foreach (XQueryStaticContext ctx in libModuleContexts) + if (ctx.InScopeFunctions [name] != null) + return; + throw new XmlQueryCompileException (String.Format ("Unresolved function name: {0}", name)); + } + + private void ResolveVariableReferences () + { + // TODO + } + + internal XmlSchemaType ResolveSchemaType (XmlQualifiedName name) + { + XmlSchemaType type = InternalPool.GetBuiltInType (name); + if (type != null) + return type; + type = inScopeSchemas.GlobalTypes [name] as XmlSchemaType; + if (type != null) + return type; + return null; + } + + private XQueryFunction CompileFunction (FunctionDeclaration func) + { + if (func.External) + return XQueryFunction.FromQName (func.Name); + return new XQueryUserFunction (func.Name, func.Parameters.ToArray (), func.FunctionBody.Expr, func.ReturnType); + } + + private ExprSequence CompileExprSequence (ExprSequence expr) + { + for (int i = 0; i < expr.Count; i++) + expr [i] = expr [i].Compile (this); + return expr; + } + + internal void CheckType (ExprSingle expr, SequenceType type) + { + if (!expr.StaticType.CanConvertTo (type)) + throw new XmlQueryCompileException (String.Format ("Cannot convert type from {0} to {1}", expr.StaticType, type)); + } + + internal XQueryFunction ResolveFunction (XmlQualifiedName name) + { + XQueryFunction func = XQueryFunction.FindKnownFunction (name); + if (func == null) + func = localFunctions [name]; + + if (func != null) + return func; + else + throw new XmlQueryCompileException ("Could not find specified function."); + } + } +} +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryArithmeticOperator.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryArithmeticOperator.cs new file mode 100755 index 00000000000..665a5212eab --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryArithmeticOperator.cs @@ -0,0 +1,368 @@ +// +// XQueryArithmeticOperator.cs +// +// Author: +// Atsushi Enomoto +// +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// + +#if NET_2_0 +using System; +using System.Collections; +using System.Reflection; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Query; +using System.Xml.XPath; +using System.Xml.Xsl; +using Mono.Xml; + +namespace Mono.Xml.XPath2 +{ + // FIXME: Handle complete type promotion and subtype substitution. + // See XQuery 1.0 Appendix B.*. + public class XQueryArithmeticOperator + { + /// + /// x + y + /// + public static XPathAtomicValue Add (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + // numeric, date, time, dateTime, yearMonthDuration, dayTimeDuration + switch (lvalue.XmlType.TypeCode) { + + // numerics + case XmlTypeCode.Integer: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Integer: + return new XPathAtomicValue (lvalue.ValueAsInt64 + rvalue.ValueAsInt64, rvalue.XmlType); + case XmlTypeCode.Decimal: + return new XPathAtomicValue (lvalue.ValueAsDecimal + rvalue.ValueAsDecimal, rvalue.XmlType); + case XmlTypeCode.Float: + case XmlTypeCode.Double: + return new XPathAtomicValue (lvalue.ValueAsDouble + rvalue.ValueAsDouble, rvalue.XmlType); + } + break; + + case XmlTypeCode.Decimal: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Integer: + case XmlTypeCode.Decimal: + return new XPathAtomicValue (lvalue.ValueAsDecimal + rvalue.ValueAsDecimal, rvalue.XmlType); + case XmlTypeCode.Float: + case XmlTypeCode.Double: + return new XPathAtomicValue (lvalue.ValueAsDouble + rvalue.ValueAsDouble, rvalue.XmlType); + } + break; + + case XmlTypeCode.Float: + case XmlTypeCode.Double: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Integer: + case XmlTypeCode.Decimal: + case XmlTypeCode.Float: + case XmlTypeCode.Double: + return new XPathAtomicValue (lvalue.ValueAsDouble + rvalue.ValueAsDouble, rvalue.XmlType); + } + break; + + // datetimes + case XmlTypeCode.Time: + if (rvalue.XmlType.TypeCode == XmlTypeCode.DayTimeDuration) + goto case XmlTypeCode.DateTime; + break; + case XmlTypeCode.DateTime: + case XmlTypeCode.Date: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.YearMonthDuration: + case XmlTypeCode.DayTimeDuration: + return new XPathAtomicValue (lvalue.ValueAsDateTime + new TimeSpan (rvalue.ValueAsDateTime.Ticks), lvalue.XmlType); + } + break; + // durations + case XmlTypeCode.YearMonthDuration: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Date: + case XmlTypeCode.DateTime: + return new XPathAtomicValue (lvalue.ValueAsDateTime + new TimeSpan (rvalue.ValueAsDateTime.Ticks), rvalue.XmlType); + case XmlTypeCode.YearMonthDuration: + return new XPathAtomicValue (new DateTime (lvalue.ValueAsDateTime.Ticks + rvalue.ValueAsDateTime.Ticks), InternalPool.XdtYearMonthDuration); + } + break; + case XmlTypeCode.DayTimeDuration: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Date: + case XmlTypeCode.Time: + case XmlTypeCode.DateTime: + return new XPathAtomicValue (lvalue.ValueAsDateTime + new TimeSpan (rvalue.ValueAsDateTime.Ticks), rvalue.XmlType); + case XmlTypeCode.DayTimeDuration: + return new XPathAtomicValue (new DateTime (lvalue.ValueAsDateTime.Ticks + rvalue.ValueAsDateTime.Ticks), InternalPool.XdtDayTimeDuration); + } + break; + } + + throw new XmlQueryException (String.Format ("Not allowed arithmetic operation: {0} + {1}", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName)); + } + + /// + /// x - y + /// + public static XPathAtomicValue Subtract (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + // numeric, date, time, dateTime, yearMonthDuration, dayTimeDuration + switch (lvalue.XmlType.TypeCode) { + + // numerics + case XmlTypeCode.Integer: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Integer: + return new XPathAtomicValue (lvalue.ValueAsInt64 - rvalue.ValueAsInt64, rvalue.XmlType); + case XmlTypeCode.Decimal: + return new XPathAtomicValue (lvalue.ValueAsDecimal - rvalue.ValueAsDecimal, rvalue.XmlType); + case XmlTypeCode.Float: + case XmlTypeCode.Double: + return new XPathAtomicValue (lvalue.ValueAsDouble - rvalue.ValueAsDouble, rvalue.XmlType); + } + break; + + case XmlTypeCode.Decimal: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Integer: + case XmlTypeCode.Decimal: + return new XPathAtomicValue (lvalue.ValueAsDecimal - rvalue.ValueAsDecimal, rvalue.XmlType); + case XmlTypeCode.Float: + case XmlTypeCode.Double: + return new XPathAtomicValue (lvalue.ValueAsDouble - rvalue.ValueAsDouble, rvalue.XmlType); + } + break; + + case XmlTypeCode.Float: + case XmlTypeCode.Double: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Integer: + case XmlTypeCode.Decimal: + case XmlTypeCode.Float: + case XmlTypeCode.Double: + return new XPathAtomicValue (lvalue.ValueAsDouble - rvalue.ValueAsDouble, rvalue.XmlType); + } + break; + + // datetimes + case XmlTypeCode.Time: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Time: + return new XPathAtomicValue (lvalue.ValueAsDateTime - rvalue.ValueAsDateTime, InternalPool.XdtDayTimeDuration); + case XmlTypeCode.DayTimeDuration: + return new XPathAtomicValue (lvalue.ValueAsDateTime - new TimeSpan (rvalue.ValueAsDateTime.Ticks), lvalue.XmlType); + } + break; + + case XmlTypeCode.DateTime: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.DateTime: + // FIXME: check fn:subtract-daytimes-yielding-dayTimeDuration() + return new XPathAtomicValue (lvalue.ValueAsDateTime - rvalue.ValueAsDateTime, InternalPool.XdtDayTimeDuration); + case XmlTypeCode.YearMonthDuration: + case XmlTypeCode.DayTimeDuration: + return new XPathAtomicValue (lvalue.ValueAsDateTime - new TimeSpan (rvalue.ValueAsDateTime.Ticks), lvalue.XmlType); + } + break; + + case XmlTypeCode.Date: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Date: + // FIXME: check fn:subtract-daytimes-yielding-dayTimeDuration() + return new XPathAtomicValue (lvalue.ValueAsDateTime - rvalue.ValueAsDateTime, InternalPool.XdtDayTimeDuration); + case XmlTypeCode.YearMonthDuration: + case XmlTypeCode.DayTimeDuration: + return new XPathAtomicValue (lvalue.ValueAsDateTime - new TimeSpan (rvalue.ValueAsDateTime.Ticks), lvalue.XmlType); + } + break; + + // durations + case XmlTypeCode.YearMonthDuration: + if (rvalue.XmlType.TypeCode == XmlTypeCode.YearMonthDuration) + return new XPathAtomicValue (new TimeSpan (lvalue.ValueAsDateTime.Ticks - rvalue.ValueAsDateTime.Ticks), InternalPool.XdtYearMonthDuration); + break; + case XmlTypeCode.DayTimeDuration: + if (rvalue.XmlType.TypeCode == XmlTypeCode.DayTimeDuration) + return new XPathAtomicValue (new TimeSpan (lvalue.ValueAsDateTime.Ticks - rvalue.ValueAsDateTime.Ticks), InternalPool.XdtDayTimeDuration); + break; + } + + throw new XmlQueryException (String.Format ("Not allowed arithmetic operation: {0} - {1}", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName)); + } + + /// + /// x * y + /// + public static XPathAtomicValue Multiply (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + // numeric, date, time, dateTime, yearMonthDuration, dayTimeDuration + switch (lvalue.XmlType.TypeCode) { + + // numerics + case XmlTypeCode.Integer: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Integer: + return new XPathAtomicValue (lvalue.ValueAsInt64 * rvalue.ValueAsInt64, rvalue.XmlType); + case XmlTypeCode.Decimal: + return new XPathAtomicValue (lvalue.ValueAsDecimal * rvalue.ValueAsDecimal, rvalue.XmlType); + case XmlTypeCode.Float: + case XmlTypeCode.Double: + return new XPathAtomicValue (lvalue.ValueAsDouble * rvalue.ValueAsDouble, rvalue.XmlType); + + case XmlTypeCode.DayTimeDuration: + case XmlTypeCode.YearMonthDuration: + goto case XmlTypeCode.Decimal; + } + break; + + case XmlTypeCode.Decimal: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Integer: + case XmlTypeCode.Decimal: + return new XPathAtomicValue (lvalue.ValueAsDecimal * rvalue.ValueAsDecimal, rvalue.XmlType); + case XmlTypeCode.Float: + case XmlTypeCode.Double: + return new XPathAtomicValue (lvalue.ValueAsDouble * rvalue.ValueAsDouble, rvalue.XmlType); + + case XmlTypeCode.YearMonthDuration: + case XmlTypeCode.DayTimeDuration: + return new XPathAtomicValue (new TimeSpan ((long) (lvalue.ValueAsDateTime.Ticks * rvalue.ValueAsDecimal)), rvalue.XmlType); + } + break; + + case XmlTypeCode.Float: + case XmlTypeCode.Double: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Integer: + case XmlTypeCode.Decimal: + case XmlTypeCode.Float: + case XmlTypeCode.Double: + return new XPathAtomicValue (lvalue.ValueAsDouble * rvalue.ValueAsDouble, rvalue.XmlType); + + case XmlTypeCode.DayTimeDuration: + case XmlTypeCode.YearMonthDuration: + goto case XmlTypeCode.Decimal; + } + break; + + // durations + case XmlTypeCode.DayTimeDuration: + case XmlTypeCode.YearMonthDuration: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Integer: + case XmlTypeCode.Decimal: + case XmlTypeCode.Float: + case XmlTypeCode.Double: + return Multiply (rvalue, lvalue); + } + break; + } + + throw new XmlQueryException (String.Format ("Not allowed arithmetic operation: {0} * {1}", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName)); + } + + /// + /// x / y + /// + public static XPathAtomicValue Divide (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + // numeric, date, time, dateTime, yearMonthDuration, dayTimeDuration + switch (lvalue.XmlType.TypeCode) { + + // numerics + case XmlTypeCode.Integer: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Integer: + return new XPathAtomicValue (lvalue.ValueAsInt64 / rvalue.ValueAsInt64, rvalue.XmlType); + case XmlTypeCode.Decimal: + return new XPathAtomicValue (lvalue.ValueAsDecimal / rvalue.ValueAsDecimal, rvalue.XmlType); + case XmlTypeCode.Float: + case XmlTypeCode.Double: + return new XPathAtomicValue (lvalue.ValueAsDouble / rvalue.ValueAsDouble, rvalue.XmlType); + } + break; + + case XmlTypeCode.Decimal: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Integer: + case XmlTypeCode.Decimal: + return new XPathAtomicValue (lvalue.ValueAsDecimal / rvalue.ValueAsDecimal, rvalue.XmlType); + case XmlTypeCode.Float: + case XmlTypeCode.Double: + return new XPathAtomicValue (lvalue.ValueAsDouble / rvalue.ValueAsDouble, rvalue.XmlType); + } + break; + + case XmlTypeCode.Float: + case XmlTypeCode.Double: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Integer: + case XmlTypeCode.Decimal: + case XmlTypeCode.Float: + case XmlTypeCode.Double: + return new XPathAtomicValue (lvalue.ValueAsDouble / rvalue.ValueAsDouble, rvalue.XmlType); + + case XmlTypeCode.DayTimeDuration: + case XmlTypeCode.YearMonthDuration: + goto case XmlTypeCode.Decimal; + } + break; + + // durations + case XmlTypeCode.DayTimeDuration: + case XmlTypeCode.YearMonthDuration: + switch (rvalue.XmlType.TypeCode) { + case XmlTypeCode.Integer: + case XmlTypeCode.Decimal: + case XmlTypeCode.Float: + case XmlTypeCode.Double: + return new XPathAtomicValue (new DateTime ((long) (lvalue.ValueAsDateTime.Ticks / rvalue.ValueAsDouble)), rvalue.XmlType); + } + break; + } + + throw new XmlQueryException (String.Format ("Not allowed arithmetic operation: {0} div {1}", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName)); + } + + /// + /// x idiv y + /// + public static XPathAtomicValue IntDivide (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + return new XPathAtomicValue (lvalue.ValueAsInt64 / rvalue.ValueAsInt64, InternalPool.XsInteger); + } + + /// + /// x imod y + /// + public static XPathAtomicValue Remainder (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + return new XPathAtomicValue (lvalue.ValueAsInt64 % rvalue.ValueAsInt64, InternalPool.XsInteger); + } + } +} +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryCliFunction.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryCliFunction.cs new file mode 100755 index 00000000000..c081a5b6cdb --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryCliFunction.cs @@ -0,0 +1,210 @@ +// +// XQueryCliFunction.cs +// +// Author: +// Atsushi Enomoto +// +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// + +// +// Runtime type method wrapper for XPath2 function. +// +#if NET_2_0 +using System; +using System.Collections; +using System.Reflection; +using System.Security; +using System.Security.Policy; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Query; +using System.Xml.XPath; +using System.Xml.Xsl; +using Mono.Xml; + +namespace Mono.Xml.XPath2 +{ + + // Ideas: + // declare function namespace cli = "http://mono-project.com/xquery/function/cli" + // declare variable v = cli:invoke (cli:new (Microsoft.CSharp:CSharpCodeProvider), CreateCompiler); + // declare variable v2 = System.Math:Abs (0.5); + // + + public class XQueryCliFunction : XQueryFunction + { + internal static XQueryCliFunction CreateFromMethodInfo (MethodInfo mi) + { + return CreateFromMethodInfo (null, mi); + } + + internal static XQueryCliFunction CreateFromMethodInfo (XmlQualifiedName name, MethodInfo mi) + { + return CreateFromMethodInfo (name, new MethodInfo [] {mi}); + } + + internal static XQueryCliFunction CreateFromMethodInfo (MethodInfo [] methods) + { + return CreateFromMethodInfo (null, methods); + } + + internal static XQueryCliFunction CreateFromMethodInfo (XmlQualifiedName name, MethodInfo [] methodList) + { + if (methodList == null || methodList.Length == 0) + throw new ArgumentException (String.Format ("Argument methods is missing or zero-length array. Name is {0}", name)); + + Type cliReturnType = null; + ArrayList arguments = new ArrayList (); + + if (name == null || name == XmlQualifiedName.Empty) + name = new XmlQualifiedName (methodList [0].Name, methodList [0].DeclaringType.FullName); + + int maxArgs = 0; + int minArgs = -1; + Hashtable methods = new Hashtable (); + + foreach (MethodInfo mi in methodList) { + if (cliReturnType == null) + cliReturnType = mi.ReturnType; + else if (mi.ReturnType != cliReturnType) + throw new ArgumentException (String.Format ("Every XQuery functions which share the same name must have the same return type. Method name is {0}.", mi.Name)); + ParameterInfo [] prms = mi.GetParameters (); + + int args = prms.Length; + + // Whether it takes "current context" or not. + Type t = args > 0 ? prms [0].ParameterType : null; + bool ctxSeq = mi.GetCustomAttributes (typeof (XQueryFunctionContextAttribute), false).Length > 0; + bool hasContextArg = ctxSeq || t == typeof (XQueryContext); + if (ctxSeq || hasContextArg) + args--; + if (methods [args] != null) + throw new ArgumentException (String.Format ("XQuery does not allow functions that accepts such methods that have the same number of parameters in different types. Method name is {0}", mi.Name)); + methods.Add ((int) args, mi); + if (args < minArgs || minArgs < 0) + minArgs = args; + if (args > maxArgs) + maxArgs = args; + } + + MethodInfo m = (MethodInfo) methods [(int) maxArgs]; + if (m == null) + throw new SystemException ("Should not happen: maxArgs is " + maxArgs); + ParameterInfo [] pl = m.GetParameters (); + for (int i = 0; i < pl.Length; i++) { + Type t = pl [i].ParameterType; + if (t != typeof (XQueryContext)) + arguments.Add ( + new XQueryFunctionArgument (new XmlQualifiedName (pl [i].Name), SequenceType.Create (pl [i].ParameterType))); + } + + return new XQueryCliFunction (name, + arguments.ToArray (typeof (XQueryFunctionArgument)) as XQueryFunctionArgument [], + SequenceType.Create (cliReturnType), + methods, + minArgs, + maxArgs); + } + + private XQueryCliFunction (XmlQualifiedName name, + XQueryFunctionArgument [] args, + SequenceType returnType, + Hashtable methods, + int minArgs, + int maxArgs) + : base (name, args, returnType) + { + this.methods = methods; + this.maxArgs = maxArgs; + this.minArgs = minArgs; + } + + // instance members + + // [int argsize] -> MethodInfo (according to the spec 1.1, + // there should be no overloads that accepts the same parameter + // count in different types). + Hashtable methods = new Hashtable (); + int maxArgs = 0; + int minArgs = -1; + SequenceType returnType; + + public override int MinArgs { + get { return minArgs; } + } + + public override int MaxArgs { + get { return maxArgs; } + } + + public override object Invoke (XPathSequence current, object [] args) + { + MethodInfo mi = methods [args.Length] as MethodInfo; + if (mi == null) + throw new ArgumentException ("The number of custom function parameter does not match with the registered method's signature."); + ParameterInfo [] prms = mi.GetParameters (); + + // Use Evidence and PermissionSet.Demand() here + // before invoking external function. + Evidence e = current.Context.StaticContext.Evidence; + if (e != null) + SecurityManager.ResolvePolicy (e).Demand (); + + Type t = prms.Length > 0 ? prms [0].ParameterType : null; + bool ctxSeq = mi.GetCustomAttributes ( + typeof (XQueryFunctionContextAttribute), + false).Length > 0; + if (t == typeof (XQueryContext)) { + ArrayList pl = new ArrayList (args); + pl.Insert (0, current.Context); + args = pl.ToArray (); + } + else if (ctxSeq) { + ArrayList pl = new ArrayList (args); + pl.Insert (0, current); + args = pl.ToArray (); + } + + if (args.Length != prms.Length) + throw new XmlQueryException (String.Format ("Argument numbers were different for function {0}. Signature requires {1} while actual call was {2}.", mi.Name, prms.Length, args.Length)); + + // If native parameter type is XPathSequence and the actual values are not, adjust them + for (int i = 0; i < args.Length; i++) { + if (prms [i].ParameterType == typeof (XPathSequence) && !(args [i] is XPathSequence)) { + XPathItem item = args [i] as XPathItem; + if (item == null) + item = args [i] == null ? null : new XPathAtomicValue (args [i], InternalPool.GetBuiltInType (InternalPool.XmlTypeCodeFromRuntimeType (prms [i].ParameterType, true))); + if (item == null) + args [i] = new XPathEmptySequence (current.Context); + else + args [i] = new SingleItemIterator (item, current.Context); + } + } + + return mi.Invoke (null, args); + } + } + +} +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryCommandImpl.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryCommandImpl.cs new file mode 100755 index 00000000000..e77ec257e23 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryCommandImpl.cs @@ -0,0 +1,100 @@ +// +// XQueryCommandImpl.cs - core XQueryCommand implementation in System.Xml.dll +// +// Author: +// Atsushi Enomoto +// +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// + +#if NET_2_0 +using System; +using System.Collections; +using System.IO; +using System.Reflection; +using System.Security.Policy; +using System.Xml; +using System.Xml.Query; +using System.Xml.XPath; +using Mono.Xml.XPath2; +using Mono.Xml.XQuery.Parser; + +namespace Mono.Xml.XPath2 +{ + public class XQueryCommandImpl + { + MethodInfo xqueryCommandOnMessageEventMethod; + + MethodInfo GetEventHandler (object qobj) + { + if (xqueryCommandOnMessageEventMethod == null) { + EventInfo ei = qobj.GetType ().GetEvent ("OnMessageEvent"); + xqueryCommandOnMessageEventMethod = ei.GetRaiseMethod (true); + } + return xqueryCommandOnMessageEventMethod; + } + + XQueryStaticContext staticContext; + object xqueryCommand; + + public XQueryCommandImpl () + { + } + + public void Compile (TextReader input, Evidence evidence, object xqueryCommand) + { + staticContext = XQueryASTCompiler.Compile (XQueryParser.Parse (input), null, evidence, this); + this.xqueryCommand = xqueryCommand; + // FIXME: generate executable assembly, and load it with evidence. + } + + public void Execute (XPathNavigator input, XmlResolver resolver, XmlArgumentList args, XmlWriter writer) + { + if (staticContext == null) + throw new XmlQueryException ("Query string is not compiled."); + // Initialize event handler method info. + xqueryCommandOnMessageEventMethod = null; + + XQueryContext ctx = new XQueryContext (new XQueryContextManager (staticContext, input, writer, resolver, args)); + + XPathSequence iter = new SingleItemIterator (input, ctx); + + foreach (ExprSingle expr in staticContext.QueryBody) + expr.Serialize (iter); + } + + internal void ProcessMessageEvent (object sender, QueryEventArgs e) + { + // FIXME: how to handle event raise method? + throw new NotImplementedException (); + /* + MethodInfo mi = GetEventHandler (xqueryCommand); + if (mi != null) + mi.Invoke (xqueryCommand, new object [] {sender, e}); + */ + } + } + +} + +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryComparisonOperator.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryComparisonOperator.cs new file mode 100755 index 00000000000..c7f7301afb5 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryComparisonOperator.cs @@ -0,0 +1,235 @@ +// +// XQueryComparisonOperator.cs +// +// Author: +// Atsushi Enomoto +// +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// + +#if NET_2_0 +using System; +using System.Collections; +using System.Reflection; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Query; +using System.Xml.XPath; +using System.Xml.Xsl; + +namespace Mono.Xml.XPath2 +{ + // FIXME: Handle complete type promotion and subtype substitution. + // See XQuery 1.0 Appendix B.*. + public class XQueryComparisonOperator + { + private static bool OpBooleanLessThan (bool b1, bool b2) + { + return !b1 && b2; + } + + private static bool OpBooleanGreaterThan (bool b1, bool b2) + { + return b1 && !b2; + } + + private static bool CompareEquality (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + switch (lvalue.XmlType.TypeCode) { + case XmlTypeCode.Boolean: + return lvalue.ValueAsBoolean == rvalue.ValueAsBoolean; + case XmlTypeCode.UntypedAtomic: + case XmlTypeCode.String: + return lvalue.Value == rvalue.Value; + case XmlTypeCode.Date: + case XmlTypeCode.Time: + case XmlTypeCode.DateTime: + case XmlTypeCode.YearMonthDuration: + case XmlTypeCode.DayTimeDuration: + return lvalue.ValueAsDateTime == rvalue.ValueAsDateTime; + case XmlTypeCode.HexBinary: + case XmlTypeCode.Base64Binary: + case XmlTypeCode.AnyUri: + case XmlTypeCode.QName: + case XmlTypeCode.Notation: + throw new NotImplementedException (); + } + XmlQualifiedName nameL = lvalue.XmlType.QualifiedName != XmlQualifiedName.Empty ? lvalue.XmlType.QualifiedName : new XmlQualifiedName ("anyType", XmlSchema.Namespace); + XmlQualifiedName nameR = rvalue.XmlType.QualifiedName != XmlQualifiedName.Empty ? rvalue.XmlType.QualifiedName : new XmlQualifiedName ("anyType", XmlSchema.Namespace); + throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", nameL, nameR)); + } + + public static bool ValueEQ (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + if (lvalue.XmlType.TypeCode == XmlTypeCode.Decimal && + rvalue.XmlType.TypeCode == XmlTypeCode.Decimal) + return lvalue.ValueAsDecimal == rvalue.ValueAsDecimal; + if (SequenceType.IsNumeric (lvalue.XmlType.TypeCode) && + SequenceType.IsNumeric (lvalue.XmlType.TypeCode)) + return lvalue.ValueAsDouble == rvalue.ValueAsDouble; + if (lvalue.XmlType.TypeCode == rvalue.XmlType.TypeCode) + return CompareEquality (lvalue, rvalue); + + throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName)); + } + + public static bool ValueNE (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + if (lvalue.XmlType.TypeCode == XmlTypeCode.Decimal && + rvalue.XmlType.TypeCode == XmlTypeCode.Decimal) + return lvalue.ValueAsDecimal != rvalue.ValueAsDecimal; + if (SequenceType.IsNumeric (lvalue.XmlType.TypeCode) && + SequenceType.IsNumeric (lvalue.XmlType.TypeCode)) + return lvalue.ValueAsDouble != rvalue.ValueAsDouble; + if (lvalue.XmlType.TypeCode == rvalue.XmlType.TypeCode) + return !CompareEquality (lvalue, rvalue); + + throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName)); + } + + private static bool CompareLT (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + switch (lvalue.XmlType.TypeCode) { + case XmlTypeCode.Boolean: + return OpBooleanLessThan (lvalue.ValueAsBoolean, rvalue.ValueAsBoolean); + case XmlTypeCode.String: + return lvalue.Value == rvalue.Value; + case XmlTypeCode.Date: + case XmlTypeCode.Time: + case XmlTypeCode.DateTime: + case XmlTypeCode.YearMonthDuration: + case XmlTypeCode.DayTimeDuration: + return lvalue.ValueAsDateTime < rvalue.ValueAsDateTime; + } + throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName)); + } + + public static bool ValueLT (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + if (lvalue.XmlType.TypeCode == XmlTypeCode.Decimal && + rvalue.XmlType.TypeCode == XmlTypeCode.Decimal) + return lvalue.ValueAsDecimal < rvalue.ValueAsDecimal; + if (SequenceType.IsNumeric (lvalue.XmlType.TypeCode) && + SequenceType.IsNumeric (lvalue.XmlType.TypeCode)) + return lvalue.ValueAsDouble < rvalue.ValueAsDouble; + if (lvalue.XmlType.TypeCode == rvalue.XmlType.TypeCode) + return CompareLT (lvalue, rvalue); + + throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName)); + } + + private static bool CompareLE (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + switch (lvalue.XmlType.TypeCode) { + case XmlTypeCode.Boolean: + return !OpBooleanGreaterThan (lvalue.ValueAsBoolean, rvalue.ValueAsBoolean); + case XmlTypeCode.String: + return lvalue.Value == rvalue.Value; + case XmlTypeCode.Date: + case XmlTypeCode.Time: + case XmlTypeCode.DateTime: + case XmlTypeCode.YearMonthDuration: + case XmlTypeCode.DayTimeDuration: + return lvalue.ValueAsDateTime <= rvalue.ValueAsDateTime; + } + throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName)); + } + + public static bool ValueLE (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + if (lvalue.XmlType.TypeCode == XmlTypeCode.Decimal && + rvalue.XmlType.TypeCode == XmlTypeCode.Decimal) + return lvalue.ValueAsDecimal <= rvalue.ValueAsDecimal; + if (SequenceType.IsNumeric (lvalue.XmlType.TypeCode) && + SequenceType.IsNumeric (lvalue.XmlType.TypeCode)) + return lvalue.ValueAsDouble <= rvalue.ValueAsDouble; + if (lvalue.XmlType.TypeCode == rvalue.XmlType.TypeCode) + return CompareLE (lvalue, rvalue); + + throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName)); + } + + private static bool CompareGT (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + switch (lvalue.XmlType.TypeCode) { + case XmlTypeCode.Boolean: + return OpBooleanGreaterThan (lvalue.ValueAsBoolean, rvalue.ValueAsBoolean); + case XmlTypeCode.String: + return lvalue.Value == rvalue.Value; + case XmlTypeCode.Date: + case XmlTypeCode.Time: + case XmlTypeCode.DateTime: + case XmlTypeCode.YearMonthDuration: + case XmlTypeCode.DayTimeDuration: + return lvalue.ValueAsDateTime > rvalue.ValueAsDateTime; + } + throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName)); + } + + public static bool ValueGT (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + if (lvalue.XmlType.TypeCode == XmlTypeCode.Decimal && + rvalue.XmlType.TypeCode == XmlTypeCode.Decimal) + return lvalue.ValueAsDecimal > rvalue.ValueAsDecimal; + if (SequenceType.IsNumeric (lvalue.XmlType.TypeCode) && + SequenceType.IsNumeric (lvalue.XmlType.TypeCode)) + return lvalue.ValueAsDouble > rvalue.ValueAsDouble; + if (lvalue.XmlType.TypeCode == rvalue.XmlType.TypeCode) + return CompareGT (lvalue, rvalue); + + throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName)); + } + + private static bool CompareGE (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + switch (lvalue.XmlType.TypeCode) { + case XmlTypeCode.Boolean: + return !OpBooleanLessThan (lvalue.ValueAsBoolean, rvalue.ValueAsBoolean); + case XmlTypeCode.String: + return lvalue.Value == rvalue.Value; + case XmlTypeCode.Date: + case XmlTypeCode.Time: + case XmlTypeCode.DateTime: + case XmlTypeCode.YearMonthDuration: + case XmlTypeCode.DayTimeDuration: + return lvalue.ValueAsDateTime >= rvalue.ValueAsDateTime; + } + throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName)); + } + + public static bool ValueGE (XPathAtomicValue lvalue, XPathAtomicValue rvalue) + { + if (lvalue.XmlType.TypeCode == XmlTypeCode.Decimal && + rvalue.XmlType.TypeCode == XmlTypeCode.Decimal) + return lvalue.ValueAsDecimal >= rvalue.ValueAsDecimal; + if (SequenceType.IsNumeric (lvalue.XmlType.TypeCode) && + SequenceType.IsNumeric (lvalue.XmlType.TypeCode)) + return lvalue.ValueAsDouble >= rvalue.ValueAsDouble; + if (lvalue.XmlType.TypeCode == rvalue.XmlType.TypeCode) + return CompareGE (lvalue, rvalue); + + throw new XmlQueryException (String.Format ("Not allowed value comparison between {0} and {1}.", lvalue.XmlType.QualifiedName, rvalue.XmlType.QualifiedName)); + } + } +} +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryCompileContext.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryCompileContext.cs new file mode 100755 index 00000000000..c49d8f194b5 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryCompileContext.cs @@ -0,0 +1,93 @@ +// +// XQueryCompileContext.cs +// +// Author: +// Atsushi Enomoto +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// + +#if NET_2_0 + +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Xml; +using System.Xml.Query; +using System.Xml.Schema; +using Mono.Xml.XPath2; + +namespace Mono.Xml.XPath2 +{ + // Holds dynamic compile context that is shared between one or more + // compilers that are created during one XQueryCommand.Compile(). + internal class XQueryCompileContext + { + public XQueryCompileContext () + { + schemaCache = new Hashtable (); + moduleCache = new Hashtable (); + + inEffectSchemas = new XmlSchemaSet (); + inEffectVariables = new Hashtable (); + inEffectFunctions = new XQueryFunctionTable (); + } + + // Compiled schema table; It is used to avoid multiple time + // compilation of the same schemas that is likely to happen + // when a library module is divided into multiple files. + // [location string] -> XmlSchema (done) or null (not). + IDictionary schemaCache; + // ditto for local module resources. + // [location] -> XQueryLibraryModule (done) or null (not). + IDictionary moduleCache; + + // Collects the whole schemas, variables and functions. + XmlSchemaSet inEffectSchemas; + Hashtable inEffectVariables; + XQueryFunctionTable inEffectFunctions; + + public IDictionary SchemaCache { + get { return schemaCache; } + } + + public IDictionary ModuleCache { + get { return moduleCache; } + } + + // Compilation results + + public XmlSchemaSet InEffectSchemas { + get { return inEffectSchemas; } + } + + public Hashtable InEffectVariables { + get { return inEffectVariables; } + } + + public XQueryFunctionTable InEffectFunctions { + get { return inEffectFunctions; } + } + } +} + +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryCompileOptions.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryCompileOptions.cs new file mode 100755 index 00000000000..b4e0f8192aa --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryCompileOptions.cs @@ -0,0 +1,101 @@ +// +// XQueryCompileOptions.cs - XQuery compiler option stucture. +// +// Author: +// Atsushi Enomoto +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// + +#if NET_2_0 + +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Globalization; +using System.Xml; +using System.Xml.Query; +using System.Xml.Schema; +using Mono.Xml.XPath2; + +namespace Mono.Xml.XPath2 +{ + public class XQueryCompileOptions + { + public XQueryCompileOptions () + : this (new NameTable (), null) + { + } + + public XQueryCompileOptions (XmlNameTable nameTable, CultureInfo defaultCollation) + { + this.nameTable = nameTable; + this.defaultCollation = defaultCollation; + if (this.defaultCollation == null) + this.defaultCollation = CultureInfo.InvariantCulture; + + knownCollections = new Hashtable (); + } + + XmlNameTable nameTable; + XmlQueryDialect compat; + CultureInfo defaultCollation; + Hashtable knownCollections; + bool xqueryFlagger; + bool xqueryStaticFlagger; + + // XPath 1.0 Compatibility Mode. + public XmlQueryDialect Compatibility { + get { return compat; } + set { compat = value; } + } + + public XmlNameTable NameTable { + get { return nameTable; } + set { nameTable = value; } + } + + public CultureInfo DefaultCollation { + get { return defaultCollation; } + set { defaultCollation = value; } + } + + // FIXME: implement + public bool XQueryFlagger { + get { return xqueryFlagger; } + set { xqueryFlagger = value; } + } + + // FIXME: implement + public bool XQueryStaticFlagger { + get { return xqueryStaticFlagger; } + set { xqueryStaticFlagger = value; } + } + + // FIXME: implement + public Hashtable KnownCollections { + get { return knownCollections; } + } + } +} + +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryContext.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryContext.cs new file mode 100755 index 00000000000..c4367efcb80 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryContext.cs @@ -0,0 +1,318 @@ +// +// XQueryContext.cs - XQuery/XPath2 dynamic context +// +// Author: +// Atsushi Enomoto +// +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// +#if NET_2_0 +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Xml; +using System.Xml.Schema; +using System.Xml.XPath; +using System.Xml.Query; +using Mono.Xml; + +namespace Mono.Xml.XPath2 +{ + internal class XQueryContextManager + { + XQueryStaticContext staticContext; + + // Fixed dynamic context during evaluation + XmlArgumentList args; + XmlResolver extDocResolver; + + Stack contextStack = new Stack (); + XQueryContext currentContext; +#if SEEMS_CONTEXT_FOR_CURRENT_REQURED +#else + Stack contextSequenceStack = new Stack (); +#endif + XmlWriter currentWriter; + XPathItem input; // source input item(node) + XPathSequence currentSequence; + XmlNamespaceManager namespaceManager; + Hashtable localCollationCache = new Hashtable (); + + internal XQueryContextManager (XQueryStaticContext ctx, XPathItem input, XmlWriter writer, XmlResolver resolver, XmlArgumentList args) + { + this.input = input; + this.staticContext = ctx; + this.args = args; + currentWriter = writer; + this.extDocResolver = resolver; + + namespaceManager = new XmlNamespaceManager (ctx.NameTable); + foreach (DictionaryEntry de in ctx.NSResolver.GetNamespacesInScope (XmlNamespaceScope.ExcludeXml)) + namespaceManager.AddNamespace (de.Key.ToString (), de.Value.ToString ()); + namespaceManager.PushScope (); + + currentContext = new XQueryContext (this, null, new Hashtable ()); + if (input != null) { + currentSequence = new SingleItemIterator (input, currentContext); + currentSequence.MoveNext (); + } + currentContext = new XQueryContext (this, currentSequence, new Hashtable ()); + } + + public bool Initialized { + get { return currentContext != null; } + } + + public XmlResolver ExtDocResolver { + get { return extDocResolver; } + } + + public XmlArgumentList Arguments { + get { return args; } + } + + public XmlWriter Writer { + get { return currentWriter; } + // FIXME: might be better avoid setter as public + set { currentWriter = value; } + } + + internal XQueryContext CurrentContext { + get { return currentContext; } + } + + internal XQueryStaticContext StaticContext { + get { return staticContext; } + } + + internal CultureInfo GetCulture (string collation) + { + CultureInfo ci = staticContext.GetCulture (collation); + if (ci == null) + ci = (CultureInfo) localCollationCache [collation]; + if (ci != null) + return ci; + ci = new CultureInfo (collation); + localCollationCache [collation] = ci; + return ci; + } + + public void PushCurrentSequence (XPathSequence sequence) + { + if (sequence == null) + throw new ArgumentNullException (); +// sequence = sequence.Clone (); +#if SEEMS_CONTEXT_FOR_CURRENT_REQURED + contextStack.Push (currentContext); + currentsequence = sequence; + currentContext = new XQueryContext (this); +#else + contextSequenceStack.Push (currentSequence); + currentSequence = sequence; +#endif + } + + public void PopCurrentSequence () + { +#if SEEMS_CONTEXT_FOR_CURRENT_REQURED + PopContext (); +#else + currentSequence = contextSequenceStack.Pop (); +#endif + if (currentSequence == null) + throw new SystemException ("XQuery error: should not happen."); + } + + internal void PushContext () + { + contextStack.Push (currentContext); + currentContext = new XQueryContext (this); + } + + internal void PopContext () + { + currentContext = contextStack.Pop (); + } + + internal void PushVariable (XmlQualifiedName name, object iter) + { + PushContext (); + CurrentContext.SetVariable (name, iter); + } + + internal void PopVariable () + { + PopContext (); + } + + internal XmlNamespaceManager NSManager { + get { return namespaceManager; } + } + + internal XPathSequence CurrentSequence { + get { return currentSequence; } + } + } + + public class XQueryContext : IXmlNamespaceResolver + { + XQueryContextManager contextManager; + Hashtable currentVariables; + XPathSequence currentSequence; + + internal XQueryContext (XQueryContextManager manager) + : this (manager, + manager.CurrentSequence, + (Hashtable) manager.CurrentContext.currentVariables.Clone ()) + { + } + + internal XQueryContext (XQueryContextManager manager, XPathSequence currentSequence, Hashtable currentVariables) + { + contextManager = manager; + this.currentSequence = currentSequence; +/* + if (manager.CurrentContext != null) + currentVariables = (Hashtable) manager.CurrentContext.currentVariables.Clone (); + else + currentVariables = new Hashtable (); +*/ + this.currentVariables = currentVariables; + } + + internal XmlWriter Writer { + get { return contextManager.Writer; } + // FIXME: might be better avoid public setter. + set { contextManager.Writer = value; } + } + + internal XQueryStaticContext StaticContext { + get { return contextManager.StaticContext; } + } + + internal CultureInfo DefaultCollation { + get { return StaticContext.DefaultCollation; } + } + + internal XQueryContextManager ContextManager { + get { return contextManager; } + } + + public XPathItem CurrentItem { + get { + if (currentSequence == null) + throw new XmlQueryException ("This XQuery dynamic context has no context item."); + return CurrentSequence.Current; + } + } + + public XPathNavigator CurrentNode { + get { return CurrentItem as XPathNavigator; } + } + + public XPathSequence CurrentSequence { + get { return currentSequence; } + } + + internal CultureInfo GetCulture (string collation) + { + return contextManager.GetCulture (collation); + } + + internal void PushVariable (XmlQualifiedName name, object iter) + { + contextManager.PushVariable (name, iter); + } + + // FIXME: Hmm... this design is annoying. + internal void SetVariable (XmlQualifiedName name, object iter) + { + currentVariables [name] = iter; + } + + internal void PopVariable () + { + contextManager.PopVariable (); + } + + internal XPathSequence ResolveVariable (XmlQualifiedName name) + { + object obj = currentVariables [name]; + if (obj == null && contextManager.Arguments != null) + obj = contextManager.Arguments.GetParameter (name.Name, name.Namespace); + if (obj == null) + return new XPathEmptySequence (this); + XPathSequence seq = obj as XPathSequence; + if (seq != null) + return seq; + XPathItem item = obj as XPathItem; + if (item == null) + item = new XPathAtomicValue (obj, InternalPool.GetBuiltInType (InternalPool.XmlTypeCodeFromRuntimeType (obj.GetType (), true))); + return new SingleItemIterator (item, this); + } + + internal XPathSequence ResolveCollection (string name) + { + // FIXME: support later. + return new XPathEmptySequence (currentSequence.Context); + } + + public IXmlNamespaceResolver NSResolver { + get { return contextManager.NSManager; } + } + + #region IXmlNamespaceResolver implementation + public XmlNameTable NameTable { + get { return contextManager.NSManager.NameTable; } + } + + public string LookupPrefix (string ns) + { + return contextManager.NSManager.LookupPrefix (ns); + } + + public string LookupPrefix (string ns, bool atomized) + { + return contextManager.NSManager.LookupPrefix (ns, atomized); + } + + public string LookupNamespace (string prefix) + { + return contextManager.NSManager.LookupNamespace (prefix); + } + + public string LookupNamespace (string prefix, bool atomized) + { + return contextManager.NSManager.LookupNamespace (prefix, atomized); + } + + public IDictionary GetNamespacesInScope (XmlNamespaceScope scope) + { + return contextManager.NSManager.GetNamespacesInScope (scope); + } + #endregion + } +} + +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryConvert.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryConvert.cs new file mode 100755 index 00000000000..6e1109c5aef --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryConvert.cs @@ -0,0 +1,1021 @@ +// +// System.Xml.Query.XQueryConvert +// +// Author: +// Atsushi Enomoto +// +// Copyright (C) 2004 Novell Inc. +// + +// +// 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. +// +#if NET_2_0 + +using System; +using System.Globalization; +using System.IO; +using System.Text; +using System.Xml; +using System.Xml.Schema; +using System.Xml.XPath; + +namespace System.Xml +{ + internal class XQueryConvert // Won't be public in the final stage + { + [MonoTODO] + public static bool ShouldCheckValueFacets (XmlSchemaType schemaTypeDest) + { + throw new NotImplementedException (); + } + + public static XmlTypeCode GetFallbackType (XmlTypeCode type) + { + switch (type) { + case XmlTypeCode.AnyAtomicType: + return XmlTypeCode.Item; + case XmlTypeCode.UntypedAtomic: + return XmlTypeCode.String; + case XmlTypeCode.Notation: + return XmlTypeCode.QName; + case XmlTypeCode.NormalizedString: + case XmlTypeCode.Token: + case XmlTypeCode.Language: + case XmlTypeCode.NmToken: + case XmlTypeCode.Name: + case XmlTypeCode.NCName: + case XmlTypeCode.Id: + case XmlTypeCode.Idref: + case XmlTypeCode.Entity: + return XmlTypeCode.String; + case XmlTypeCode.NonPositiveInteger: + return XmlTypeCode.Decimal; + case XmlTypeCode.NegativeInteger: + return XmlTypeCode.NonPositiveInteger; + case XmlTypeCode.Long: + return XmlTypeCode.Integer; + case XmlTypeCode.Short: + return XmlTypeCode.Int; + case XmlTypeCode.Byte: + return XmlTypeCode.Int; + case XmlTypeCode.NonNegativeInteger: + return XmlTypeCode.Decimal; + case XmlTypeCode.UnsignedLong: + return XmlTypeCode.NonNegativeInteger; + case XmlTypeCode.UnsignedInt: + return XmlTypeCode.Integer; + case XmlTypeCode.UnsignedShort: + return XmlTypeCode.Int; + case XmlTypeCode.UnsignedByte: + return XmlTypeCode.UnsignedShort; + case XmlTypeCode.PositiveInteger: + return XmlTypeCode.NonNegativeInteger; + default: + return XmlTypeCode.None; + } + } + + [MonoTODO] + // See XQuery & XPath 2.0 functions & operators section 17. + public static bool CanConvert (XPathItem item, XmlSchemaType schemaTypeDest) + { + if (item == null) + throw new ArgumentNullException ("item"); + if (schemaTypeDest == null) + throw new ArgumentNullException ("schemaTypeDest"); + XmlTypeCode src = item.XmlType.TypeCode; + XmlTypeCode dst = schemaTypeDest.TypeCode; + + // Notation cannot be converted from other than Notation + if (src == XmlTypeCode.Notation && dst != XmlTypeCode.Notation) + return false; + + // untypedAtomic and string are convertable unless source type is QName. + switch (dst) { + case XmlTypeCode.UntypedAtomic: + case XmlTypeCode.String: + return src != XmlTypeCode.QName; + } + + switch (src) { + case XmlTypeCode.None: + case XmlTypeCode.Item: + case XmlTypeCode.Node: + case XmlTypeCode.Document: + case XmlTypeCode.Element: + case XmlTypeCode.Attribute: + case XmlTypeCode.Namespace: + case XmlTypeCode.ProcessingInstruction: + case XmlTypeCode.Comment: + case XmlTypeCode.Text: + throw new NotImplementedException (); // FIXME: check what happens + + case XmlTypeCode.AnyAtomicType: + throw new NotImplementedException (); // FIXME: check what happens + case XmlTypeCode.UntypedAtomic: + case XmlTypeCode.String: + // 'M' + throw new NotImplementedException (); // FIXME: check what happens + + case XmlTypeCode.Boolean: + case XmlTypeCode.Decimal: + switch (dst) { + case XmlTypeCode.Float: + case XmlTypeCode.Double: + case XmlTypeCode.Decimal: + case XmlTypeCode.Boolean: + return true; + } + return false; + + case XmlTypeCode.Float: + case XmlTypeCode.Double: + if (dst == XmlTypeCode.Decimal) + // 'M' + throw new NotImplementedException (); // FIXME: check what happens + goto case XmlTypeCode.Decimal; + + case XmlTypeCode.Duration: + switch (dst) { + case XmlTypeCode.Duration: + case XmlTypeCode.YearMonthDuration: + case XmlTypeCode.DayTimeDuration: + return true; + } + return false; + + case XmlTypeCode.DateTime: + switch (dst) { + case XmlTypeCode.DateTime: + case XmlTypeCode.Time: + case XmlTypeCode.Date: + case XmlTypeCode.GYearMonth: + case XmlTypeCode.GYear: + case XmlTypeCode.GMonthDay: + case XmlTypeCode.GDay: + case XmlTypeCode.GMonth: + return true; + } + return false; + + case XmlTypeCode.Time: + switch (dst) { + case XmlTypeCode.Time: + case XmlTypeCode.Date: + return true; + } + return false; + + case XmlTypeCode.Date: + if (dst == XmlTypeCode.Time) + return false; + goto case XmlTypeCode.DateTime; + + case XmlTypeCode.GYearMonth: + case XmlTypeCode.GYear: + case XmlTypeCode.GMonthDay: + case XmlTypeCode.GDay: + case XmlTypeCode.GMonth: + return src == dst; + + case XmlTypeCode.HexBinary: + case XmlTypeCode.Base64Binary: + if (src == dst) + return true; + switch (dst) { + case XmlTypeCode.HexBinary: + case XmlTypeCode.Base64Binary: + return true; + } + return false; + + case XmlTypeCode.AnyUri: + case XmlTypeCode.QName: + case XmlTypeCode.Notation: + return src == dst; + + case XmlTypeCode.NormalizedString: + case XmlTypeCode.Token: + case XmlTypeCode.Language: + case XmlTypeCode.NmToken: + case XmlTypeCode.Name: + case XmlTypeCode.NCName: + case XmlTypeCode.Id: + case XmlTypeCode.Idref: + case XmlTypeCode.Entity: + case XmlTypeCode.Integer: + case XmlTypeCode.NonPositiveInteger: + case XmlTypeCode.NegativeInteger: + case XmlTypeCode.Long: + case XmlTypeCode.Int: + case XmlTypeCode.Short: + case XmlTypeCode.Byte: + case XmlTypeCode.NonNegativeInteger: + case XmlTypeCode.UnsignedLong: + case XmlTypeCode.UnsignedInt: + case XmlTypeCode.UnsignedShort: + case XmlTypeCode.UnsignedByte: + case XmlTypeCode.PositiveInteger: + throw new NotImplementedException (); + + // xdt:* + case XmlTypeCode.YearMonthDuration: + if (dst == XmlTypeCode.DayTimeDuration) + return false; + goto case XmlTypeCode.Duration; + case XmlTypeCode.DayTimeDuration: + if (dst == XmlTypeCode.YearMonthDuration) + return false; + goto case XmlTypeCode.Duration; + } + + throw new NotImplementedException (); + } + + // Individual conversion + + public static string AnyUriToString (string value) + { + return value; + } + + public static byte [] Base64BinaryToHexBinary (byte [] value) + { + return XmlConvert.FromBinHexString (Convert.ToBase64String (value)); + } + + public static string Base64BinaryToString (byte [] value) + { + return Convert.ToBase64String (value); + } + + public static decimal BooleanToDecimal (bool value) + { + return Convert.ToDecimal (value); + } + + public static double BooleanToDouble (bool value) + { + return Convert.ToDouble (value); + } + + public static float BooleanToFloat (bool value) + { + return Convert.ToSingle (value); + } + + public static int BooleanToInt (bool value) + { + return Convert.ToInt32 (value); + } + + public static long BooleanToInteger (bool value) + { + return Convert.ToInt64 (value); + } + + public static string BooleanToString (bool value) + { + // It looks not returning "True" + return value ? "true" : "false"; + } + + [MonoTODO] + public static DateTime DateTimeToDate (DateTime value) + { + return value.Date; + } + + [MonoTODO] + public static DateTime DateTimeToGDay (DateTime value) + { + return new DateTime (0, 0, value.Day); + } + + [MonoTODO] + public static DateTime DateTimeToGMonth (DateTime value) + { + return new DateTime (0, value.Month, 0); + } + + [MonoTODO] + public static DateTime DateTimeToGYear (DateTime value) + { + return new DateTime (value.Year, 0, 0); + } + + [MonoTODO] + public static DateTime DateTimeToGYearMonth (DateTime value) + { + return new DateTime (value.Year, value.Month, 0); + } + + [MonoTODO] + public static DateTime DateToDateTime (DateTime value) + { + return value.Date; + } + + [MonoTODO] + public static DateTime DateToGDay (DateTime value) + { + return new DateTime (0, 0, value.Day); + } + + [MonoTODO] + public static DateTime DateToGMonth (DateTime value) + { + return new DateTime (0, value.Month, 0); + } + + [MonoTODO] + public static DateTime DateToGYear (DateTime value) + { + return new DateTime (value.Year, 0, 0); + } + + [MonoTODO] + public static DateTime DateToGYearMonth (DateTime value) + { + return new DateTime (value.Year, value.Month, 0); + } + + [MonoTODO] + public static string DateToString (DateTime value) + { + return XmlConvert.ToString (value); + } + + [MonoTODO] + public static string DateTimeToString (DateTime value) + { + return XmlConvert.ToString (value); + } + + [MonoTODO] + public static string DayTimeDurationToDuration (TimeSpan value) + { + return XmlConvert.ToString (value); + } + + [MonoTODO] + public static string DayTimeDurationToString (TimeSpan value) + { + return DayTimeDurationToDuration (value); + } + + [MonoTODO] + public static bool DecimalToBoolean (decimal value) + { + return value != 0; + } + + [MonoTODO] + public static double DecimalToDouble (decimal value) + { + return (double) value; + } + + [MonoTODO] + public static float DecimalToFloat (decimal value) + { + return (float) value; + } + + [MonoTODO] + public static int DecimalToInt (decimal value) + { + return (int) value; + } + + [MonoTODO] + public static long DecimalToInteger (decimal value) + { + return (long) value; + } + + [MonoTODO] // what if value was negative? + public static decimal DecimalToNonNegativeInteger (decimal value) + { + throw new NotImplementedException (); + } + + [MonoTODO] // what if value was positive? + public static decimal DecimalToNonPositiveInteger (decimal value) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public static string DecimalToString (decimal value) + { + return XmlConvert.ToString (value); + } + + [MonoTODO] + public static bool DoubleToBoolean (double value) + { + return value != 0; + } + + [MonoTODO] + public static decimal DoubleToDecimal (double value) + { + return (decimal) value; + } + + [MonoTODO] + public static float DoubleToFloat (double value) + { + return (float) value; + } + + [MonoTODO] + public static int DoubleToInt (double value) + { + return (int) value; + } + + [MonoTODO] + public static long DoubleToInteger (double value) + { + return (long) value; + } + + [MonoTODO] // what if value was negative? + public static decimal DoubleToNonNegativeInteger (double value) + { + throw new NotImplementedException (); + } + + [MonoTODO] // what if value was positive? + public static decimal DoubleToNonPositiveInteger (double value) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public static string DoubleToString (double value) + { + return XmlConvert.ToString (value); + } + + [MonoTODO] + public static TimeSpan DurationToDayTimeDuration (string value) + { + return XmlConvert.ToTimeSpan (value); + } + + [MonoTODO] + public static string DurationToString (string value) + { + return XmlConvert.ToString (XmlConvert.ToTimeSpan (value)); + } + + [MonoTODO] + public static TimeSpan DurationToYearMonthDuration (string value) + { + return XmlConvert.ToTimeSpan (value); + } + + + [MonoTODO] + public static bool FloatToBoolean (float value) + { + return value != 0; + } + + [MonoTODO] + public static decimal FloatToDecimal (float value) + { + return (decimal) value; + } + + [MonoTODO] + public static double FloatToDouble (float value) + { + return (double) value; + } + + [MonoTODO] + public static int FloatToInt (float value) + { + return (int) value; + } + + [MonoTODO] + public static long FloatToInteger (float value) + { + return (long) value; + } + + [MonoTODO] // what if value was negative? + public static decimal FloatToNonNegativeInteger (float value) + { + throw new NotImplementedException (); + } + + [MonoTODO] // what if value was positive? + public static decimal FloatToNonPositiveInteger (float value) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public static string FloatToString (float value) + { + return XmlConvert.ToString (value); + } + + [MonoTODO] + public static string GDayToString (DateTime value) + { + return XmlConvert.ToString (TimeSpan.FromDays (value.Day)); + } + + [MonoTODO] + public static string GMonthDayToString (DateTime value) + { + return XmlConvert.ToString (new TimeSpan (value.Day, value.Hour, value.Minute, value.Second)); + } + + [MonoTODO] + public static string GMonthToString (DateTime value) + { + return XmlConvert.ToString (new TimeSpan (0, value.Month, 0)); + } + + [MonoTODO] + public static string GYearMonthToString (DateTime value) + { + return XmlConvert.ToString (new TimeSpan (value.Year, value.Month, 0)); + } + + [MonoTODO] + public static string GYearToString (DateTime value) + { + return XmlConvert.ToString (new TimeSpan (new DateTime (value.Year, 0, 0).Ticks)); + } + + public static string HexBinaryToString (byte [] data) + { + return XmlConvert.ToBinHexString (data); + } + + public static string HexBinaryToBase64String (byte [] data) + { + return XmlConvert.ToBinHexString (data); + } + + + [MonoTODO] + public static bool IntegerToBoolean (long value) + { + return value != 0; + } + + [MonoTODO] + public static decimal IntegerToDecimal (long value) + { + return (decimal) value; + } + + [MonoTODO] + public static double IntegerToDouble (long value) + { + return (double) value; + } + + [MonoTODO] + public static float IntegerToFloat (long value) + { + return (float) value; + } + + [MonoTODO] + public static int IntegerToInt (long value) + { + return (int) value; + } + + [MonoTODO] + public static string IntegerToString (long value) + { + return XmlConvert.ToString (value); + } + + [MonoTODO] + public static bool IntToBoolean (int value) + { + return value != 0; + } + + [MonoTODO] + public static decimal IntToDecimal (int value) + { + return (decimal) value; + } + + [MonoTODO] + public static double IntToDouble (int value) + { + return (double) value; + } + + [MonoTODO] + public static float IntToFloat (int value) + { + return (float) value; + } + + [MonoTODO] + public static long IntToInteger (int value) + { + return (long) value; + } + + [MonoTODO] + public static string IntToString (int value) + { + return XmlConvert.ToString (value); + } + + [MonoTODO] + public static string NonNegativeIntegerToString (decimal value) + { + return XmlConvert.ToString (value); + } + + [MonoTODO] + public static string NonPositiveIntegerToString (decimal value) + { + return XmlConvert.ToString (value); + } + + [MonoTODO] + public static DateTime TimeToDateTime (DateTime value) + { + return value; + } + + [MonoTODO] + public static string TimeToString (DateTime value) + { + return XmlConvert.ToString (value, "HH:mm:ssZ"); + } + + [MonoTODO] + public static string YearMonthDurationToDuration (TimeSpan value) + { + return XmlConvert.ToString (value); + } + + [MonoTODO] + public static string YearMonthDurationToString (TimeSpan value) + { + return YearMonthDurationToDuration (value); + } + + [MonoTODO] + public static string StringToAnyUri (string value) + { + return value; + } + + [MonoTODO] + public static byte [] StringToBase64Binary (string value) + { + return Convert.FromBase64String (value); + } + + [MonoTODO] + public static bool StringToBoolean (string value) + { + return XmlConvert.ToBoolean (value); + } + + [MonoTODO] + public static DateTime StringToDate (string value) + { + return XmlConvert.ToDateTime (value); + } + + [MonoTODO] + public static DateTime StringToDateTime (string value) + { + return XmlConvert.ToDateTime (value); + } + + [MonoTODO] + public static TimeSpan StringToDayTimeDuration (string value) + { + return XmlConvert.ToTimeSpan (value); + } + + [MonoTODO] + public static decimal StringToDecimal (string value) + { + return XmlConvert.ToDecimal (value); + } + + [MonoTODO] + public static double StringToDouble (string value) + { + return XmlConvert.ToDouble (value); + } + + [MonoTODO] + public static string StringToDuration (string value) + { + return XmlConvert.ToString (XmlConvert.ToTimeSpan (value)); + } + + [MonoTODO] + public static float StringToFloat (string value) + { + return XmlConvert.ToSingle (value); + } + + [MonoTODO] + public static DateTime StringToGDay (string value) + { + return XmlConvert.ToDateTime (value); + } + + [MonoTODO] + public static DateTime StringToGMonth (string value) + { + return XmlConvert.ToDateTime (value); + } + + [MonoTODO] + public static DateTime StringToGMonthDay (string value) + { + return XmlConvert.ToDateTime (value); + } + + [MonoTODO] + public static DateTime StringToGYear (string value) + { + return XmlConvert.ToDateTime (value); + } + + [MonoTODO] + public static DateTime StringToGYearMonth (string value) + { + return XmlConvert.ToDateTime (value); + } + + [MonoTODO] + public static byte [] StringToHexBinary (string value) + { + return XmlConvert.FromBinHexString (value); + } + + [MonoTODO] + public static int StringToInt (string value) + { + return XmlConvert.ToInt32 (value); + } + + [MonoTODO] + public static long StringToInteger (string value) + { + return XmlConvert.ToInt64 (value); + } + + [MonoTODO] + public static decimal StringToNonNegativeInteger (string value) + { + return XmlConvert.ToDecimal (value); + } + + [MonoTODO] + public static decimal StringToNonPositiveInteger (string value) + { + return XmlConvert.ToDecimal (value); + } + + [MonoTODO] + public static DateTime StringToTime (string value) + { + return XmlConvert.ToDateTime (value); + } + + [MonoTODO] + public static long StringToUnsignedInt (string value) + { + return XmlConvert.ToInt32 (value); + } + + [MonoTODO] + public static decimal StringToUnsignedLong (string value) + { + return XmlConvert.ToInt32 (value); + } + + [MonoTODO] + public static int StringToUnsignedShort (string value) + { + return XmlConvert.ToInt32 (value); + } + + [MonoTODO] + public static TimeSpan StringToYearMonthDuration (string value) + { + return XmlConvert.ToTimeSpan (value); + } + + [MonoTODO] + public static string ItemToAnyUri (XPathItem value) + { + return value.Value; + } + + [MonoTODO] + public static byte [] ItemToBase64Binary (XPathItem value) + { + return Convert.FromBase64String (value.Value); + } + + [MonoTODO] + public static bool ItemToBoolean (XPathItem value) + { + return XmlConvert.ToBoolean (value.Value); + } + + [MonoTODO] + public static DateTime ItemToDate (XPathItem value) + { + return XmlConvert.ToDateTime (value.Value); + } + + [MonoTODO] + public static DateTime ItemToDateTime (XPathItem value) + { + return XmlConvert.ToDateTime (value.Value); + } + + [MonoTODO] + public static TimeSpan ItemToDayTimeDuration (XPathItem value) + { + return XmlConvert.ToTimeSpan (value.Value); + } + + [MonoTODO] + public static decimal ItemToDecimal (XPathItem value) + { + return XmlConvert.ToDecimal (value.Value); + } + + [MonoTODO] + public static double ItemToDouble (XPathItem value) + { + return XmlConvert.ToDouble (value.Value); + } + + [MonoTODO] + public static string ItemToDuration (XPathItem value) + { + return XmlConvert.ToString (XmlConvert.ToTimeSpan (value.Value)); + } + + [MonoTODO] + public static float ItemToFloat (XPathItem value) + { + return XmlConvert.ToSingle (value.Value); + } + + [MonoTODO] + public static DateTime ItemToGDay (XPathItem value) + { + return XmlConvert.ToDateTime (value.Value); + } + + [MonoTODO] + public static DateTime ItemToGMonth (XPathItem value) + { + return XmlConvert.ToDateTime (value.Value); + } + + [MonoTODO] + public static DateTime ItemToGMonthDay (XPathItem value) + { + return XmlConvert.ToDateTime (value.Value); + } + + [MonoTODO] + public static DateTime ItemToGYear (XPathItem value) + { + return XmlConvert.ToDateTime (value.Value); + } + + [MonoTODO] + public static DateTime ItemToGYearMonth (XPathItem value) + { + return XmlConvert.ToDateTime (value.Value); + } + + [MonoTODO] + public static byte [] ItemToHexBinary (XPathItem value) + { + return XmlConvert.FromBinHexString (value.Value); + } + + [MonoTODO] + public static int ItemToInt (XPathItem value) + { + return XmlConvert.ToInt32 (value.Value); + } + + [MonoTODO] + public static long ItemToInteger (XPathItem value) + { + return XmlConvert.ToInt64 (value.Value); + } + + [MonoTODO] + public static XPathItem ItemToItem (XPathItem value, XmlSchemaType schemaTypeDest) + { + return new XPathAtomicValue (value.Value, schemaTypeDest); + } + + [MonoTODO] + public static decimal ItemToNonNegativeInteger (XPathItem value) + { + return XmlConvert.ToDecimal (value.Value); + } + + [MonoTODO] + public static decimal ItemToNonPositiveInteger (XPathItem value) + { + return XmlConvert.ToDecimal (value.Value); + } + + [MonoTODO] + public static XmlQualifiedName ItemToQName (XPathItem value) + { + return (XmlQualifiedName) value.TypedValue; + } + + [MonoTODO] + public static string ItemToString (XPathItem value) + { + if (value.ValueType == typeof (DateTime)) + return XmlConvert.ToString ((DateTime) value.TypedValue); + if (value.TypedValue is XmlQualifiedName) + throw new ArgumentException ("Invalid cast from schema QName type to string type."); + return value.Value; + } + + [MonoTODO] + public static DateTime ItemToTime (XPathItem value) + { + return XmlConvert.ToDateTime (value.Value); + } + + [MonoTODO] + public static long ItemToUnsignedInt (XPathItem value) + { + return XmlConvert.ToInt32 (value.Value); + } + + [MonoTODO] + public static decimal ItemToUnsignedLong (XPathItem value) + { + return XmlConvert.ToInt32 (value.Value); + } + + [MonoTODO] + public static int ItemToUnsignedShort (XPathItem value) + { + return XmlConvert.ToInt32 (value.Value); + } + + [MonoTODO] + public static TimeSpan ItemToYearMonthDuration (XPathItem value) + { + return XmlConvert.ToTimeSpan (value.Value); + } + } +} + +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryDefaultFunctionCall.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryDefaultFunctionCall.cs new file mode 100755 index 00000000000..7eb4e280563 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryDefaultFunctionCall.cs @@ -0,0 +1,387 @@ +// +// XQueryDefaultFunctionCall.cs +// +// Author: +// Atsushi Enomoto +// +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// + +// +// XQuery 1.0 and XPath 2.0 Functions implementation as XPathItemExpression. +// See XQuery 1.0 and XPath 2.0 Functions and Operators. +// +#if NET_2_0 +using System; +using System.Collections; +using System.Reflection; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Query; +using System.Xml.XPath; +using System.Xml.Xsl; + +namespace Mono.Xml.XPath2 +{ + internal abstract class DefaultFunctionCall : FunctionCallExprBase + { + static Hashtable qnameTable = new Hashtable (); + static XmlQualifiedName GetName (string name) + { + XmlQualifiedName qname = qnameTable [name] as XmlQualifiedName; + if (qname == null) { + qname = new XmlQualifiedName (name, XQueryFunction.Namespace); + qnameTable.Add (name, qname); + } + return qname; + } + + public DefaultFunctionCall (XQueryStaticContext ctx, string name, int minArgs, int maxArgs, SequenceType type, ExprSequence args) + : base (GetName (name), args) + { + this.type = type; + this.minArgs = minArgs; + this.maxArgs = maxArgs; + } + + SequenceType type; + int minArgs; + int maxArgs; + + public override int MinArgs { get { return minArgs; } } + public override int MaxArgs { get { return maxArgs; } } + + public override SequenceType StaticType { + get { return type; } + } + } + + // Accessors + + // 2.1 fn:node-name ($arg as node ()?) as xs:QName? + internal class FnNodeNameCall : DefaultFunctionCall + { + public FnNodeNameCall (XQueryStaticContext ctx, ExprSequence args) + : base (ctx, "node-name", 1, 1, SequenceType.Create (XmlSchemaSimpleType.XsQName, Occurence.Optional), args) + { + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + XPathSequence res = Args [0].Evaluate (iter); + if (!res.MoveNext ()) + return new XPathEmptySequence (iter.Context); + // FIXME: what happens if context item is not a node. + XPathNavigator nav = res.Current as XPathNavigator; + if (nav == null || nav.LocalName == String.Empty) + return new XPathEmptySequence (iter.Context); + return new SingleItemIterator (new XPathAtomicValue (new XmlQualifiedName (nav.LocalName, nav.NamespaceURI), XmlSchemaSimpleType.XsQName), iter); + } + } + + // 2.2 fn:nilled ($arg as node()) as xs:boolean? + internal class FnNilledCall : DefaultFunctionCall + { + public FnNilledCall (XQueryStaticContext ctx, XPathItemExpression [] args) + : base (ctx, "nilled", 1, 1, SequenceType.Create (XmlSchemaSimpleType.XsBoolean, Occurence.One), args) + { + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + XPathSequence res = Args [0].Evaluate (iter); + if (!res.MoveNext ()) + return new XPathEmptySequence (iter.Context); + XPathNavigator nav = res.Current as XPathNavigator; + IXmlSchemaInfo info = nav.NodeType == XPathNodeType.Element ? nav.SchemaInfo : null; + if (info != null) + return new SingleItemIterator (new XPathAtomicValue (info.IsNil, null), iter); + else + return new XPathEmptySequence (iter.Context); + } + } + + // 2.3 fn:string ($arg as item()?) as xs:string + internal class FnStringCall : DefaultFunctionCall + { + public FnStringCall (XQueryStaticContext ctx, XPathItemExpression [] args) + : base (ctx, "string", 0, 1, SequenceType.Create (XmlSchemaSimpleType.XsString, Occurence.Optional), args) + { + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + XPathItem item = null; + if (Args.Length == 0) + item = iter.Context.CurrentItem; + else { + XPathSequence res = Args [0].Evaluate (iter); + if (!res.MoveNext ()) + return new XPathEmptySequence (iter.Context); + item = res.Current; + } + return new SingleItemIterator (new XPathAtomicValue (Core (item), null), iter); + } + + private string Core (XPathItem item) + { + XPathNavigator nav = item as XPathNavigator; + + return nav != null ? nav.Value : XQueryConvert.ItemToString (item); + } + } + + // 2.4 fn:data ($arg as item()*) as xdt:anyAtomicType* + internal class FnDataCall : DefaultFunctionCall + { + public FnDataCall (XQueryStaticContext ctx, XPathItemExpression [] args) + : base (ctx, "data", 1, 1, SequenceType.Create (XmlSchemaComplexType.AnyType, Occurence.ZeroOrMore), args) + { + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return new AtomizingIterator (Args [0].Evaluate (iter)); + } + } + + // 2.5 fn:base-uri ($arg as node()?) as xs:anyURI? + internal class FnBaseUriCall : DefaultFunctionCall + { + public FnBaseUriCall (XQueryStaticContext ctx, XPathItemExpression [] args) + : base (ctx, "base-uri", 1, 1, SequenceType.Create (XmlSchemaSimpleType.XsAnyUri, Occurence.Optional), args) + { + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + XPathSequence res = Args [0].Evaluate (iter); + if (res.MoveNext ()) + return new XPathEmptySequence (iter.Context); + XPathNavigator nav = res.Current as XPathNavigator; + if (nav == null) + return new XPathEmptySequence (iter.Context); + else + return new SingleItemIterator (new XPathAtomicValue (nav.BaseURI, XmlSchemaSimpleType.XsString), iter); + } + } + + // 2.6 fn:document-uri ($arg as node()?) as xs:anyURI? + internal class FnDocumentUriCall : DefaultFunctionCall + { + public FnDocumentUriCall (XQueryStaticContext ctx, XPathItemExpression [] args) + : base (ctx, "document-uri", 1, 1, SequenceType.Create (XmlSchemaSimpleType.XsAnyUri, Occurence.Optional), args) + { + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + XPathSequence res = Args [0].Evaluate (iter); + if (res.MoveNext ()) + return new XPathEmptySequence (iter.Context); + XPathNavigator nav = res.Current as XPathNavigator; + if (nav == null) + return new XPathEmptySequence (iter.Context); + nav = nav.Clone (); + nav.MoveToRoot (); + return new SingleItemIterator (new XPathAtomicValue (nav.BaseURI, null), iter); + } + } + + // 3 fn:error () + // fn:error ($error as xs:QName) + // fn:error ($error as xs:QName, $description as xs:string) + // fn:error ($error as xs:QName, $description as xs:string, $error-object as item()*) + internal class FnErrorCall : DefaultFunctionCall + { + public FnErrorCall (XQueryStaticContext ctx, XPathItemExpression [] args) + // FIXME: return type is actually none + : base (ctx, "error", 0, 3, SequenceType.AnyType, args) + { + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + // error name + XPathSequence errorNameIter = Args.Length > 0 ? Args [0].Evaluate (iter) : null; + XmlQualifiedName errorType = XmlQualifiedName.Empty; + if (errorNameIter != null && errorNameIter.MoveNext ()) + errorType = XQueryConvert.ItemToQName (errorNameIter.Current); + + // description + string description = Args.Length > 1 ? Args [1].EvaluateAsString (iter) : String.Empty; + + // error-object + XPathSequence errorObjIter = Args.Length > 2 ? Args [2].Evaluate (iter) : null; + + // FIXME: add error-object information + throw new XmlQueryException (errorType + description); + } + } + + // 4 trace ($value as item()*, $label as xs:string) as item()* + internal class FnTraceCall : DefaultFunctionCall + { + public FnTraceCall (XQueryStaticContext ctx, XPathItemExpression [] args) + : base (ctx, "trace", 2, 2, SequenceType.Create (XmlSchemaComplexType.AnyType, Occurence.ZeroOrMore), args) + { + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return new TracingIterator (Args [0].Evaluate (iter), Args [1].EvaluateAsString (iter)); + } + } + + // 5 constructor functions + internal class AtomicConstructorCall : DefaultFunctionCall + { + // FIXME: use IXmlNamespaceResolver.LookupPrefix() in ctx + public AtomicConstructorCall (XQueryStaticContext ctx, SequenceType type, XPathItemExpression [] args) + : base (ctx, type.SchemaType.QualifiedName.Name, 1, 1, type, args) + { + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return new SingleItemIterator (XQueryConvert.ItemToItem (Atomize (Args [0].Evaluate (iter)), null), iter); + } + } + + // 6 functions on numerics (operators are not defined here) + + // 6.4.1 fn:abs ($arg as numeric?) as numeric? + internal class FnAbsCall : DefaultFunctionCall + { + public FnAbsCall (XQueryStaticContext ctx, XPathItemExpression [] args) + : base (ctx, "abs", 1, 1, args [0].StaticType, args) + { + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + XPathSequence arg = Args [0].Evaluate (iter); + if (!arg.MoveNext ()) + return new XPathEmptySequence (iter.Context); + XPathAtomicValue a = null; + // FIXME: use schema type IsDerivedFrom() + switch (Type.GetTypeCode (arg.Current.ValueType)) { + case TypeCode.Int64: + return new SingleItemIterator (new XPathAtomicValue (System.Math.Abs (arg.Current.ValueAsInt64), arg.Current.XmlType), iter); + case TypeCode.Int32: + return new SingleItemIterator (new XPathAtomicValue (System.Math.Abs (arg.Current.ValueAsInt32), arg.Current.XmlType), iter); + case TypeCode.Double: + return new SingleItemIterator (new XPathAtomicValue (System.Math.Abs (arg.Current.ValueAsDouble), arg.Current.XmlType), iter); + case TypeCode.Decimal: + return new SingleItemIterator (new XPathAtomicValue (System.Math.Abs (arg.Current.ValueAsDecimal), arg.Current.XmlType), iter); + case TypeCode.Single: + return new SingleItemIterator (new XPathAtomicValue (System.Math.Abs (arg.Current.ValueAsSingle), arg.Current.XmlType), iter); + } + return new XPathEmptySequence (iter.Context); + } + } + + // 6.4.2 fn:ceiling ($arg as numeric?) as numeric? + internal class FnCeilingCall : DefaultFunctionCall + { + public FnCeilingCall (XQueryStaticContext ctx, XPathItemExpression [] args) + : base (ctx, "ceiling", 1, 1, args [0].StaticType, args) + { + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + throw new NotImplementedException (); + } + } + + // 6.4.3 fn:floor ($arg as numeric?) as numeric? + internal class FnFloorCall : DefaultFunctionCall + { + public FnFloorCall (XQueryStaticContext ctx, XPathItemExpression [] args) + : base (ctx, "floor", 1, 1, args [0].StaticType, args) + { + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + throw new NotImplementedException (); + } + } + + // 6.4.4 fn:round ($arg as numeric?) as numeric? + internal class FnRoundCall : DefaultFunctionCall + { + public FnRoundCall (XQueryStaticContext ctx, XPathItemExpression [] args) + : base (ctx, "round", 1, 1, args [0].StaticType, args) + { + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + throw new NotImplementedException (); + } + } + + // 6.4.5 fn:round-half-to-even ($arg as numeric?) as numeric? + internal class FnRoundHalfToEvenCall : DefaultFunctionCall + { + public FnRoundHalfToEvenCall (XQueryStaticContext ctx, XPathItemExpression [] args) + : base (ctx, "round-half-to-even", 1, 2, args [0].StaticType, args) + { + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + throw new NotImplementedException (); + } + } + + // 7.2.1 fn:codepoints-to-string ($arg as xs:integer*) as xs:string + internal class FnCodepointsToStringCall : DefaultFunctionCall + { + public FnCodepointsToStringCall (XQueryStaticContext ctx, XPathItemExpression [] args) + : base (ctx, "codepoints-to-string", 1, 1, SequenceType.IntegerList, args) + { + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + throw new NotImplementedException (); + } + } + + internal class FnStringCallToCodepointsCall : DefaultFunctionCall + { + public FnStringCallToCodepointsCall (XQueryStaticContext ctx, XPathItemExpression [] args) + : base (ctx, "string-to-codepoints", 1, 1, SequenceType.Create (XmlSchemaSimpleType.XsString, Occurence.Optional), args) + { + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + throw new NotImplementedException (); + } + } +} +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryExpression.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryExpression.cs new file mode 100755 index 00000000000..fcb6dc00db7 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryExpression.cs @@ -0,0 +1,579 @@ +// +// XQueryExpression.cs - abstract syntax tree for XQuery 1.0 +// +// Author: +// Atsushi Enomoto +// +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// +#if NET_2_0 +using System; +using System.Collections; +using System.Xml; +using System.Xml.Query; +using System.Xml.Schema; +using System.Xml.XPath; +using Mono.Xml.XPath2; +using Mono.Xml; + +namespace Mono.Xml.XQuery +{ + internal abstract class XmlConstructorExpr : ExprSingle + { + public XmlConstructorExpr (ExprSequence content) + { + this.content = content; + } + + ExprSequence content; + + public ExprSequence Content { + get { return content; } + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + if (Content != null) + for (int i = 0; i < Content.Count; i++) + Content [i] = Content [i].Compile (compiler); + return this; + } + + public void SerializeContent (XPathSequence iter) + { + if (Content != null) + foreach (ExprSingle expr in Content) + expr.Serialize (iter); + } + + internal IXmlNamespaceResolver GetNSResolver (XPathSequence iter) + { + // FIXME: IXmlNamespaceResolver must be constructed + // considering 1)static context and 2)in-scope element + // construction. + return iter.Context; + } + + public XPathSequence EvaluateNode (XPathSequence iter) + { + return EvaluateNode (iter, XPathNodeType.All); + } + + public XPathSequence EvaluateNode (XPathSequence iter, XPathNodeType moveAfterCreation) + { + XmlDocument doc = new XmlDocument (); + XmlWriter w = iter.Context.Writer; + try { + iter.Context.Writer = doc.CreateNavigator ().AppendChild (); + Serialize (iter); + iter.Context.Writer.Close (); + } finally { + iter.Context.Writer = w; + } + XPathNavigator nav = doc.CreateNavigator (); + switch (moveAfterCreation) { + case XPathNodeType.Attribute: + nav.MoveToFirstAttribute (); + break; + case XPathNodeType.Root: + break; + default: + nav.MoveToFirstChild (); + break; + } + return new SingleItemIterator (nav, iter.Context); + } +#endregion + } + + internal class XmlAttrConstructorList : CollectionBase + { + public XmlAttrConstructorList () + { + } + + public void Add (XmlAttrConstructor item) + { + List.Add (item); + } + + public void Insert (int pos, XmlAttrConstructor item) + { + List.Insert (pos, item); + } + } + + internal class XmlElemConstructor : XmlConstructorExpr + { + XmlQualifiedName name; + ExprSequence nameExpr; + + public XmlElemConstructor (XmlQualifiedName name, ExprSequence content) + : base (content) + { + this.name = name; + } + + public XmlElemConstructor (ExprSequence name, ExprSequence content) + : base (content) + { + this.name = XmlQualifiedName.Empty; + this.nameExpr = name; + } + + public XmlQualifiedName Name { + get { return name; } + } + public ExprSequence NameExpr { + get { return nameExpr; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + if (nameExpr != null) + nameExpr.CheckReference (compiler); + if (Content != null) + Content.CheckReference (compiler); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + if (NameExpr != null) + for (int i = 0; i < NameExpr.Count; i++) + NameExpr [i] = NameExpr [i].Compile (compiler); + if (Content != null) + for (int i = 0; i < Content.Count; i++) + Content [i] = Content [i].Compile (compiler); + return this; + } + + // FIXME: can be optimized by checking all items in Expr + public override SequenceType StaticType { + get { return SequenceType.Element; } + } + + public override void Serialize (XPathSequence iter) + { + XmlQualifiedName name = EvaluateName (iter); + XmlWriter w = iter.Context.Writer; + w.WriteStartElement (iter.Context.LookupPrefix (name.Namespace), name.Name, name.Namespace); + SerializeContent (iter); + w.WriteEndElement (); + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return EvaluateNode (iter); + } + + private XmlQualifiedName EvaluateName (XPathSequence iter) + { + XmlQualifiedName name = Name; + if (NameExpr != null) { + XPathAtomicValue value = Atomize (new ExprSequenceIterator (iter, NameExpr)); + IXmlNamespaceResolver res = iter.Context.NSResolver; + + switch (value.XmlType.TypeCode) { + case XmlTypeCode.QName: + name = (XmlQualifiedName) value.ValueAs (typeof (XmlQualifiedName), res); + break; + case XmlTypeCode.String: + try { + name = InternalPool.ParseQName (value.Value, res); + } catch (ArgumentException ex) { + // FIXME: add more info + throw new XmlQueryException (String.Format ("The evaluation result of the name expression could not be resolved as a valid QName. Evaluation result string is '{0}'.", value.Value)); + } + break; + default: + // FIXME: add more info + throw new XmlQueryException ("A name of an element constructor must be resolved to either a QName or string."); + } + } + return name; + } +#endregion + } + + internal class XmlAttrConstructor : XmlConstructorExpr + { + XmlQualifiedName name; + ExprSequence nameExpr; + + public XmlAttrConstructor (XmlQualifiedName name, ExprSequence content) + : base (content) + { + this.name = name; + } + + public XmlAttrConstructor (ExprSequence name, ExprSequence content) + : base (content) + { + this.nameExpr = name; + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + if (nameExpr != null) + nameExpr.CheckReference (compiler); + if (Content != null) + Content.CheckReference (compiler); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + if (NameExpr != null) + for (int i = 0; i < NameExpr.Count; i++) + NameExpr [i] = NameExpr [i].Compile (compiler); + if (Content != null) + for (int i = 0; i < Content.Count; i++) + Content [i] = Content [i].Compile (compiler); + return this; + } + + public XmlQualifiedName Name { + get { return name; } + } + public ExprSequence NameExpr { + get { return nameExpr; } + } + + // FIXME: can be optimized by checking all items in Expr + public override SequenceType StaticType { + get { return SequenceType.Attribute; } + } + + public override void Serialize (XPathSequence iter) + { + XmlQualifiedName name = EvaluateName (iter); + XmlWriter w = iter.Context.Writer; + w.WriteStartAttribute (GetNSResolver (iter).LookupPrefix (name.Namespace), name.Name, name.Namespace); + SerializeContent (iter); + w.WriteEndAttribute (); + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return EvaluateNode (iter, XPathNodeType.Attribute); + } + + private XmlQualifiedName EvaluateName (XPathSequence iter) + { + XmlQualifiedName name = Name; + if (NameExpr != null) { + XPathAtomicValue value = Atomize (new ExprSequenceIterator (iter, NameExpr)); + IXmlNamespaceResolver res = GetNSResolver (iter); + + switch (value.XmlType.TypeCode) { + case XmlTypeCode.QName: + name = (XmlQualifiedName) value.ValueAs (typeof (XmlQualifiedName), res); + break; + case XmlTypeCode.String: + try { + // nonprefixed attribute name == element's local namespace + if (value.Value.IndexOf (':') < 0) + name = new XmlQualifiedName (value.Value); + else + name = InternalPool.ParseQName (value.Value, res); + } catch (ArgumentException ex) { + // FIXME: add more info + throw new XmlQueryException (String.Format ("The evaluation result of the name expression could not be resolved as a valid QName. Evaluation result string is '{0}'.", value.Value)); + } + break; + default: + // FIXME: add more info + throw new XmlQueryException ("A name of an attribute constructor must be resolved to either a QName or string."); + } + } + return name; + } +#endregion + } + + internal class XmlNSConstructor : XmlConstructorExpr + { + public XmlNSConstructor (string prefix, ExprSequence content) + : base (content) + { + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + Content.CheckReference (compiler); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + if (Content != null) + for (int i = 0; i < Content.Count; i++) + Content [i] = Content [i].Compile (compiler); + return this; + } + + // FIXME: can be optimized by checking all items in Expr + public override SequenceType StaticType { + get { return SequenceType.Namespace; } + } + + public override void Serialize (XPathSequence iter) + { + // TBD + throw new NotImplementedException (); + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + // TBD + throw new NotImplementedException (); + } +#endregion + } + + internal class XmlDocConstructor : XmlConstructorExpr + { + public XmlDocConstructor (ExprSequence content) + : base (content) + { + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + if (Content != null) + Content.CheckReference (compiler); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + if (Content != null) + for (int i = 0; i < Content.Count; i++) + Content [i] = Content [i].Compile (compiler); + return this; + } + + // FIXME: can be optimized by checking all items in Expr + public override SequenceType StaticType { + get { return SequenceType.Document; } + } + + public override void Serialize (XPathSequence iter) + { + XmlWriter w = iter.Context.Writer; + w.WriteStartDocument (); + SerializeContent (iter); + w.WriteEndDocument (); + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return EvaluateNode (iter, XPathNodeType.Root); + } +#endregion + } + + internal class XmlTextConstructor : XmlConstructorExpr + { + public XmlTextConstructor (string text) + : base (null) + { + this.text = text; + } + + public XmlTextConstructor (ExprSequence content) + : base (content) + { + } + + string text; + + public string LiteralText { + get { return text; } + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + if (Content != null) + Content.CheckReference (compiler); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + if (Content != null) + for (int i = 0; i < Content.Count; i++) + Content [i] = Content [i].Compile (compiler); + return this; + } + + public override SequenceType StaticType { + get { return SequenceType.Text; } + } + + public override void Serialize (XPathSequence iter) + { + if (Content != null) + iter.Context.Writer.WriteString (Atomize (new ExprSequenceIterator (iter, Content)).Value); + else + iter.Context.Writer.WriteString (LiteralText); + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return EvaluateNode (iter); + } +#endregion + } + + internal class XmlCommentConstructor : XmlConstructorExpr + { + string contentLiteral; + + public XmlCommentConstructor (string content) + : base (null) + { + this.contentLiteral = content; + } + + public XmlCommentConstructor (ExprSequence content) + : base (content) + { + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + if (Content != null) + Content.CheckReference (compiler); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + if (Content != null) + for (int i = 0; i < Content.Count; i++) + Content [i] = Content [i].Compile (compiler); + return this; + } + + // FIXME: can be optimized by checking all items in Expr + public override SequenceType StaticType { + get { return SequenceType.Comment; } + } + + public override void Serialize (XPathSequence iter) + { + iter.Context.Writer.WriteComment (Atomize (new ExprSequenceIterator (iter, Content)).Value); + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return EvaluateNode (iter); + } +#endregion + } + + internal class XmlPIConstructor : XmlConstructorExpr + { + string name; + ExprSequence nameExpr; + + string contentLiteral; + + public XmlPIConstructor (string name, string content) + : base (null) + { + this.name = name; + this.contentLiteral = content; + } + + public XmlPIConstructor (string name, ExprSequence content) + : base (content) + { + this.name = name; + } + + public XmlPIConstructor (ExprSequence name, ExprSequence content) + : base (content) + { + this.nameExpr = name; + } + + internal override void CheckReference (XQueryASTCompiler compiler) + { + if (nameExpr != null) + nameExpr.CheckReference (compiler); + if (Content != null) + Content.CheckReference (compiler); + } + +#region CompileAndEvaluate + internal override ExprSingle CompileCore (XQueryASTCompiler compiler) + { + if (NameExpr != null) + for (int i = 0; i < NameExpr.Count; i++) + NameExpr [i] = NameExpr [i].Compile (compiler); + if (Content != null) + for (int i = 0; i < Content.Count; i++) + Content [i] = Content [i].Compile (compiler); + return this; + } + + public string Name { + get { return name; } + } + + public ExprSequence NameExpr { + get { return nameExpr; } + } + + // FIXME: can be optimized by checking all items in Expr + public override SequenceType StaticType { + get { return SequenceType.XmlPI; } + } + + public override void Serialize (XPathSequence iter) + { + iter.Context.Writer.WriteProcessingInstruction ( + GetName (iter), + Atomize (new ExprSequenceIterator (iter, Content)).Value); + } + + public override XPathSequence Evaluate (XPathSequence iter) + { + return EvaluateNode (iter); + } + + private string GetName (XPathSequence iter) + { + if (Name != String.Empty) + return Name; + return Atomize (new ExprSequenceIterator (iter, NameExpr)).Value; + } +#endregion + } +} + +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunction.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunction.cs new file mode 100755 index 00000000000..d0a745e8f7b --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunction.cs @@ -0,0 +1,322 @@ +// +// XQueryFunction.cs - XQuery 1.0 and XPath 2.0 Functions implementation +// +// Author: +// Atsushi Enomoto +// +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// + +// +// See XQuery 1.0 and XPath 2.0 Functions and Operators. +// +#if NET_2_0 +using System; +using System.Collections; +using System.Reflection; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Query; +using System.Xml.XPath; +using System.Xml.Xsl; +using Mono.Xml; + +namespace Mono.Xml.XPath2 +{ + // It is instantiated per function definition. (e.g. fn:string(), fn:data(), fn:contat()). + public abstract class XQueryFunction + { + public const string Namespace = "http://www.w3.org/2004/07/xpath-functions"; + + static XQueryFunctionTable defaultFunctions = new XQueryFunctionTable (); + + static XQueryFunction () + { + defaultFunctions.Add (FromName ("node-name", "FnNodeName")); + defaultFunctions.Add (FromName ("nilled", "FnNilled")); + defaultFunctions.Add (FromName ("string", "FnString")); + defaultFunctions.Add (FromName ("data", "FnData")); + defaultFunctions.Add (FromName ("base-uri", "FnBaseUri")); + defaultFunctions.Add (FromName ("document-uri", "FnDocumentUri")); + defaultFunctions.Add (FromName ("error", "FnError")); + defaultFunctions.Add (FromName ("trace", "FnTrace")); + defaultFunctions.Add (FromName ("abs", "FnAbs")); + defaultFunctions.Add (FromName ("ceiling", "FnCeiling")); + defaultFunctions.Add (FromName ("floor", "FnFloor")); + defaultFunctions.Add (FromName ("round", "FnRound")); + defaultFunctions.Add (FromName ("round-half-to-even", "FnRoundHalfToEven")); + defaultFunctions.Add (FromName ("codepoints-to-string", "FnCodepointsToString")); + defaultFunctions.Add (FromName ("string-to-codepoints", "FnStringToCodepoints")); + defaultFunctions.Add (FromName ("compare", "FnCompare")); + defaultFunctions.Add (FromName ("concat", "FnConcat")); + defaultFunctions.Add (FromName ("string-join", "FnStringJoin")); + defaultFunctions.Add (FromName ("substring", "FnSubstring")); + defaultFunctions.Add (FromName ("string-length", "FnStringLength")); + defaultFunctions.Add (FromName ("normaize-space", "FnNormalizeSpace")); + defaultFunctions.Add (FromName ("normalize-unicode", "FnNormalizeUnicode")); + defaultFunctions.Add (FromName ("uppercase", "FnUpperCase")); + defaultFunctions.Add (FromName ("lowercase", "FnLowerCase")); + defaultFunctions.Add (FromName ("translate", "FnTranslate")); + defaultFunctions.Add (FromName ("escape-uri", "FnEscapeUri")); + defaultFunctions.Add (FromName ("contains", "FnContains")); + defaultFunctions.Add (FromName ("starts-with", "FnStartsWith")); + defaultFunctions.Add (FromName ("ends-with", "FnEndsWith")); + defaultFunctions.Add (FromName ("substring-before", "FnSubstringBefore")); + defaultFunctions.Add (FromName ("substring-after", "FnSubstringAfter")); + defaultFunctions.Add (FromName ("matches", "FnMatches")); + defaultFunctions.Add (FromName ("replace", "FnReplace")); + defaultFunctions.Add (FromName ("tokenize", "FnTokenize")); + defaultFunctions.Add (FromName ("resolve-uri", "FnResolveUri")); + defaultFunctions.Add (FromName ("true", "FnTrue")); + defaultFunctions.Add (FromName ("false", "FnFalse")); + defaultFunctions.Add (FromName ("not", "FnNot")); + + defaultFunctions.Add (FromName ("resolve-qname", "FnResolveQName")); + defaultFunctions.Add (FromName ("expand-qname", "FnExpandQName")); + defaultFunctions.Add (FromName ("namespace-uri-for-prefix", "FnNamespaceUriForPrefix")); + defaultFunctions.Add (FromName ("in-scope-prefixes", "FnInScopePrefixes")); + defaultFunctions.Add (FromName ("name", "FnName")); + defaultFunctions.Add (FromName ("local-name", "FnLocalName")); + defaultFunctions.Add (FromName ("namespace-uri", "FnNamespaceUri")); + defaultFunctions.Add (FromName ("number", "FnNumber")); + defaultFunctions.Add (FromName ("lang", "FnLang")); + defaultFunctions.Add (FromName ("root", "FnRoot")); + defaultFunctions.Add (FromName ("boolean", "FnBoolean")); + defaultFunctions.Add (FromName ("indexof", "FnIndexOf")); + defaultFunctions.Add (FromName ("empty", "FnEmpty")); + defaultFunctions.Add (FromName ("exists", "FnExists")); + defaultFunctions.Add (FromName ("distinct-values", "FnDistinctValues")); + defaultFunctions.Add (FromName ("insert-before", "FnInsertBefore")); + defaultFunctions.Add (FromName ("remove", "FnRemove")); + defaultFunctions.Add (FromName ("reverse", "FnReverse")); + defaultFunctions.Add (FromName ("subsequence", "FnSubsequence")); + defaultFunctions.Add (FromName ("unordered", "FnUnordered")); + defaultFunctions.Add (FromName ("zero-or-one", "FnZeroOrOne")); + defaultFunctions.Add (FromName ("one-or-more", "FnOneOrMore")); + defaultFunctions.Add (FromName ("exactly-one", "FnExactlyOne")); + defaultFunctions.Add (FromName ("deep-equal", "FnDeepEqual")); + defaultFunctions.Add (FromName ("count", "FnCount")); + defaultFunctions.Add (FromName ("avg", "FnAvg")); + defaultFunctions.Add (FromName ("max", "FnMax")); + defaultFunctions.Add (FromName ("min", "FnMin")); + defaultFunctions.Add (FromName ("sum", "FnSum")); + defaultFunctions.Add (FromName ("id", "FnId")); + defaultFunctions.Add (FromName ("idref", "FnIdRef")); + defaultFunctions.Add (FromName ("doc", "FnDoc")); + defaultFunctions.Add (FromName ("collection", "FnCollection")); + defaultFunctions.Add (FromName ("position", "FnPosition")); + defaultFunctions.Add (FromName ("last", "FnLast")); + defaultFunctions.Add (FromName ("current-datetime", "FnCurrentDateTime")); + defaultFunctions.Add (FromName ("current-date", "FnCurrentDate")); + defaultFunctions.Add (FromName ("current-time", "FnCurrentTime")); + defaultFunctions.Add (FromName ("default-collation", "FnDefaultCollation")); + defaultFunctions.Add (FromName ("implicit-timezone", "FnImplicitTimeZone")); +// defaultFunctions.Add (FromName ("years-from-duration", "FnYearsFromDuration")); +/* + fnAtomicConstructor, + fnYearsFromDuration, fnMonthsFromDuration, + fnDaysFromDuration, fnHoursFromDuration, + fnMinutesFromDuration, fnSecondsFromDuration, + fnYearFromDateTime, fnMonthFromDateTime, + fnDayFromDateTime, fnHoursFromDateTime, + fnMinutesFromDateTime, fnSecondsFromDateTime, + fnTimeZoneFromDateTime, fnYearFromDate, fnMonthFromDate, + fnDayFromDate, fnTimeZoneFromDate, fnHoursFromTime, + fnMinutesFromTime, fnSecondsFromTime, + fnTimeZoneFromTime, fnAdjustDateTimeToTimeZone, + fnAdjustDateToTimeZone, fnAdjustTimeToTimeZone, + fnSubtractDateTimesYieldingYearMonthDuration, + fnSubtractDateTimesYieldingDayTimeDuration, + fnSubtractDatesYieldingYearMonthDuration, + fnSubtractDatesYieldingDayTimeDuration, + fnSubtractTimes, +*/ + } + + private static XQueryCliFunction FromName (string xname, string cliname) + { + return XQueryCliFunction.CreateFromMethodInfo ( + new XmlQualifiedName (xname, XQueryFunction.Namespace), + FindNamedMethods (typeof (XQueryFunctionCliImpl), cliname) + ); + } + + internal static XQueryCliFunction FromQName (XmlQualifiedName qname) + { + return XQueryCliFunction.CreateFromMethodInfo ( + qname, FindNamedMethods (Type.GetType (qname.Namespace), qname.Name)); + } + + private static bool FilterImpl (MemberInfo m, object filterCriteria) + { + return m.Name == filterCriteria.ToString (); + } + + private static MemberFilter memberFilter = new MemberFilter (FilterImpl); + + private static MethodInfo [] FindNamedMethods (Type type, string name) + { + ArrayList al = new ArrayList ( + type.FindMembers ( + MemberTypes.Method, + BindingFlags.Default | BindingFlags.Public | BindingFlags.Static, + // FIXME: wait for anonymous method support +// delegate (MemberInfo m, object filterCriteria) { +// return m.Name == filterCriteria.ToString (); +// }, + memberFilter, + name)); + return al.ToArray (typeof (MethodInfo)) as MethodInfo []; + } + + internal static XQueryFunction FindKnownFunction ( + XmlQualifiedName name) + { + switch (name.Namespace) { + case XQueryFunction.Namespace: + return defaultFunctions [name]; + case InternalPool.XdtNamespace: + case XmlSchema.Namespace: + XmlSchemaType type = XmlSchemaType.GetBuiltInSimpleType (name); + if (type != null) + return null; // FIXME: atomic constructor + type = XmlSchemaType.GetBuiltInComplexType (name); + if (type == null) + return null; // FIXME: atomic constructor? + return null; + default: + return null; + } + } + + // Constructor + + internal XQueryFunction (XmlQualifiedName name, XQueryFunctionArgument [] args, SequenceType returnType) + { + this.name = name; + this.args = args; + this.returnType = returnType; + } + + // Fields + + XmlQualifiedName name; + XQueryFunctionArgument [] args; + SequenceType returnType; + + // Properties + + public XmlQualifiedName Name { + get { return name; } + } + + public abstract int MinArgs { get; } + public abstract int MaxArgs { get; } + + public XQueryFunctionArgument [] Args { + get { return args; } + } + + public SequenceType ReturnType { + get { return returnType; } + } + + public abstract object Invoke (XPathSequence current, object [] args); + + public virtual XPathSequence Evaluate (XPathSequence iter, ExprSequence args) + { + object [] instParams = new object [args.Count]; + for (int i = 0; i < args.Count; i++) { + XPathSequence val = args [i].Evaluate (iter); + instParams [i] = Args [i].Type.ToRuntimeType (val); + } + object o = Invoke (iter, instParams); + if (o == null) + return new XPathEmptySequence (iter.Context); + if (o is XPathSequence) + return (XPathSequence) o; + XPathItem item = o as XPathItem; + if (item == null) + item = new XPathAtomicValue (o, ReturnType.SchemaType); + return new SingleItemIterator (item, iter.Context); + } + } + + public class XQueryFunctionArgument + { + public XQueryFunctionArgument (XmlQualifiedName name, SequenceType type) + { + this.name = name; + this.type = type; + } + + XmlQualifiedName name; + SequenceType type; + + public XmlQualifiedName Name { + get { return name; } + } + + public SequenceType Type { + get { return type; } + } + } + + public class XQueryUserFunction : XQueryFunction + { + ExprSequence expr; + + internal XQueryUserFunction (XmlQualifiedName name, + XQueryFunctionArgument [] parameters, + ExprSequence expr, + SequenceType returnType) + : base (name, parameters, returnType) + { + this.expr = expr; + } + + public override int MinArgs { + get { return Args.Length; } + } + + public override int MaxArgs { + get { return Args.Length; } + } + + public override object Invoke (XPathSequence current, object [] args) + { + throw new SystemException ("XQuery internal error: should not happen."); + } + + public override XPathSequence Evaluate (XPathSequence iter, ExprSequence args) + { + for (int i = 0; i < Args.Length; i++) + iter.Context.PushVariable (Args [i].Name, args [i].Evaluate (iter)); + XPathSequence seq = new ExprSequenceIterator (iter, expr); + for (int i = 0; i < Args.Length; i++) + iter.Context.PopVariable (); + return seq; + } + } +} +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunctionCliImpl.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunctionCliImpl.cs new file mode 100755 index 00000000000..690851a3147 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunctionCliImpl.cs @@ -0,0 +1,1135 @@ +// +// XQueryFunctionCliImple.cs +// +// Author: +// Atsushi Enomoto +// +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// + +// +// Runtime-level (native) implementation of XQuery 1.0 and XPath 2.0 +// Functions implementation. XQueryCliFunction +// See XQuery 1.0 and XPath 2.0 Functions and Operators. +// +#if NET_2_0 +using System; +using System.Collections; +using System.Globalization; +using System.IO; +using System.Text.RegularExpressions; +using System.Xml; +using System.Xml.Query; +using System.Xml.Schema; +using System.Xml.XPath; +using Mono.Xml; + +namespace Mono.Xml.XPath2 +{ + public class XQueryFunctionCliImpl + { + internal static XmlSchemaType XmlTypeFromCliType (Type cliType) + { + switch (Type.GetTypeCode (cliType)) { + case TypeCode.Int32: + return InternalPool.XsInt; + case TypeCode.Decimal: + return InternalPool.XsDecimal; + case TypeCode.Double: + return InternalPool.XsDouble; + case TypeCode.Single: + return InternalPool.XsFloat; + case TypeCode.Int64: + return InternalPool.XsLong; + case TypeCode.Int16: + return InternalPool.XsShort; + case TypeCode.UInt16: + return InternalPool.XsUnsignedShort; + case TypeCode.UInt32: + return InternalPool.XsUnsignedInt; + case TypeCode.String: + return InternalPool.XsString; + case TypeCode.DateTime: + return InternalPool.XsDateTime; + case TypeCode.Boolean: + return InternalPool.XsBoolean; + } + if (cliType == typeof (XmlQualifiedName)) + return InternalPool.XsQName; + return null; + } + + private static XPathItem ToItem (object arg) + { + if (arg == null) + return null; + XPathItem item = arg as XPathItem; + if (item != null) + return item; + XPathSequence seq = arg as XPathSequence; + if (seq != null) + return seq.MoveNext () ? seq.Current : null; + return new XPathAtomicValue (arg, XmlTypeFromCliType (arg.GetType ())); + } + + // Accessors + + public static XmlQualifiedName FnNodeName (XPathNavigator arg) + { + if (arg == null) + return null; + + return arg.LocalName == String.Empty ? + XmlQualifiedName.Empty : + new XmlQualifiedName (arg.LocalName, arg.NamespaceURI); + } + + public static bool FnNilled (XPathNavigator arg) + { + if (arg == null) + throw new XmlQueryException ("Function nilled() does not allow empty sequence parameter."); + + IXmlSchemaInfo info = arg.NodeType == XPathNodeType.Element ? arg.SchemaInfo : null; + return info != null && info.IsNil; + } + + public static string FnString (XQueryContext context) + { + XPathItem item = context.CurrentItem; + if (item == null) + throw new ArgumentException ("FONC0001: undefined context item"); + return FnString (item); + } + + [MonoTODO] + public static string FnString (object arg) + { + if (arg == null) + return String.Empty; + XPathNavigator nav = arg as XPathNavigator; + if (nav != null) + return nav.Value; + // FIXME: it should be exactly the same as "arg cast as xs:string" + XPathItem item = ToItem (arg); + return item != null ? XQueryConvert.ItemToString (item) : null; + } + + [MonoTODO] + public static XPathAtomicValue FnData (object arg) + { + // FIXME: parameter should be object [] + XPathNavigator nav = arg as XPathNavigator; + if (nav != null) { + XmlSchemaType st = nav.SchemaInfo != null ? nav.SchemaInfo.SchemaType : null; + return new XPathAtomicValue (nav.TypedValue, st != null ? st : InternalPool.XsAnyType); + } + else + return (XPathAtomicValue) arg; + } + + public static string FnBaseUri (XPathNavigator nav) + { + return nav != null ? nav.BaseURI : null; + } + + public static string FnDocumentUri (XPathNavigator nav) + { + if (nav == null) + return null; + XPathNavigator root = nav.Clone (); + root.MoveToRoot (); + return root.BaseURI; + } + + // Error + + [MonoTODO] + public static void FnError (object arg) + { + throw new NotImplementedException (); + } + + // Trace + + [MonoTODO] + public static object FnTrace (XQueryContext ctx, object value, string label) + { + if (value == null) + return new XPathEmptySequence (ctx); + XPathSequence seq = value as XPathSequence; + if (seq == null) { + XPathAtomicValue av = value as XPathAtomicValue; + if (av == null) + av = new XPathAtomicValue (value, + InternalPool.GetBuiltInType ( + InternalPool.XmlTypeCodeFromRuntimeType ( + value.GetType (), true))); + seq = new SingleItemIterator (av, ctx); + } + return new TracingIterator (seq, label); + } + + // Numeric Operation + + [MonoTODO] + public static object FnAbs (object arg) + { + if (arg is int) + return System.Math.Abs ((int) arg); + if (arg is long) + return System.Math.Abs ((long) arg); + else if (arg is decimal) + return System.Math.Abs ((decimal) arg); + else if (arg is double) + return System.Math.Abs ((double) arg); + else if (arg is float) + return System.Math.Abs ((float) arg); + else if (arg is short) + return System.Math.Abs ((short) arg); + else if (arg is uint || arg is ulong || arg is ushort) + return arg; + return null; + } + + [MonoTODO] + public static object FnCeiling (object arg) + { + if (arg is decimal) { + decimal d = (decimal) arg; + decimal d2 = Decimal.Floor (d); + return d2 != d ? d2 + 1 : d2; + } + else if (arg is double || arg is float) + return System.Math.Ceiling ((double) arg); + else if (arg is int || arg is long || arg is short || arg is uint || arg is ulong || arg is ushort) + return arg; + return null; + } + + [MonoTODO] + public static object FnFloor (object arg) + { + if (arg is decimal) + return Decimal.Floor ((decimal) arg); + else if (arg is double || arg is float) + return System.Math.Floor ((double) arg); + else if (arg is int || arg is long || arg is short || arg is uint || arg is ulong || arg is ushort) + return arg; + return null; + } + + [MonoTODO] + public static object FnRound (object arg) + { + if (arg is decimal) + return Decimal.Round ((decimal) arg, 0); + else if (arg is double || arg is float) + return System.Math.Round ((double) arg); + else if (arg is int || arg is long || arg is short || arg is uint || arg is ulong || arg is ushort) + return arg; + return null; + } + + [MonoTODO] + public static object FnRoundHalfToEven (object arg) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public static string FnCodepointsToString (int [] arg) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public static int [] FnStringToCodepoints (string arg) + { + throw new NotImplementedException (); + } + + public static int FnCompare (XQueryContext ctx, string s1, string s2) + { + return FnCompare (s1, s2, ctx.DefaultCollation); + } + + public static int FnCompare (XQueryContext ctx, string s1, string s2, string collation) + { + return FnCompare (s1, s2, ctx.GetCulture (collation)); + } + + private static int FnCompare (string s1, string s2, CultureInfo ci) + { + return ci.CompareInfo.Compare (s1, s2); + } + + public static string FnConcat (object o1, object o2) + { + return String.Concat (o1, o2); + } + + public static string FnStringJoin (string [] strings, string separator) + { + return String.Join (separator, strings); + } + + public static string FnSubstring (string src, double loc) + { + return src.Substring ((int) loc); + } + + public static string FnSubstring (string src, double loc, double length) + { + return src.Substring ((int) loc, (int) length); + } + + public static int FnStringLength (XQueryContext ctx) + { + return FnString (ctx).Length; + } + + public static int FnStringLength (string s) + { + return s.Length; + } + + public static string FnNormalizeSpace (XQueryContext ctx) + { + return FnNormalizeSpace (FnString (ctx)); + } + + [MonoTODO] + public static string FnNormalizeSpace (string s) + { + throw new NotImplementedException (); + } + + public static string FnNormalizeUnicode (string arg) + { + return FnNormalizeUnicode (arg, "NFC"); + } + + [MonoTODO] + public static string FnNormalizeUnicode (string arg, string normalizationForm) + { + throw new NotImplementedException (); + } + + public static string FnUpperCase (string arg) + { + // FIXME: supply culture + return arg.ToUpper (); + } + + public static string FnLowerCase (string arg) + { + // FIXME: supply culture + return arg.ToLower (); + } + + public static string FnTranslate (string arg, string mapString, string transString) + { + return arg == null ? null : arg.Replace (mapString, transString); + } + + [MonoTODO] + public static string FnEscapeUri (string uriPart, bool escapeReserved) + { + throw new NotImplementedException (); + } + + public static bool FnContains (XQueryContext ctx, string arg1, string arg2) + { + return FnContains (arg1, arg2, ctx.DefaultCollation); + } + + public static bool FnContains (XQueryContext ctx, string arg1, string arg2, string collation) + { + return FnContains (arg1, arg2, ctx.GetCulture (collation)); + } + + private static bool FnContains (string arg1, string arg2, CultureInfo ci) + { + if (arg1 == null) + arg1 = String.Empty; + if (arg2 == null) + arg2 = String.Empty; + if (arg2 == String.Empty) + return true; + return ci.CompareInfo.IndexOf (arg1, arg2) >= 0; + } + + public static bool FnStartsWith (XQueryContext ctx, string arg1, string arg2) + { + return FnStartsWith (arg1, arg2, ctx.DefaultCollation); + } + + public static bool FnStartsWith (XQueryContext ctx, string arg1, string arg2, string collation) + { + return FnStartsWith (arg1, arg2, ctx.GetCulture (collation)); + } + + private static bool FnStartsWith (string arg1, string arg2, CultureInfo ci) + { + return ci.CompareInfo.IsPrefix (arg1, arg2); + } + + public static bool FnEndsWith (XQueryContext ctx, string arg1, string arg2) + { + return FnEndsWith (arg1, arg2, ctx.DefaultCollation); + } + + public static bool FnEndsWith (XQueryContext ctx, string arg1, string arg2, string collation) + { + return FnEndsWith (arg1, arg2, ctx.GetCulture (collation)); + } + + private static bool FnEndsWith (string arg1, string arg2, CultureInfo ci) + { + return ci.CompareInfo.IsSuffix (arg1, arg2); + } + + public static string FnSubstringBefore (XQueryContext ctx, string arg1, string arg2) + { + return FnSubstringBefore (arg1, arg2, ctx.DefaultCollation); + } + + public static string FnSubstringBefore (XQueryContext ctx, string arg1, string arg2, string collation) + { + return FnSubstringBefore (arg1, arg2, ctx.GetCulture (collation)); + } + + private static string FnSubstringBefore (string arg1, string arg2, CultureInfo ci) + { + int index = ci.CompareInfo.IndexOf (arg1, arg2); + return arg1.Substring (0, index); + } + + public static string FnSubstringAfter (XQueryContext ctx, string arg1, string arg2) + { + return FnSubstringAfter (arg1, arg2, ctx.DefaultCollation); + } + + public static string FnSubstringAfter (XQueryContext ctx, string arg1, string arg2, string collation) + { + return FnSubstringAfter (arg1, arg2, ctx.GetCulture (collation)); + } + + private static string FnSubstringAfter (string arg1, string arg2, CultureInfo ci) + { + int index = ci.CompareInfo.IndexOf (arg1, arg2); + return arg1.Substring (index); + } + + public static bool FnMatches (string input, string pattern) + { + return new Regex (pattern).IsMatch (input); + } + + [MonoTODO] + public static bool FnMatches (string input, string pattern, string flags) + { + throw new NotImplementedException (); + } + + public static string FnReplace (string input, string pattern, string replace) + { + return new Regex (pattern).Replace (input, replace); + } + + [MonoTODO] + public static string FnReplace (string input, string pattern, string replace, string flags) + { + throw new NotImplementedException (); + } + + public static string [] FnTokenize (string input, string pattern) + { + return new Regex (pattern).Split (input); + } + + [MonoTODO] + public static string [] FnTokenize (string input, string pattern, string flags) + { + throw new NotImplementedException (); + } + + public static string FnResolveUri (XQueryContext ctx, string relUri) + { + return new Uri (new Uri (ctx.StaticContext.BaseUri), relUri).ToString (); + } + + public static string FnResolveUri (string relUri, string baseUri) + { + return new Uri (new Uri (baseUri), relUri).ToString (); + } + + public static object FnTrue () + { + return true; + } + + public static object FnFalse () + { + return false; + } + + public static object FnNot (bool value) + { + return !value; + } + + // FIXME: add a bunch of annoying datetime functions + + public static object FnResolveQName (string qname, XPathNavigator element) + { + if (qname == null) + return null; + + int index = qname.IndexOf (':'); + string prefix = (index < 0) ? "" : qname.Substring (index); + return new XmlQualifiedName ( + element.LookupNamespace (prefix), + index < 0 ? qname : qname.Substring (index + 1)); + } + + public static object FnExpandQName (string ns, string local) + { + return new XmlQualifiedName (local, ns); + } + + public static string FnLocalNameFromQName (XmlQualifiedName name) + { + return name != null ? name.Name : null; + } + + public static object FnNamespaceUriFromQName (XmlQualifiedName name) + { + return name != null ? name.Namespace : null; + } + + public static object FnNamespaceUriForPrefix (XQueryContext context, string prefix) + { + return prefix != null ? context.LookupNamespace (prefix) : null; + } + + public static string [] FnInScopePrefixes (XQueryContext context) + { + IDictionary dict = context.GetNamespacesInScope (XmlNamespaceScope.ExcludeXml); + ArrayList keys = new ArrayList (dict.Keys); + return keys.ToArray (typeof (string)) as string []; + } + + public static string FnName (XPathNavigator nav) + { + return nav != null ? nav.Name : null; + } + + public static string FnLocalName (XPathNavigator nav) + { + return nav != null ? nav.LocalName : null; + } + + public static string FnNamespaceUri (XPathNavigator nav) + { + return nav != null ? nav.NamespaceURI : null; + } + + public static double FnNumber (XQueryContext ctx) + { + return FnNumber (ctx.CurrentItem); + } + + public static double FnNumber (object arg) + { + if (arg == null) + throw new XmlQueryException ("Context item could not be ndetermined during number() evaluation."); + XPathItem item = ToItem (arg); + return XQueryConvert.ItemToDouble (item); + } + + public static bool FnLang (XQueryContext ctx, string testLang) + { + return FnLang (testLang, ctx.CurrentNode); + } + + public static bool FnLang (string testLang, XPathNavigator node) + { + return testLang == node.XmlLang; + } + + public static XPathNavigator FnRoot (XQueryContext ctx) + { + if (ctx.CurrentItem == null) + throw new XmlQueryException ("FONC0001: Undefined context item."); + if (ctx.CurrentNode == null) + throw new XmlQueryException ("FOTY0011: Context item is not a node."); + return FnRoot (ctx.CurrentNode); + } + + public static XPathNavigator FnRoot (XPathNavigator node) + { + if (node == null) + return null; + XPathNavigator root = node.Clone (); + root.MoveToRoot (); + return root; + } + + public static bool FnBoolean (IEnumerator e) + { + if (!e.MoveNext ()) + return false; + XPathItem item = e.Current as XPathItem; + if (e.MoveNext ()) + return true; + return XQueryConvert.ItemToBoolean (item); + } + + public static XPathSequence FnIndexOf (XQueryContext ctx, XPathSequence items, XPathItem item) + { + return FnIndexOf (ctx, items, item, ctx.DefaultCollation); + } + + public static XPathSequence FnIndexOf (XQueryContext ctx, XPathSequence items, XPathItem item, CultureInfo ci) + { + ArrayList al = new ArrayList (); + IEnumerator e = items.GetEnumerator (); + for (int i = 0; e.MoveNext (); i++) { + XPathItem iter = e.Current as XPathItem; + if (iter.XmlType.TypeCode == XmlTypeCode.String) { + if (ci.CompareInfo.Compare (iter.Value, item.Value) == 0) + al.Add (i); + } + else { + IComparable ic = (IComparable) iter.TypedValue; + if (ic.CompareTo ((IComparable) item.TypedValue) == 0) + al.Add (i); + } + } + return new ListIterator (ctx, al); + } + + public static bool FnEmpty (XPathSequence e) + { + if (e is XPathEmptySequence) + return true; + return !e.GetEnumerator ().MoveNext (); + } + + public static bool FnExists (XPathSequence e) + { + if (e is XPathEmptySequence) + return false; + return e.MoveNext (); + } + + public static XPathSequence FnDistinctValues (XQueryContext ctx, XPathSequence items) + { + return FnDistinctValuesImpl (ctx, items, ctx.DefaultCollation); + } + + public static XPathSequence FnDistinctValues (XQueryContext ctx, XPathSequence items, string collation) + { + return FnDistinctValuesImpl (ctx, items, ctx.GetCulture (collation)); + } + + private static XPathSequence FnDistinctValuesImpl (XQueryContext ctx, XPathSequence items, CultureInfo collation) + { + return new DistinctValueIterator (ctx, items, collation); + } + + public static XPathSequence FnInsertBefore (XPathSequence target, int position, XPathSequence inserts) + { + if (position < 1) + position = 1; + return new InsertingIterator (target, position, inserts); + } + + public static XPathSequence FnRemove (XPathSequence target, int position) + { + if (position < 1) + return target; + return new RemovalIterator (target, position); + } + + [MonoTODO ("optimize")] + public static XPathSequence FnReverse (XPathSequence arg) + { + ArrayList al = new ArrayList (); + while (arg.MoveNext ()) + al.Add (arg.Current); + al.Reverse (); + return new ListIterator (arg.Context, al); + } + + public static object FnSubsequence (XPathSequence sourceSeq, double startingLoc) + { + return FnSubsequence (sourceSeq, startingLoc, double.MaxValue); + } + + [MonoTODO] + public static object FnSubsequence (XPathSequence sourceSeq, double startingLoc, double length) + { + throw new NotImplementedException (); + } + + [MonoTODO] + // Basically it should be optimized by XQueryASTCompiler + public static XPathSequence FnUnordered (XPathSequence e) + { + return e; + } + + public static XPathItem FnZeroOrOne (XPathSequence e) + { + if (!e.MoveNext ()) + return null; + XPathItem item = e.Current; + if (e.MoveNext ()) + throw new XmlQueryException ("zero-or-one() function detected that the argument sequence contains two or more items."); + return item; + } + + public static object FnOneOrMore (XPathSequence e) + { + if (!e.Clone ().MoveNext ()) + throw new XmlQueryException ("one-or-more() function detected that the argument sequence contains no items."); + return e; + } + + public static XPathItem FnExactlyOne (XPathSequence e) + { + if (!e.MoveNext ()) + throw new XmlQueryException ("exactly-one() function detected that the argument sequence contains no items."); + XPathItem item = e.Current; + if (e.MoveNext ()) + throw new XmlQueryException ("exactly-one() function detected that the argument sequence contains two or more items."); + return item; + } + + public static object FnDeepEqual (XQueryContext ctx, XPathSequence p1, XPathSequence p2) + { + return FnDeepEqualImpl (p1, p2, ctx.DefaultCollation); + } + + public static object FnDeepEqual (XQueryContext ctx, XPathSequence p1, XPathSequence p2, string collation) + { + return FnDeepEqualImpl (p1, p2, ctx.GetCulture (collation)); + } + + public static bool FnDeepEqualImpl (XPathSequence p1, XPathSequence p2, CultureInfo collation) + { + // FIXME: use collation + while (p1.MoveNext ()) { + if (!p2.MoveNext ()) + return false; + if (!FnDeepEqualItem (p1.Current, p2.Current, collation)) + return false; + } + if (p2.MoveNext ()) + return false; + return true; + } + + // FIXME: Actually ValueEQ() should consider collation. + [MonoTODO] + private static bool FnDeepEqualItem (XPathItem i1, XPathItem i2, CultureInfo collation) + { + XPathAtomicValue av1 = i1 as XPathAtomicValue; + XPathAtomicValue av2 = i1 as XPathAtomicValue; + if (av1 != null && av2 != null) { + try { + return XQueryComparisonOperator.ValueEQ (av1, av2); + } catch (XmlQueryException) { + // not-allowed comparison never raises + // an error here, just return false. + return false; + } + } + else if (av1 != null || av2 != null) + return false; + + XPathNavigator n1 = i1 as XPathNavigator; + XPathNavigator n2 = i2 as XPathNavigator; + if (n1.NodeType != n2.NodeType) + return false; + switch (n1.NodeType) { + case XPathNodeType.Root: + throw new NotImplementedException (); + case XPathNodeType.Element: + throw new NotImplementedException (); + case XPathNodeType.Attribute: + return n1.Name == n2.Name && n1.TypedValue == n2.TypedValue; + case XPathNodeType.ProcessingInstruction: + case XPathNodeType.Namespace: + return n1.Name == n2.Name && n1.Value == n2.Value; + case XPathNodeType.Text: + case XPathNodeType.Comment: + return n1.Value == n2.Value; + } + return false; + } + + public static int FnCount (XPathSequence e) + { + if (e == null) + return 0; + return e.Count; + } + + [MonoTODO] + public static object FnAvg (XPathSequence e) + { + if (!e.MoveNext ()) + return null; + switch (e.Current.XmlType.TypeCode) { + case XmlTypeCode.DayTimeDuration: + return FnAvgDayTimeDuration (e); + case XmlTypeCode.YearMonthDuration: + return FnAvgYearMonthDuration (e); + case XmlTypeCode.Decimal: + return FnAvgDecimal (e); + case XmlTypeCode.Integer: + return FnAvgInteger (e); + case XmlTypeCode.Float: + return FnAvgFloat (e); + case XmlTypeCode.UntypedAtomic: + case XmlTypeCode.Double: + return FnAvgDouble (e); + } + throw new XmlQueryException ("avg() function detected that the sequence contains an item whose type is neither of dayTimeDuration, yearMonthDuration, decimal, integer, float, double, nor untypedAtomic."); + } + + private static TimeSpan FnAvgDayTimeDuration (XPathSequence e) + { + throw new NotImplementedException (); + } + + private static TimeSpan FnAvgYearMonthDuration (XPathSequence e) + { + throw new NotImplementedException (); + } + + private static TimeSpan FnAvgDecimal (XPathSequence e) + { + throw new NotImplementedException (); + } + + private static TimeSpan FnAvgInteger (XPathSequence e) + { + throw new NotImplementedException (); + } + + private static TimeSpan FnAvgFloat (XPathSequence e) + { + throw new NotImplementedException (); + } + + private static TimeSpan FnAvgDouble (XPathSequence e) + { + throw new NotImplementedException (); + } + + public static object FnMax (XQueryContext ctx, XPathSequence e) + { + return FnMaxImpl (e, ctx.DefaultCollation); + } + + public static object FnMax (XQueryContext ctx, XPathSequence e, string collation) + { + return FnMaxImpl (e, ctx.GetCulture (collation)); + } + + private static object FnMaxImpl (XPathSequence e, CultureInfo collation) + { + if (!e.MoveNext ()) + return null; + switch (e.Current.XmlType.TypeCode) { + case XmlTypeCode.DayTimeDuration: + return FnMaxDayTimeDuration (e); + case XmlTypeCode.YearMonthDuration: + return FnMaxYearMonthDuration (e); + case XmlTypeCode.Decimal: + return FnMaxDecimal (e); + case XmlTypeCode.Integer: + return FnMaxInteger (e); + case XmlTypeCode.Float: + return FnMaxFloat (e); + case XmlTypeCode.UntypedAtomic: + case XmlTypeCode.Double: + return FnMaxDouble (e); + } + throw new XmlQueryException ("avg() function detected that the sequence contains an item whose type is neither of dayTimeDuration, yearMonthDuration, decimal, integer, float, double, nor untypedAtomic."); + } + + private static TimeSpan FnMaxDayTimeDuration (XPathSequence e) + { + // FIXME: reject yMD (but is it possible...?) + TimeSpan ret = TimeSpan.Zero; + do { + TimeSpan ts = (TimeSpan) e.Current.TypedValue; + if (ts > ret) + ret = ts; + } while (e.MoveNext ()); + return ret; + } + + private static TimeSpan FnMaxYearMonthDuration (XPathSequence e) + { + // FIXME: reject dTD (but is it possible...?) + TimeSpan ret = TimeSpan.Zero; + do { + TimeSpan ts = (TimeSpan) e.Current.TypedValue; + if (ts > ret) + ret = ts; + } while (e.MoveNext ()); + return ret; + } + + private static decimal FnMaxDecimal (XPathSequence e) + { + decimal ret = decimal.MinValue; + do { + ret = System.Math.Max (e.Current.ValueAsDecimal, ret); + } while (e.MoveNext ()); + return ret; + } + + private static int FnMaxInteger (XPathSequence e) + { + int ret = int.MinValue; + do { + ret = System.Math.Max (e.Current.ValueAsInt32, ret); + } while (e.MoveNext ()); + return ret; + } + + private static float FnMaxFloat (XPathSequence e) + { + float ret = float.MinValue; + do { + ret = System.Math.Max (e.Current.ValueAsSingle, ret); + } while (e.MoveNext ()); + return ret; + } + + private static double FnMaxDouble (XPathSequence e) + { + double ret = double.MinValue; + do { + ret = System.Math.Max (e.Current.ValueAsDouble, ret); + } while (e.MoveNext ()); + return ret; + } + + public static object FnMin (XQueryContext ctx, XPathSequence e) + { + return FnMinImpl (e, ctx.DefaultCollation); + } + + public static object FnMin (XQueryContext ctx, XPathSequence e, string collation) + { + return FnMinImpl (e, ctx.GetCulture (collation)); + } + + private static object FnMinImpl (XPathSequence e, CultureInfo collation) + { + if (!e.MoveNext ()) + return null; + switch (e.Current.XmlType.TypeCode) { + case XmlTypeCode.DayTimeDuration: + return FnMinDayTimeDuration (e); + case XmlTypeCode.YearMonthDuration: + return FnMinYearMonthDuration (e); + case XmlTypeCode.Decimal: + return FnMinDecimal (e); + case XmlTypeCode.Integer: + return FnMinInteger (e); + case XmlTypeCode.Float: + return FnMinFloat (e); + case XmlTypeCode.UntypedAtomic: + case XmlTypeCode.Double: + return FnMinDouble (e); + } + throw new XmlQueryException ("avg() function detected that the sequence contains an item whose type is neither of dayTimeDuration, yearMonthDuration, decimal, integer, float, double, nor untypedAtomic."); + } + + private static TimeSpan FnMinDayTimeDuration (XPathSequence e) + { + // FIXME: reject yMD (but is it possible...?) + TimeSpan ret = TimeSpan.Zero; + do { + TimeSpan ts = (TimeSpan) e.Current.TypedValue; + if (ts > ret) + ret = ts; + } while (e.MoveNext ()); + return ret; + } + + private static TimeSpan FnMinYearMonthDuration (XPathSequence e) + { + // FIXME: reject dTD (but is it possible...?) + TimeSpan ret = TimeSpan.Zero; + do { + TimeSpan ts = (TimeSpan) e.Current.TypedValue; + if (ts > ret) + ret = ts; + } while (e.MoveNext ()); + return ret; + } + + private static decimal FnMinDecimal (XPathSequence e) + { + decimal ret = decimal.MaxValue; + do { + ret = System.Math.Min (e.Current.ValueAsDecimal, ret); + } while (e.MoveNext ()); + return ret; + } + + private static int FnMinInteger (XPathSequence e) + { + int ret = int.MaxValue; + do { + ret = System.Math.Min (e.Current.ValueAsInt32, ret); + } while (e.MoveNext ()); + return ret; + } + + private static float FnMinFloat (XPathSequence e) + { + float ret = float.MaxValue; + do { + ret = System.Math.Min (e.Current.ValueAsSingle, ret); + } while (e.MoveNext ()); + return ret; + } + + private static double FnMinDouble (XPathSequence e) + { + double ret = double.MaxValue; + do { + ret = System.Math.Min (e.Current.ValueAsDouble, ret); + } while (e.MoveNext ()); + return ret; + } + + [MonoTODO] + public static object FnSum (XPathSequence e) + { + throw new NotImplementedException (); + } + + [MonoTODO] + public static object FnSum (XPathSequence e, XPathItem zero) + { + throw new NotImplementedException (); + } + + public static XPathNavigator FnId (XQueryContext ctx, string id) + { + return FnId (id, ctx.CurrentNode); + } + + public static XPathNavigator FnId (string id, XPathNavigator nav) + { + XPathNavigator node = nav.Clone (); + return node.MoveToId (id) ? node : null; + } + + [MonoTODO] + public static object FnIdRef (XQueryContext ctx, string arg) + { + return FnIdRef (arg, ctx.CurrentNode); + } + + [MonoTODO] + public static object FnIdRef (string arg, XPathNavigator node) + { + throw new NotImplementedException (); + } + + public static XPathNavigator FnDoc (XQueryContext ctx, string uri) + { + XmlResolver res = ctx.ContextManager.ExtDocResolver; + string baseUriString = ctx.StaticContext.BaseUri; + Uri baseUri = null; + if (baseUriString != null && baseUriString != String.Empty) + baseUri = new Uri (baseUriString); + Uri relUri = res.ResolveUri (baseUri, uri); + Stream s = res.GetEntity (relUri, null, typeof (Stream)) as Stream; + try { + XPathDocument doc = new XPathDocument (new XmlValidatingReader (new XmlTextReader (s)), XmlSpace.Preserve); + return doc.CreateNavigator (); + } finally { + s.Close (); + } + } + + public static XPathSequence FnCollection (XQueryContext ctx, string name) + { + return ctx.ResolveCollection (name); + } + + [XQueryFunctionContext] + public static int FnPosition (XPathSequence current) + { + return current.Position; + } + + [XQueryFunctionContext] + public static int FnLast (XPathSequence current) + { + return current.Count; + } + + public static DateTime FnCurrentDateTime () + { + return DateTime.Now; + } + + public static DateTime FnCurrentDate () + { + return DateTime.Today; + } + + public static DateTime FnCurrentTime () + { + return new DateTime (DateTime.Now.TimeOfDay.Ticks); + } + + [MonoTODO] + public static object FnDefaultCollation () + { + throw new NotImplementedException (); + } + + [MonoTODO] + public static object FnImplicitTimeZone () + { + throw new NotImplementedException (); + } + } +} +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunctionContextAttribute.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunctionContextAttribute.cs new file mode 100755 index 00000000000..5c8d6b9c8c4 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunctionContextAttribute.cs @@ -0,0 +1,45 @@ +// +// XQueryFunctionContextAttribute.cs +// +// Author: +// Atsushi Enomoto +// +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// +// It is used to represent that a function needs current nodeset information. +// +#if NET_2_0 +using System; +using System.Collections; +using System.Xml; +using System.Xml.Schema; +using System.Xml.XPath; + +namespace Mono.Xml.XPath2 +{ + public class XQueryFunctionContextAttribute : Attribute + { + } +} + +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunctionTable.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunctionTable.cs new file mode 100755 index 00000000000..7e5254ea324 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryFunctionTable.cs @@ -0,0 +1,66 @@ +// +// XQueryFunctionTable.cs +// +// Author: +// Atsushi Enomoto +// +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// + +#if NET_2_0 +using System; +using System.Collections; +using System.Reflection; +using System.Xml; +using System.Xml.Schema; +using System.Xml.Query; +using System.Xml.XPath; +using System.Xml.Xsl; + +namespace Mono.Xml.XPath2 +{ + public class XQueryFunctionTable : DictionaryBase + { + public XQueryFunctionTable () + { + } + + public XQueryFunction this [XmlQualifiedName name] { + get { return Dictionary [name] as XQueryFunction; } + } + + internal void Add (XQueryFunction func) + { + Dictionary.Add (func.Name, func); + } + + public ICollection Keys { + get { return Dictionary.Keys; } + } + + public ICollection Values { + get { return Dictionary.Values; } + } + } +} +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryModuleProlog.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryModuleProlog.cs new file mode 100755 index 00000000000..7091c775e71 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryModuleProlog.cs @@ -0,0 +1,529 @@ +// +// XQueryModuleProlog.cs - abstract syntax tree for XQuery +// +// Author: +// Atsushi Enomoto +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// + +#if NET_2_0 + +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Xml; +using System.Xml.Query; +using System.Xml.Schema; +using Mono.Xml.XQuery; + +namespace Mono.Xml.XPath2 +{ + internal abstract class XQueryModule + { + string version; + Prolog prolog; + IXmlNamespaceResolver nsResolver; + + public string Version { + get { return version; } + set { version = value; } + } + + public Prolog Prolog { + get { return prolog; } + set { prolog = value; } + } + + public IXmlNamespaceResolver NSResolver { + get { return nsResolver; } + set { nsResolver = value; } + } + } + + internal class XQueryMainModule : XQueryModule + { + ExprSequence queryBody; + + public ExprSequence QueryBody { + get { return queryBody; } + set { queryBody = value; } + } + } + + internal class XQueryLibraryModule : XQueryModule + { + ModuleDecl moduleDecl; + + public ModuleDecl ModuleDecl { + get { return moduleDecl; } + set { moduleDecl = value; } + } + } + + internal class ModuleDecl + { + string prefix; + string ns; + + public string Prefix { + get { return prefix; } + set { prefix = value; } + } + + public string Namespace { + get { return ns; } + set { ns = value; } + } + } + + internal class Prolog + { + public Prolog () + { + namespaceDecls = new StringDictionary (); + schemaImports = new SchemaImportCollection (); + moduleImports = new ModuleImportCollection (); + variables = new XQueryVariableTable (); + functions = new FunctionCollection (); + } + + string version; + StringDictionary namespaceDecls; + XmlSpace xmlSpaceDecl; + XmlSpace constructorDecl; + string defaultElementNamespace; + string defaultFunctionNamespace; + string defaultCollation; + string baseUri; + bool defaultOrdered; // false by default + SchemaImportCollection schemaImports; + ModuleImportCollection moduleImports; + XQueryVariableTable variables; + XmlSchemaContentProcessing validationType; + FunctionCollection functions; + + public string Version { + get { return version; } + set { version = value; } + } + + public StringDictionary NamespaceDecls { + get { return namespaceDecls; } + } + + public XmlSpace XmlSpace { + get { return xmlSpaceDecl; } + set { xmlSpaceDecl = value; } + } + + public XmlSpace Constructor { + get { return constructorDecl; } + set { constructorDecl = value; } + } + + public bool DefaultOrdered { + get { return defaultOrdered; } + set { defaultOrdered = value; } + } + + public string DefaultElementNamespace { + get { return defaultElementNamespace; } + set { defaultElementNamespace = value; } + } + + public string DefaultFunctionNamespace { + get { return defaultFunctionNamespace; } + set { defaultFunctionNamespace = value; } + } + + public string DefaultCollation { + get { return defaultCollation; } + set { defaultCollation = value; } + } + + public string BaseUri { + get { return baseUri; } + set { baseUri = value; } + } + + public SchemaImportCollection SchemaImports { + get { return schemaImports; } + } + + public ModuleImportCollection ModuleImports { + get { return moduleImports; } + } + + public XQueryVariableTable Variables { + get { return variables; } + } + + public XmlSchemaContentProcessing ValidationType { + get { return validationType; } + set { validationType = value; } + } + + public FunctionCollection Functions { + get { return functions; } + } + + public void Add (object item) + { + if (item is bool) + DefaultOrdered = (bool) item; + else if (item is XmlQualifiedName) { + XmlQualifiedName q = (XmlQualifiedName) item; + NamespaceDecls.Add (q.Name, q.Namespace); + } else if (item is XmlSpaceDecl) { + XmlSpace = ((XmlSpaceDecl) item).Value; + } else if (item is ConstructionDecl) { + Constructor = ((ConstructionDecl) item).Value; + } else if (item is SimplePrologContent) { + SimplePrologContent c = (SimplePrologContent) item; + string s = c.LiteralValue; + switch (c.Type) { + case PrologContentType.DefaultElementNamespace: + DefaultElementNamespace = s; + break; + case PrologContentType.DefaultFunctionNamespace: + DefaultFunctionNamespace = s; + break; + case PrologContentType.DefaultCollation: + DefaultCollation = s; + break; + case PrologContentType.BaseUri: + BaseUri = s; + break; + default: + throw new XmlQueryCompileException ("Invalid XQuery prolog content was found."); + } + } else if (item is SchemaImport) { + SchemaImports.Add (item as SchemaImport); + } else if (item is ModuleImport) { + ModuleImports.Add (item as ModuleImport); + } else if (item is XQueryVariable) { + XQueryVariable var = item as XQueryVariable; + Variables.Add (var); + } else if (item is XmlSchemaContentProcessing) { + ValidationType = (XmlSchemaContentProcessing) item; + } else if (item is FunctionDeclaration) { + Functions.Add (item as FunctionDeclaration); + } else + throw new XmlQueryCompileException ("Invalid XQuery prolog content item was found."); + } + } + + class XmlSpaceDecl + { + public XmlSpace Value; + + public XmlSpaceDecl (XmlSpace value) + { + Value = value; + } + } + + class ConstructionDecl + { + public XmlSpace Value; + + public ConstructionDecl (XmlSpace value) + { + Value = value; + } + } + + public class ModuleImportCollection : CollectionBase + { + public void Add (ModuleImport import) + { + List.Add (import); + } + } + + public class SchemaImportCollection : CollectionBase + { + public void Add (SchemaImport import) + { + List.Add (import); + } + } + + public enum PrologContentType { + DefaultElementNamespace, + DefaultFunctionNamespace, + DefaultCollation, + BaseUri + } + + public class SimplePrologContent + { + public SimplePrologContent (PrologContentType type, string literalValue) + { + this.type = type; + this.literalValue = literalValue; + } + + PrologContentType type; + string literalValue; + + public PrologContentType Type { + get { return type; } + set { type = value; } + } + + public string LiteralValue { + get { return literalValue; } + set { literalValue = value; } + } + } + + public abstract class AbstractImport + { + public AbstractImport (string prefix, string ns, ICollection locations) + { + this.prefix = prefix; + this.ns = ns; + this.locations = locations; + if (locations == null) + this.locations = new ArrayList (); // empty list + } + + string prefix, ns; + ICollection locations; + + public string Prefix { + get { return prefix; } + set { prefix = value; } + } + + public string Namespace { + get { return ns; } + set { ns = value; } + } + + public ICollection Locations { + get { return locations; } + set { locations = value != null ? value : new ArrayList (); } + } + } + + public class SchemaImport : AbstractImport + { + public SchemaImport (string prefix, string ns, ICollection schemaLocations) + : base (prefix == "default element namespace" ? String.Empty : prefix, ns, schemaLocations) + { + // Prefix might 1) String.Empty for non-specified prefix, + // 2) "default element namespace" that is as is + // specified in xquery. + if (prefix == "default element namespace") + useDefaultElementNamespace = true; + } + + bool useDefaultElementNamespace; + + public bool UseDefaultElementNamespace { + get { return useDefaultElementNamespace; } + set { useDefaultElementNamespace = value; } + } + } + + public class ModuleImport : AbstractImport + { + public ModuleImport (string prefix, string ns, ICollection moduleLocations) + : base (prefix, ns, moduleLocations) + { + } + } + + public class XQueryVariableTable : DictionaryBase + { + public void Add (XQueryVariable decl) + { + Dictionary.Add (decl.Name, decl); + } + + public ICollection Keys { + get { return Dictionary.Keys; } + } + + public ICollection Values { + get { return Dictionary.Values; } + } + + public XQueryVariable this [XmlQualifiedName name] { + get { return Dictionary [name] as XQueryVariable; } + } + } + + public class XQueryVariable + { + public XQueryVariable (XmlQualifiedName name, SequenceType type, ExprSequence varBody) + { + this.name = name; + this.type = type; + this.varBody = varBody; // might be null (just declaration). + } + + XmlQualifiedName name; + SequenceType type; + ExprSequence varBody; + + public XmlQualifiedName Name { + get { return name; } + } + + public SequenceType VariableType { + get { return type; } + } + + public bool External { + get { return varBody == null; } + } + + public ExprSequence VariableBody { + get { return varBody; } + } + } + + internal class FunctionCollection : DictionaryBase + { + public void Add (FunctionDeclaration decl) + { + Dictionary.Add (decl.Name, decl); + } + + public ICollection Keys { + get { return Dictionary.Keys; } + } + + public ICollection Values { + get { return Dictionary.Values; } + } + + public FunctionDeclaration this [XmlQualifiedName name] { + get { return Dictionary [name] as FunctionDeclaration; } + } + } + + internal class FunctionDeclaration + { + public FunctionDeclaration (XmlQualifiedName name, + XQueryFunctionArgumentList parameters, + SequenceType type, + EnclosedExpr expr) + { + this.name = name; + this.parameters = parameters; + this.returnType = type; + this.funcBody = expr; + } + + XmlQualifiedName name; + SequenceType returnType; + XQueryFunctionArgumentList parameters; + EnclosedExpr funcBody; + + public XmlQualifiedName Name { + get { return name; } + } + + public SequenceType ReturnType { + get { return returnType; } + } + + public bool External { + get { return funcBody == null; } + } + + public XQueryFunctionArgumentList Parameters { + get { return parameters; } + } + + public EnclosedExpr FunctionBody { + get { return funcBody; } + } + } + + public class XQueryFunctionArgumentList : CollectionBase + { + public void Add (XQueryFunctionArgument p) + { + List.Add (p); + } + + public void Insert (int pos, XQueryFunctionArgument p) + { + List.Insert (pos, p); + } + + public XQueryFunctionArgument this [int i] { + get { return (XQueryFunctionArgument) List [i]; } + } + + public XQueryFunctionArgument [] ToArray () + { + XQueryFunctionArgument [] arr = new XQueryFunctionArgument [List.Count]; + List.CopyTo (arr, 0); + return arr; + } + } + + public abstract class PragmaMUExtensionBase + { + XmlQualifiedName name; + string text; + + protected PragmaMUExtensionBase (XmlQualifiedName name, string text) + { + this.name = name; + this.text = text; + } + + public XmlQualifiedName Name { + get { return name; } + } + + public string Text { + get { return text; } + } + } + + public class Pragma : PragmaMUExtensionBase + { + public Pragma (XmlQualifiedName name, string text) + : base (name, text) + { + } + } + + public class MUExtension : PragmaMUExtensionBase + { + public MUExtension (XmlQualifiedName name, string text) + : base (name, text) + { + } + } +} + +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryParser.jay b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryParser.jay new file mode 100755 index 00000000000..f11635bfda2 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryParser.jay @@ -0,0 +1,2535 @@ +%{ +// +// XQueryParser.jay +// +// Author: +// Atsushi Enomoto +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// + +// +// FIXME: +// attribute value template +// handle double literal +// + +#if NET_2_0 + +using System; +using System.Collections; +using System.IO; +using System.Xml; +using System.Xml.Query; +using System.Xml.Schema; +using System.Xml.XPath; +using System.Security.Policy; +using Mono.Xml.XPath2; +using Mono.Xml.XQuery; +using Mono.Xml; + +namespace Mono.Xml.XQuery.Parser +{ + internal class XQueryParser + { + // See also FunctionCall production rule. + static Hashtable reservedFunctionNames; + + static XQueryParser () + { + reservedFunctionNames = new Hashtable (); + reservedFunctionNames.Add ("attribute", "attribute"); + reservedFunctionNames.Add ("comment", "comment"); + reservedFunctionNames.Add ("document", "document"); + reservedFunctionNames.Add ("element", "element"); + reservedFunctionNames.Add ("empty", "empty"); + reservedFunctionNames.Add ("if", "if"); + reservedFunctionNames.Add ("item", "item"); + reservedFunctionNames.Add ("node", "node"); + reservedFunctionNames.Add ("processing-instruction", "processing-instruction"); + reservedFunctionNames.Add ("text", "text"); + reservedFunctionNames.Add ("type", "type"); + reservedFunctionNames.Add ("typeswitch", "typeswitch"); + } + + public static XQueryModule Parse (TextReader reader) + { + return new XQueryParser ().RunParse (reader); + } + + private XQueryTokenizer tokenizer; + + private XQueryParser () + { + } + + // FIXME: we don't need Evidence here at all. It is used only + // to generate runnable IL (on loading resulting Assembly). + public XQueryModule RunParse (TextReader source) + { + tokenizer = null; + try { +// debug = new yydebug.yyDebugSimple (); + tokenizer = new XQueryTokenizer (source); + XQueryModule mod = (XQueryModule) yyparse (tokenizer); + mod.NSResolver = tokenizer.NSResolver; + return mod; + } catch (yyParser.yyException ex) { + throw new XmlQueryCompileException (String.Format ("Tokenizer error at line {0}, column {1}: {2}", tokenizer.LineNumber, tokenizer.LinePosition, ex.Message), ex); + } + } + + public XmlTypeCode GetAtomicTypeCode (XmlQualifiedName name) + { + if (name.Namespace == InternalPool.XdtNamespace) { + switch (name.Name) { + case "anyAtomicType": + return XmlTypeCode.AnyAtomicType; + case "dayTimeDuration": + return XmlTypeCode.DayTimeDuration; + case "item": + return XmlTypeCode.Item; + case "untypedAtomic": + return XmlTypeCode.UntypedAtomic; + case "yearMonthDuration": + return XmlTypeCode.YearMonthDuration; + } + } else if (name.Namespace == XmlSchema.Namespace) { + switch (name.Name) { + case "boolean": + return XmlTypeCode.Boolean; + case "byte": + return XmlTypeCode.Byte; + case "date": + return XmlTypeCode.Date; + case "dateTime": + return XmlTypeCode.DateTime; + case "decimal": + return XmlTypeCode.Decimal; + case "double": + return XmlTypeCode.Double; + case "duration": + return XmlTypeCode.Duration; + case "entity": + return XmlTypeCode.Entity; + case "float": + return XmlTypeCode.Float; + case "gDay": + return XmlTypeCode.GDay; + case "gMonth": + return XmlTypeCode.GMonth; + case "gMonthDay": + return XmlTypeCode.GMonthDay; + case "gYear": + return XmlTypeCode.GYear; + case "gYearMonth": + return XmlTypeCode.GYearMonth; + case "hexBinary": + return XmlTypeCode.HexBinary; + case "id": + return XmlTypeCode.Id; + case "idref": + return XmlTypeCode.Idref; + case "int": + return XmlTypeCode.Int; + case "integer": + return XmlTypeCode.Integer; + case "language": + return XmlTypeCode.Language; + case "long": + return XmlTypeCode.Long; + case "Name": + return XmlTypeCode.Name; + case "NCName": + return XmlTypeCode.NCName; + case "negativeInteger": + return XmlTypeCode.NegativeInteger; + case "NMTOKEN": + return XmlTypeCode.NmToken; + case "nonNegativeInteger": + return XmlTypeCode.NonNegativeInteger; + case "nonPositiveInteger": + return XmlTypeCode.NonPositiveInteger; + case "normalizedString": + return XmlTypeCode.NormalizedString; + case "NOTATION": + return XmlTypeCode.Notation; + case "positiveInteger": + return XmlTypeCode.PositiveInteger; + case "QName": + return XmlTypeCode.QName; + case "short": + return XmlTypeCode.Short; + case "string": + return XmlTypeCode.String; + case "time": + return XmlTypeCode.Time; + case "token": + return XmlTypeCode.Token; + case "unsignedByte": + return XmlTypeCode.UnsignedByte; + case "unsignedInt": + return XmlTypeCode.UnsignedInt; + case "unsignedLong": + return XmlTypeCode.UnsignedLong; + case "unsignedShort": + return XmlTypeCode.UnsignedShort; + } + } + throw new XmlQueryCompileException (String.Format ("Unexpected type name was specified as atomic type: {0}", name)); + } + +%} + +/* -------------------------------------------------------- + Tokens +-------------------------------------------------------- */ + +/* These are for numbers */ +//%token SMALL_E //"e" +//%token LARGE_E //"E" + +%token DOT "." +%token DOT2 ".." +%token SEMICOLON ";" +%token OPEN_PAREN "(" +%token OPEN_PAREN_COLON "(:" +%token PRAGMA_OPEN "(::" +%token CLOSE_PAREN ")" +%token COLON ":" +%token COLON2 "::" +%token PRAGMA_CLOSE "::)" +%token CLOSE_PAREN_COLON ":)" +%token COLON_EQUAL ":=" +%token OPEN_BRACKET "[" +%token CLOSE_BRACKET "]" +%token OPEN_CURLY "{" +%token CLOSE_CURLY "}" +%token COMMA "," +%token DOLLAR "$" +%token EQUAL "=" +%token NOT_EQUAL "!=" +%token LESSER "<" +%token LESSER2 "<<" +%token LESSER_EQUAL "<=" +%token GREATER ">" +%token GREATER2 ">>" +%token GREATER_EQUAL ">=" +%token BAR "|" +%token ASTERISK "*" +%token PLUS "+" +%token MINUS "-" +%token SLASH "/" +%token SLASH2 "//" +%token QUESTION "?" + + +%token XQUERY //"xquery" +%token VERSION //"version" +%token PRAGMA //"pragma" +%token EXTENSION //"extension" +%token MODULE //"module" +%token NAMESPACE //"namespace" +%token DECLARE //"declare" +%token XMLSPACE //"xmlspace" +%token PRESERVE //"preserve" +%token STRIP //"strip" +%token DEFAULT //"default" +%token DOCUMENT_NODE //"document-node" +%token DOCUMENT //"document" +%token ELEMENT //"element" +%token ATTRIBUTE //"attribute" +%token PROCESSING_INSTRUCTION //"processing-instruction" +%token COMMENT //"comment" +%token TEXT //"text" +%token NODE //"node" +%token FUNCTION //"function" +%token COLLATION //"collation" +%token CONSTRUCTION //"construction" +%token ORDERING //"ordering" +%token ORDERED //"ordered" +%token UNORDERED //"unordered" +%token BASEURI //"base-uri" +%token IMPORT //"import" +%token SCHEMA //"schema" +%token AT //"at" +%token VARIABLE //"variable" +%token AS //"as" +%token EXTERNAL //"external" +%token VALIDATION //"validation" +%token LAX //"lax" +%token STRICT //"strict" +%token SKIP //"skip" +%token RETURN //"return" +%token FOR //"for" +%token LET //"let" +%token IN //"in" +%token WHERE //"where" +%token ORDER //"order" +%token BY //"by" +%token STABLE //"stable" +%token ASCENDING //"ascending" +%token DESCENDING //"descending" +%token EMPTY //"empty" +%token GREATEST //"greatest" +%token LEAST //"least" +%token SOME //"some" +%token EVERY //"every" +%token SATISFIES //"satisfies" +%token IS //"is" +%token TO //"to" +%token EQ //"eq" +%token NE //"ne" +%token LT //"lt" +%token LE //"le" +%token GT //"gt" +%token GE //"ge" +%token AND //"and" +%token OR //"or" +%token INSTANCE //"instance" +%token OF //"of" +%token IF //"if" +%token THEN //"then" +%token ELSE //"else" +%token TYPESWITCH //"typeswitch" +%token CASE //"case" +%token TREAT //"treat" +%token CASTABLE //"castable" +%token CAST //"as" +%token DIV //"div" +%token IDIV //"idiv" +%token MOD //"mod" +%token UNION //"union" +%token INTERSECT //"intersect" +%token EXCEPT //"except" +%token VALIDATE //"validate" +%token CONTEXT //"context" +%token NILLABLE //"nillable" +%token ITEM //"item" + + +%token GLOBAL //"global" +%token TYPE //"type" + +%token CHILD //"child" +%token DESCENDANT //"descendant" +%token ATTRIBUTE //"attribute" +%token SELF //"self" +%token DESCENDANT_OR_SELF //"descendant-or-self" +%token FOLLOWING_SIBLING //"following-sibling" +%token FOLLOWING //"following" +%token PARENT //"parent" +%token ANCESTOR //"ancestor" +%token PRECEDING_SIBLING //"preceding-sibling" +%token PRECEDING //"preceding" +%token ANCESTOR_OR_SELF //"ancestor-or-self" + + + +%token QNAME +%token NCNAME +%token WILD_LOCALNAME +%token WILD_PREFIX + +%token STRING_LITERAL +%token DECIMAL_LITERAL +%token DOUBLE_LITERAL + +%token PRAGMA_CONTENTS // characters until "::)" + + +%token PREDEFINED_ENTITY_REF +%token CHAR_REF + +// Used only inside Constructor +%token XML_COMMENT_START // "" +%token XML_PI_START // "" +%token XML_CDATA_START // " +%token EMPTY_TAG_CLOSE // "/>" +%token END_TAG_START // " there after state is Operator. + tokenizer.PushState (ParseState.Operator); + tokenizer.State = ParseState.StartTag; + // FIXME: tokenizer.Space = WhitespaceHandling.Significant; + } QName AttributeList FollowDirElemConstructor { + tokenizer.PopState (); + } + { + ExprSequence expr = new ExprSequence (); + expr.AddRange ((ICollection) $4); + expr.AddRange ((ICollection) $5); + $$ = new XmlElemConstructor ((XmlQualifiedName) $3, expr); + } + ; + +FollowDirElemConstructor // returns ExprSequence + : EMPTY_TAG_CLOSE + { + $$ = new ExprSequence (); + } + | GREATER { + tokenizer.State = ParseState.ElementContent; + } ElementContentList END_TAG_START { + tokenizer.State = ParseState.EndTag; + } QName { +// tokenizer.Space = WhitespaceHandling.Arbitrary; + } GREATER + { + $$ = $3; + } + ; + +ElementContentList // returns ExprSequence + : // empty + { + $$ = new ExprSequence (); + } + | ElementContent ElementContentList + { + ExprSequence el = (ExprSequence) $2; + el.Insert (0, (ExprSingle) $1); + $$ = el; + } + ; + +AttributeList // returns XmlAttrConstructorList + : // empty + { + $$ = new XmlAttrConstructorList (); + } + | /* space */ Attribute AttributeList + { + XmlAttrConstructorList al = (XmlAttrConstructorList) $2; + al.Insert (0, (XmlAttrConstructor) $1); + $$ = al; + } + ; + +Attribute // returns XmlAttrConstructor + : QName /* opt-space */ EQUAL /* opt-space */ AttributeValue + { + $$ = new XmlAttrConstructor ((XmlQualifiedName) $1, (ExprSequence) $3); + } + ; + +/* +// FIXME: it should be more complex +AttributeValue // returns ExprSequence + : STRING_LITERAL + { + ExprSequence es = new ExprSequence (); + es.Insert (0, new StringLiteralExpr ((string) $1)); + $$ = es; + } + ; +*/ + +AttributeValue // returns ExprSequence + : QUOT { + tokenizer.State = ParseState.QuotAttributeContent; + } AttributeValueContentSequence QUOT { + tokenizer.State = ParseState.StartTag; + } + { + $$ = $3; + } + | APOS { + tokenizer.State = ParseState.AposAttributeContent; + } AttributeValueContentSequence APOS { + tokenizer.State = ParseState.StartTag; + } + { + $$ = $3; + } + ; + + +AttributeValueContentSequence // returns ExprSequence + : // empty + { + $$ = new ExprSequence (); + } + | AttributeValueContent AttributeValueContentSequence + { + ExprSequence es = (ExprSequence) $2; + es.Insert (0, (ExprSingle) $1); + $$ = es; + } + ; + +AttributeValueContent // returns ExprSingle + : ATT_VALUE_LITERAL // including "{{", "}}" and char/predefined entities + { + $$ = new StringLiteralExpr ((string) $1); + } + | EnclosedExpr + ; + +EnclosedExpr // returns EnclosedExpr + // FIXME: check if this state transition is valid for ElementContent and AttributeValueContent + : OPEN_CURLY { + switch (tokenizer.State) { + case ParseState.ElementContent: + case ParseState.QuotAttributeContent: + case ParseState.AposAttributeContent: + tokenizer.PushState (tokenizer.State); + break; + } + tokenizer.State = ParseState.Default; + } Expr CloseCurly + { + $$ = new EnclosedExpr ((ExprSequence) $3); + } + ; + +ElementContent // returns ExprSingle + : ELEM_CONTENT_LITERAL // including "{{", "}}" and char/predefined entities + { + $$ = new XmlTextConstructor ((string) $1); + } + | DirElemConstructor + | EnclosedExpr + | XmlCData + | XmlComment + | XmlPI + ; + +XmlCData + : XML_CDATA_START XML_CDATA_TO_END + { + $$ = new XmlTextConstructor ((string) $2); + } + ; + +XmlComment // returns XmlCommentConstructor + : XML_COMMENT_START XML_COMMENT_TO_END + { + $$ = new XmlCommentConstructor ((string) $2); + } + ; + +XmlPI // returns XmlPIConstructor + : XML_PI_START { + tokenizer.PushState (tokenizer.State); + tokenizer.State = ParseState.XmlPI; + } PITarget { + tokenizer.State = ParseState.XmlPIContent; + } XML_PI_TO_END { + tokenizer.PopState (); + } + { + string name = (string) $3; + $$ = new XmlPIConstructor (name, (string) $5); + } + ; + +PITarget + : NCName + ; + +ComputedConstructor // returns ExprSingle + : CompElemConstructor + | CompAttrConstructor + | CompDocConstructor + | CompTextConstructor + | CompXmlPI + | CompXmlComment + | CompNSConstructor + ; + +CompElemConstructor + : ELEMENT QName OPEN_CURLY Expr CloseCurly + { + $$ = new XmlElemConstructor ((XmlQualifiedName) $2, (ExprSequence) $4); + } + | ELEMENT OPEN_CURLY Expr CloseCurly OPEN_CURLY Expr CloseCurly + { + $$ = new XmlElemConstructor ((ExprSequence) $3, (ExprSequence) $6); + } + ; + +CompAttrConstructor + : ATTRIBUTE QName OPEN_CURLY Expr CloseCurly + { + $$ = new XmlAttrConstructor ((XmlQualifiedName) $2, (ExprSequence) $4); + } + | ATTRIBUTE OPEN_CURLY Expr CloseCurly OPEN_CURLY Expr CloseCurly + { + $$ = new XmlAttrConstructor ((ExprSequence) $3, (ExprSequence) $6); + } + ; + +CompNSConstructor + : NAMESPACE NCName OPEN_CURLY Expr CloseCurly + { + $$ = new XmlNSConstructor ((string) $2, (ExprSequence) $4); + } + ; + +CompDocConstructor + : DOCUMENT OPEN_CURLY Expr CloseCurly + { + $$ = new XmlDocConstructor ((ExprSequence) $3); + } + ; + +CompTextConstructor + : TEXT OPEN_CURLY Expr CloseCurly + { + $$ = new XmlTextConstructor ((ExprSequence) $3); + } + ; + +CompXmlComment + : COMMENT OPEN_CURLY Expr CloseCurly + { + $$ = new XmlCommentConstructor ((ExprSequence) $3); + } + ; + +CompXmlPI + : PROCESSING_INSTRUCTION NCName OPEN_CURLY Expr CloseCurly + { + $$ = new XmlPIConstructor ((string) $2, (ExprSequence) $4); + } + | PROCESSING_INSTRUCTION OPEN_CURLY Expr CloseCurly OPEN_CURLY Expr CloseCurly + { + $$ = new XmlPIConstructor ((ExprSequence) $3, (ExprSequence) $6); + } + ; + +/* ----------------- + Terminal Wrappers +----------------- */ + + +NCName // returns string + : NCNAME + ; + +QName // returns XmlQualifiedName. Note that this state is just a wrapper for state transition. + : QNAME { + switch (tokenizer.State) { + case ParseState.Default: + tokenizer.State = ParseState.Operator; + break; + case ParseState.ItemType: + tokenizer.State = ParseState.OccurenceIndicator; + break; + case ParseState.KindTest: + case ParseState.SchemaContextStep: + tokenizer.State = ParseState.CloseKindTest; + break; + case ParseState.ExtKey: + tokenizer.State = ParseState.ExprComment; + break; + } + } + ; + +Slash + : SLASH { + switch (tokenizer.State) { + case ParseState.Operator: + tokenizer.State = ParseState.Default; + break; + case ParseState.KindTest: + tokenizer.State = ParseState.SchemaContextStep; + break; + } + } + ; + +Slash2 + : SLASH2 { + if (tokenizer.State == ParseState.Operator) + tokenizer.State = ParseState.Default; + } + ; + +CloseCurly + : CLOSE_CURLY { + if (tokenizer.State == ParseState.Operator) + tokenizer.PopState (); + } + ; + +%% + +} + +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryStaticContext.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryStaticContext.cs new file mode 100755 index 00000000000..e17033f21a9 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryStaticContext.cs @@ -0,0 +1,231 @@ +// +// XQueryStaticContext.cs - XQuery static context components +// +// Author: +// Atsushi Enomoto +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// + +#if NET_2_0 + +using System; +using System.Collections; +using System.Collections.Specialized; +using System.Globalization; +using System.IO; +using System.Security.Policy; +using System.Xml; +using System.Xml.Query; +using System.Xml.Schema; +using Mono.Xml.XPath2; + +namespace Mono.Xml.XPath2 +{ + // Holds static context, that is created for each module. + internal class XQueryStaticContext + { + public static XQueryStaticContext Optimize (XQueryStaticContext ctx) + { + // FIXME: do type promotion and expression reduction + return ctx; + } + + // Don't keep XQueryCompileOptions and XQueryMainModule + // inside this class. I don't want them affect this instance + // by being modified externally after the compilation. + + public XQueryStaticContext ( + XQueryCompileOptions options, + XQueryCompileContext compileContext, + ExprSequence queryBody, + XmlSchemaSet inScopeSchemas, + IDictionary inScopeVariables, + XQueryFunctionTable functionSignatures, + IXmlNamespaceResolver nsResolver, + string defaultFunctionNamespace, + bool preserveWhitespace, + bool constructionSpace, + bool defaultOrdered, + string baseUri, + Evidence evidence, + XQueryCommandImpl commandImpl) + { + // Initialization phase. + compat = options.Compatibility; + nameTable = options.NameTable; + this.queryBody = queryBody; + this.nsResolver = nsResolver; + this.defaultFunctionNamespace = defaultFunctionNamespace; +// elemNSManager = new XmlNamespaceManager (nameTable); +// funcNSManager = new XmlNamespaceManager (nameTable); + xqueryFlagger = options.XQueryFlagger; + xqueryStaticFlagger = options.XQueryStaticFlagger; +// xqueryResolver = options.KnownDocumentResolver; + knownCollections = (IDictionary) options.KnownCollections.Clone (); + functions = functionSignatures; + this.compileContext = compileContext; + this.inScopeSchemas = inScopeSchemas; + this.inScopeVariables = inScopeVariables; + this.preserveWhitespace = preserveWhitespace; + this.preserveConstructionSpace = constructionSpace; + this.defaultOrdered = defaultOrdered; + this.baseUri = baseUri; + this.defaultCollation = options.DefaultCollation; + // FIXME: set contextItemStaticType + // FIXME: set extDocResolver + + this.evidence = evidence; + this.commandImpl = commandImpl; + } + + // It holds in-effect components et. al. + XQueryCompileContext compileContext; + + XmlNameTable nameTable; + Evidence evidence; // for safe custom function execution / safe assembly loading + XQueryCommandImpl commandImpl; // for event delegate + + ExprSequence queryBody; + + // See XQuery 1.0, 2.1.1 "Static Context" + XmlQueryDialect compat; // XPath 1.0 compatibility mode + IXmlNamespaceResolver nsResolver; // Manages "statically known namespaces" and "default element/type namespace" + string defaultFunctionNamespace; // default function namespace + XmlSchemaSet inScopeSchemas; // in-scope schemas + IDictionary inScopeVariables; + Type contextItemStaticType; // TODO: context item static type? + XQueryFunctionTable functions; + + // Statically known collations is not defined here. It is equal to all supported CultureInfo. +// IDictionary staticallyKnownCollations; + + CultureInfo defaultCollation; // or TextInfo ? + bool preserveConstructionSpace; // construction mode + bool defaultOrdered; // Ordering mode + bool preserveWhitespace; // Xml space policy + string baseUri; +// XmlResolver extDocResolver; // statically known documents + IDictionary knownCollections; // statically known collections + bool xqueryFlagger; + bool xqueryStaticFlagger; + + // Properties + + public XQueryCompileContext CompileContext { + get { return compileContext; } + } + + public XmlQueryDialect Compatibility { + get { return compat; } + } + + public ExprSequence QueryBody { + get { return queryBody; } + } + + public XmlNameTable NameTable { + get { return nameTable; } + } + + public Evidence Evidence { + get { return evidence; } + } + + public CultureInfo DefaultCollation { + get { return defaultCollation; } + } + + public XmlSchemaSet InScopeSchemas { + get { return inScopeSchemas; } + } + + // in-scope functions. + public XQueryFunctionTable InScopeFunctions { + get { return functions; } + } + + // in-scope variables. XmlQualifiedName to XPathItem + public IDictionary InScopeVariables { + get { return inScopeVariables; } + } + + public bool PreserveWhitespace { + get { return preserveWhitespace; } + } + + public bool PreserveConstructionSpace { + get { return preserveConstructionSpace; } + } + + public bool DefaultOrdered { + get { return defaultOrdered; } + } + + // statically known collections. string to ICollection (or XPathItemIterator, or XPathNodeIterator). + public IDictionary KnownCollections { + get { return knownCollections; } + } + + public bool XQueryFlagger { + get { return xqueryFlagger; } + } + + public bool XQueryStaticFlagger { + get { return xqueryStaticFlagger; } + } + + public string BaseUri { + get { return baseUri; } + } + + public IXmlNamespaceResolver NSResolver { + get { return nsResolver; } + } + + public string DefaultFunctionNamespace { + get { return defaultFunctionNamespace; } + set { defaultFunctionNamespace = value; } + } + + // FIXME: consider those from imported modules + public XQueryFunction ResolveFunction (XmlQualifiedName name) + { + XQueryFunction f = functions [name]; + if (f != null) + return f; + return null; + } + + // FIXME: wait for W3C clarification. + internal CultureInfo GetCulture (string collation) + { + return null; + } + + internal void OnMessageEvent (object sender, QueryEventArgs e) + { + commandImpl.ProcessMessageEvent (sender, e); + } + } +} +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryTokenizer.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryTokenizer.cs new file mode 100755 index 00000000000..67a10da8ce9 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XQueryTokenizer.cs @@ -0,0 +1,1285 @@ +// +// XQueryTokenizer.cs +// +// Author: +// Atsushi Enomoto +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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. +// +#if NET_2_0 + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Security.Policy; +using System.Xml; +using System.Xml.Query; +using System.Xml.Schema; +using System.Xml.XPath; +using Mono.Xml.XQuery; +using Mono.Xml.XPath2; +using Mono.Xml; + +namespace Mono.Xml.XQuery.Parser +{ + // FIXME: make internal in the future + public class XQueryTokenizer + : Mono.Xml.XQuery.Parser.yyParser.yyInput, IXmlLineInfo + { + int line = 1; + int column = 0; + bool nextIncrementLine; + + // namespace resolver + XmlNamespaceManager nsResolver; + string defaultFunctionNamespace = XQueryFunction.Namespace; + + // input source + TextReader source; + int peekChar = -1; + + // token info + int currentToken; + string prefixName; + object tokenValue; + + int lookAheadToken = -1; + object lookAheadTokenValue; + + // state info + WhitespaceHandling ws = WhitespaceHandling.Arbitrary; + ParseState state = ParseState.Default; + Stack stateStack; + + char [] buffer = new char [30]; + int bufferIndex; + + public XQueryTokenizer (TextReader reader) + { + this.source = reader; + + stateStack = new Stack (); + + nsResolver = new XmlNamespaceManager (new NameTable ()); + nsResolver.AddNamespace ("xs", XmlSchema.Namespace); + nsResolver.AddNamespace ("xdt", InternalPool.XdtNamespace); + // FIXME: Are they really predefined? + nsResolver.AddNamespace ("xsi", XmlSchema.InstanceNamespace); + nsResolver.AddNamespace ("fn", "http://www.w3.org/2003/11/xpath-functions"); + nsResolver.AddNamespace ("local", "http://www.w3.org/2003/11/xquery-local-functions"); + } + + internal IXmlNamespaceResolver NSResolver { + get { return nsResolver; } + } + + internal string DefaultFunctionNamespace { + get { return defaultFunctionNamespace; } + set { defaultFunctionNamespace = value; } + } + + public void AddNamespace (string prefix, string ns) + { + nsResolver.AddNamespace (prefix, ns); + } + + public bool advance () + { + if (currentToken < 0) + return false; + if (lookAheadToken >= 0) { + tokenValue = lookAheadTokenValue; + currentToken = lookAheadToken; + lookAheadToken = -1; + } + else + currentToken = ParseToken (); + return currentToken >= 0; + } + + public int token () + { + return currentToken; + } + + public object value () + { + return tokenValue; + } + + public bool HasLineInfo () + { + return true; + } + + public int LineNumber { + get { return line; } + } + + public int LinePosition { + get { return column; } + } + + internal WhitespaceHandling Space { + get { return ws; } + set { ws = value; } + } + + internal ParseState State { + get { return state; } + set { +// Console.Error.WriteLine ("**** eno **** state transition from {0} to {1}, stack count = {2}", state, value, stateStack.Count); +//foreach (ParseState ps in stateStack.ToArray ()) Console.Error.WriteLine ("***** eno ***** " + ps); + state = value; + } + } + + internal void PushState (ParseState newState) + { + stateStack.Push (newState); +// Console.Error.WriteLine ("**** eno **** state pushed {0}, added stack count = {1}", newState, stateStack.Count); +//foreach (ParseState ps in stateStack.ToArray ()) Console.Error.WriteLine ("***** eno ***** " + ps); + } + + internal void PopState () + { + if (stateStack.Count == 0) + throw Error ("Internal state transition error. State stack is empty."); + state = (ParseState) stateStack.Pop (); +// Console.Error.WriteLine ("**** eno **** state pop, now as {0}, stack count = {1}", state, stateStack.Count); +//foreach (ParseState ps in stateStack.ToArray ()) Console.Error.WriteLine ("***** eno ***** " + ps); + } + + private XmlQueryCompileException Error (string message) + { + return new XmlQueryCompileException (message, this, null, null); + } + + private int ParseToken () + { + bufferIndex = 0; + + switch (state) { + case ParseState.StartTag: + break; + default: + SkipWhitespaces (); + break; + } + /* + switch (ws) { + case WhitespaceHandling.Arbitrary: + SkipWhitespaces (); + break; + case WhitespaceHandling.Explicit: + if (!XmlChar.IsWhitespace (PeekChar ())) + throw Error ("Whitespace is required."); + goto case WhitespaceHandling.Arbitrary; + } + */ + + int c = PeekChar (); + if (c < 0) + return -1; + + // FIXME: consider DOUBLE_LITERAL + if (Char.IsNumber ((char) c)) { + tokenValue = ReadDecimal (false); + return Token.DECIMAL_LITERAL; + } + + switch (state) { + case ParseState.OccurenceIndicator: + return ParseOccurenceIndicator (); + case ParseState.XmlPIContent: + return ParseXmlPIContent (); + case ParseState.XmlComment: + return ParseXmlCommentContent (); + case ParseState.ElementContent: + return ParseElementContent (); + case ParseState.StartTag: + return ParseStartTag (); + case ParseState.QuotAttributeContent: + return ParseAttributeContent ('"'); + case ParseState.AposAttributeContent: + return ParseAttributeContent ('\''); + default: + return ParseDefault (); + } + } + + private int ParseXQueryComment () + { + while (true) { + int c = ReadChar (); + if (c < 0) + throw Error ("Unexpected end of query text inside XML processing instruction content"); + if (c == ':') { + if (PeekChar () == ')') { + ReadChar (); + tokenValue = CreateValueString (); + return Token.XML_PI_TO_END; + } + else + AddValueChar (':'); + } + else + AddValueChar ((char) c); + } + } + + private int ParseXmlPIContent () + { + while (true) { + int c = ReadChar (); + if (c < 0) + throw Error ("Unexpected end of query text inside XML processing instruction content"); + if (c == '?') { + if (PeekChar () == '>') { + ReadChar (); + tokenValue = CreateValueString (); + return Token.XML_PI_TO_END; + } + else + AddValueChar ('?'); + } + else + AddValueChar ((char) c); + } + } + + private int ParseXmlCommentContent () + { + // FIXME: handle ---> correctly + while (true) { + int c = ReadChar (); + if (c < 0) + throw Error ("Unexpected end of query text inside XML comment content"); + if (c == '-') { + if (PeekChar () == '-') { + ReadChar (); + if (PeekChar () == '>') { + tokenValue = CreateValueString (); + return Token.XML_COMMENT_TO_END; + } else { + AddValueChar ('-'); + AddValueChar ('-'); + } + } + else + AddValueChar ('-'); + } + else + AddValueChar ((char) c); + } + } + + private int ParseXmlCDataContent () + { + // FIXME: handle ]]]> correctly + while (true) { + int c = ReadChar (); + if (c < 0) + throw Error ("Unexpected end of query text inside XML CDATA section content"); + if (c == ']') { + ReadChar (); + if (PeekChar () == ']') { + ReadChar (); + if (PeekChar () == '>') { + tokenValue = CreateValueString (); + return Token.XML_CDATA_TO_END; + } else { + AddValueChar (']'); + AddValueChar (']'); + } + } + else + AddValueChar (']'); + } + else + AddValueChar ((char) c); + } + } + + private int ParseElementContent () + { + tokenValue = null; + int c = PeekChar (); + if (c < 0) + throw Error ("Unexpected end of query text inside XML processing instruction content"); + switch ((char) c) { + case '<': + case '{': + return ParseDefault (); + } + + while (true) { + c = PeekChar (); + if (c < 0) + throw Error ("Unexpected end of query text inside XML processing instruction content"); + switch ((char) c) { + case '&': + ReadChar (); + ReadPredefinedEntity (); + continue; + case '<': + tokenValue += CreateValueString (); + return Token.ELEM_CONTENT_LITERAL; + default: + AddValueChar ((char) c); + ReadChar (); + continue; + } + } + } + + private void ReadPredefinedEntity () + { + string token = ReadOneToken (); + Expect (";"); + switch (token) { + case "lt": + AddValueChar ('<'); + return; + case "gt": + AddValueChar ('>'); + return; + case "amp": + AddValueChar ('&'); + return; + case "quot": + AddValueChar ('"'); + return; + case "apos": + AddValueChar ('\''); + return; + default: + throw Error (String.Format ("Unexpected general entity name: {0} .", token)); + } + } + + // FIXME: not used as yet + private int ParseExtContent () + { + // FIXME: handle :::) correctly + while (true) { + int c = PeekChar (); + if (c < 0) + throw Error ("Unexpected end of query text inside external content"); + if (c == ':') { + ReadChar (); + if (PeekChar () == ':') { + ReadChar (); + if (PeekChar () == ')') { + tokenValue = CreateValueString (); + return Token.EXT_CONTENT; + } else { + AddValueChar (':'); + AddValueChar (':'); + } + } + else + AddValueChar (':'); + } + else + AddValueChar ((char) c); + } + } + + private int ParseOccurenceIndicator () + { + state = ParseState.Operator; + switch (PeekChar ()) { + case '?': + ReadChar (); + return Token.QUESTION; + case '*': + ReadChar (); + return Token.ASTERISK; + case '+': + ReadChar (); + return Token.PLUS; + default: + return ParseOperator (); + } + } + + private int ParseStartTag () + { + int c = PeekChar (); + switch (c) { + case '\'': + ReadChar (); + return Token.APOS; + case '"': + ReadChar (); + return Token.QUOT; + case '>': + ReadChar (); + return Token.GREATER; + case '/': + ReadChar (); + Expect (">"); + return Token.EMPTY_TAG_CLOSE; + } + // FIXME: there seems a bug in the spec that StartTag + // state must accept QName without heading space for + // start tag name. +// if (!XmlChar.IsWhitespace (PeekChar ())) +// throw Error ("Whitespace is required."); + SkipWhitespaces (); + return ParseDefault (); // only QName is allowed here. + } + + private int ParseAttributeContent (char closeChar) + { + int t = Token.ATT_VALUE_LITERAL; + while (true) { + int c = PeekChar (); + if (c < 0) + throw Error ("Unexpected end of attribute value content."); + if (c == closeChar) { + ReadChar (); + c = PeekChar (); + if (c == closeChar) { + ReadChar (); + AddValueChar (closeChar); + } + else + t = closeChar == '"' ? Token.QUOT : Token.APOS; + } + else if (c == '{') { + ReadChar (); + c = PeekChar (); + if (c == '{') { + ReadChar (); + AddValueChar ('{'); + } + else + t = Token.OPEN_CURLY; + } + else + AddValueChar ((char) ReadChar ()); + + if (t != Token.ATT_VALUE_LITERAL) { + if (bufferIndex > 0) { + lookAheadToken = t; + tokenValue = CreateValueString (); + return Token.ATT_VALUE_LITERAL; + } + else + return t; + } + } + } + + private int ParseOperator () + { + // TODO: implement + return ParseDefault (); + } + + private int ParseDefault () + { + int c = ReadChar (); + switch (c) { + case '.': + if (PeekChar () == '.') { + ReadChar (); + return Token.DOT2; + } + else if (Char.IsNumber ((char) PeekChar ())) { + tokenValue = ReadDecimal (true); + } + return Token.DOT; + case ',': + return Token.COMMA; + case ';': + return Token.SEMICOLON; + case '(': + if (PeekChar () == ':') { + ReadChar (); + if (PeekChar () == ':') { + ReadChar (); + return Token.PRAGMA_OPEN; + } + ParseXQueryComment (); + return ParseToken (); // start again + } + return Token.OPEN_PAREN; + case ')': + return Token.CLOSE_PAREN; + case ':': + switch (PeekChar ()) { + case ':': + ReadChar (); + if (PeekChar () == ')') { + ReadChar (); + return Token.PRAGMA_CLOSE; + } + return Token.COLON2; + case ')': + ReadChar (); + return Token.CLOSE_PAREN_COLON; + case '=': + ReadChar (); + return Token.COLON_EQUAL; + } + return Token.COLON; + case '[': + return Token.OPEN_BRACKET; + case ']': + return Token.CLOSE_BRACKET; + case '{': + return Token.OPEN_CURLY; + case '}': + return Token.CLOSE_CURLY; + case '$': + return Token.DOLLAR; + case '\'': + tokenValue = ReadQuoted ('\''); + return Token.STRING_LITERAL; + case '"': + tokenValue = ReadQuoted ('"'); + return Token.STRING_LITERAL; + case '=': + return Token.EQUAL; + case '<': + // only happens when state is ElementContent + // (otherwise it might be "/foo': + switch (PeekChar ()) { + case '>': + ReadChar (); + return Token.GREATER2; + case '=': + ReadChar (); + return Token.GREATER_EQUAL; + } + return Token.GREATER; + case '|': + return Token.BAR; + case '*': + if (PeekChar () == ':') { + ReadChar (); + // FIXME: more check + tokenValue = new XmlQualifiedName (ReadOneToken (), "*"); + return Token.WILD_PREFIX; + } + return Token.ASTERISK; + case '+': + return Token.PLUS; + case '-': + return Token.MINUS; + case '/': + // only happens when state is StartTag + // (otherwise it might be "/>$extvar") + if (state == ParseState.StartTag && PeekChar () == '>') { + ReadChar (); + return Token.EMPTY_TAG_CLOSE; + } + if (PeekChar () == '/') { + ReadChar (); + return Token.SLASH2; + } + return Token.SLASH; + case '?': + return Token.QUESTION; + case '@': + return Token.AT; + } + + peekChar = c; + prefixName = null; + string name = ReadOneToken (); + + tokenValue = name; + bool validKeyword = false; + + switch (state) { + case ParseState.XmlSpaceDecl: + switch (name) { + case "preserve": + return Token.PRESERVE; + case "strip": + return Token.STRIP; + } + break; + case ParseState.CloseKindTest: + if (name == "nillable") + return Token.NILLABLE; + break; + case ParseState.ExtKey: + switch (name) { + case "pragma": + return Token.PRAGMA; + case "extension": + return Token.EXTENSION; + } + break; + case ParseState.KindTest: + switch (name) { + case "context": + return Token.CONTEXT; + case "element": + return Token.ELEMENT; + case "global": + return Token.GLOBAL; + case "type": + return Token.TYPE; + } + break; + case ParseState.ItemType: + switch (name) { + case "attribute": + return Token.ATTRIBUTE; + case "comment": + return Token.COMMENT; + case "document-node": + return Token.DOCUMENT_NODE; + case "element": + return Token.ELEMENT; + case "empty": + return Token.EMPTY; + case "item": + return Token.ITEM; + case "node": + return Token.NODE; + case "processing-instruction": + return Token.PROCESSING_INSTRUCTION; + case "text": + return Token.TEXT; + } + break; + case ParseState.NamespaceKeyword: + switch (name) { + case "declare": + return Token.DECLARE; + case "default": + return Token.DEFAULT; + case "element": + return Token.ELEMENT; + case "function": + return Token.FUNCTION; + case "namespace": + return Token.NAMESPACE; + } + break; + case ParseState.OccurenceIndicator: + case ParseState.Operator: + switch (name) { + case "and": + case "as": + case "ascending": + case "at": + case "base-uri": + case "by": + case "case": + case "cast": + case "castable": + case "collation": + case "declare": + case "default": + case "descending": + case "div": + case "element": + case "else": + case "empty": + case "eq": + case "every": + case "except": + case "external": + case "for": + case "function": + case "ge": + case "global": + case "greatest": + case "gt": + case "idiv": + case "import": + case "in": + case "instance": + case "intersect": + case "is": + case "lax": + case "le": + case "least": + case "let": + case "lt": + case "mod": + case "module": + case "namespace": + case "ne": + case "of": + case "or": + case "order": + case "ordered": + case "ordering": + case "return": + case "satisfies": + case "schema": + case "skip": + case "some": + case "stable": + case "strict": + case "then": + case "to": + case "treat": + case "typwswitch": + case "union": + case "unordered": + case "variable": + case "where": + case "xmlspace": + validKeyword = true; + break; + } + break; + case ParseState.Default: + switch (name) { + case "ancestor": + case "ancestor-or-self": + case "as": + case "attribute": + case "base-uri": + case "child": + case "collation": + case "comment": + case "construction": + case "declare": + case "default": + case "descendant": + case "descendant-or-self": + case "document": + case "document-node": + case "element": + case "every": + case "following": + case "following-sibling": + case "for": + case "function": + case "global": + case "if": + case "import": + case "lax": + case "let": + case "module": + case "namespace": + case "node": + case "ordered": + case "parent": + case "preceding": + case "preceding-sibling": + case "processing-instruction": + case "schema": + case "self": + case "some": + case "strict": + case "strip": + case "text": + case "typeswitch": + case "unordered": + case "validate": + case "validation": + case "version": + case "xmlspace": + case "xquery": + validKeyword = true; + break; + } + break; + } + + if (validKeyword) { + switch (name) { + case "xquery": + return Token.XQUERY; + case "version": + return Token.VERSION; + case "pragma": + return Token.PRAGMA; + case "extension": + return Token.EXTENSION; + case "module": + return Token.MODULE; + case "namespace": + return Token.NAMESPACE; + case "declare": + return Token.DECLARE; + case "xmlspace": + return Token.XMLSPACE; + case "preserve": + return Token.PRESERVE; + case "strip": + return Token.STRIP; + case "default": + return Token.DEFAULT; + case "construction": + return Token.CONSTRUCTION; + case "ordering": + return Token.ORDERING; + case "ordered": + return Token.ORDERED; + case "unordered": + return Token.UNORDERED; + case "document-node": + return Token.DOCUMENT_NODE; + case "document": + return Token.DOCUMENT; + case "element": + return Token.ELEMENT; + case "attribute": + return Token.ATTRIBUTE; + case "processing-instruction": + return Token.PROCESSING_INSTRUCTION; + case "comment": + return Token.COMMENT; + case "text": + return Token.TEXT; + case "node": + return Token.NODE; + case "function": + return Token.FUNCTION; + case "collation": + return Token.COLLATION; + case "base-uri": + return Token.BASEURI; + case "import": + return Token.IMPORT; + case "schema": + return Token.SCHEMA; + case "at": + return Token.AT; + case "variable": + return Token.VARIABLE; + case "as": + return Token.AS; + case "external": + return Token.EXTERNAL; + case "validation": + return Token.VALIDATION; + case "lax": + return Token.LAX; + case "strict": + return Token.STRICT; + case "skip": + return Token.SKIP; + case "return": + return Token.RETURN; + case "for": + return Token.FOR; + case "let": + return Token.LET; + case "in": + return Token.IN; + case "where": + return Token.WHERE; + case "order": + return Token.ORDER; + case "by": + return Token.BY; + case "stable": + return Token.STABLE; + case "ascending": + return Token.ASCENDING; + case "descending": + return Token.DESCENDING; + case "empty": + return Token.EMPTY; + case "greatest": + return Token.GREATEST; + case "least": + return Token.LEAST; + case "some": + return Token.SOME; + case "every": + return Token.EVERY; + case "satisfies": + return Token.SATISFIES; + case "is": + return Token.IS; + case "to": + return Token.TO; + case "eq": + return Token.EQ; + case "ne": + return Token.NE; + case "lt": + return Token.LT; + case "le": + return Token.LE; + case "gt": + return Token.GT; + case "ge": + return Token.GE; + case "and": + return Token.AND; + case "or": + return Token.OR; + case "instance": + return Token.INSTANCE; + case "of": + return Token.OF; + case "if": + return Token.IF; + case "then": + return Token.THEN; + case "else": + return Token.ELSE; + case "typeswitch": + return Token.TYPESWITCH; + case "case": + return Token.CASE; + case "treat": + return Token.TREAT; + case "castable": + return Token.CASTABLE; + case "cast": + return Token.CAST; + case "div": + return Token.DIV; + case "idiv": + return Token.IDIV; + case "mod": + return Token.MOD; + case "union": + return Token.UNION; + case "intersect": + return Token.INTERSECT; + case "except": + return Token.EXCEPT; + case "validate": + return Token.VALIDATE; + case "context": + return Token.CONTEXT; + case "nillable": + return Token.NILLABLE; + case "item": + return Token.ITEM; + case "global": + return Token.GLOBAL; + case "type": + return Token.TYPE; + case "child": + return Token.CHILD; + case "descendant": + return Token.DESCENDANT; + case "self": + return Token.SELF; + case "descendant-or-self": + return Token.DESCENDANT_OR_SELF; + case "following-sibling": + return Token.FOLLOWING_SIBLING; + case "following": + return Token.FOLLOWING; + case "parent": + return Token.PARENT; + case "ancestor": + return Token.ANCESTOR; + case "preceding": + return Token.PRECEDING; + case "preceding-sibling": + return Token.PRECEDING_SIBLING; + case "ancestor-or-self": + return Token.ANCESTOR_OR_SELF; + } + } + + switch (state) { + case ParseState.NamespaceDecl: + case ParseState.NamespaceKeyword: + case ParseState.XmlSpaceDecl: + case ParseState.KindTestForPI: + case ParseState.XmlPI: + return Token.NCNAME; + } + + if (PeekChar () == ':') { + ReadChar (); + prefixName = name; + switch (PeekChar ()) { + case '*': + ReadChar (); + name = "*"; + break; + case '=': // ex. let foo:= ... + ReadChar (); + tokenValue = new XmlQualifiedName (name, nsResolver.DefaultNamespace); + lookAheadToken = Token.COLON_EQUAL; + return Token.QNAME; + default: + name = ReadOneToken (); + break; + } + + string ns = nsResolver.LookupNamespace (prefixName); + if (ns == null) + throw Error (String.Format ("Prefix '{0}' is not mapped to any namespace URI.", prefixName)); + tokenValue = new XmlQualifiedName (name, ns); + prefixName = null; + return name == "*" ? Token.WILD_LOCALNAME : Token.QNAME; + } + tokenValue = new XmlQualifiedName (name); + return Token.QNAME; + } + + private int PeekChar () + { + if (peekChar == -1) + peekChar = source.Read (); + return peekChar; + } + + private int ReadChar () + { + int ret; + if (peekChar != -1) { + ret = peekChar; + peekChar = -1; + } + else + ret = source.Read (); + + if (nextIncrementLine) { + line++; + column = 0; + nextIncrementLine = false; + } + column++; + switch (ret) { + case '\r': + break; + case '\n': + nextIncrementLine = true; + goto default; + default: + break; + } + + return ret; + } + + private void SkipWhitespaces () + { + while (true) { + switch (PeekChar ()) { + case ' ': + case '\t': + case '\r': + case '\n': + ReadChar (); + continue; + default: + return; + } + } + } + + private void AddValueChar (char c) + { + if (bufferIndex == buffer.Length) { + char [] newBuf = new char [bufferIndex * 2]; + Array.Copy (buffer, newBuf, bufferIndex); + buffer = newBuf; + } + buffer [bufferIndex++] = c; + } + + private string CreateValueString () + { + return new string (buffer, 0, bufferIndex); + } + + private void Expect (string expected) + { + for (int i = 0; i < expected.Length; i++) + if (ReadChar () != expected [i]) + throw Error (String.Format ("Expected token '{0}' did not appear.", expected)); + } + + // TODO: parse three quoted + private string ReadQuoted (char quoteChar) + { + bufferIndex = 0; + bool loop = true; + do { + int c = ReadChar (); + switch (c) { + case -1: + case '"': + if (quoteChar == '"') + loop = false; + break; + case '\'': + if (quoteChar == '\'') + loop = false; + break; + default: + AddValueChar ((char) c); + break; + } + } while (loop); + + return CreateValueString (); + } + + private decimal ReadDecimal (bool floatingPoint) + { + bufferIndex = 0; + bool cond = true; + do { + int c = PeekChar (); + if (c < 0) { + cond = false; + } + // FIXME: more complex + else if (Char.IsNumber ((char) c) || c == '.') { + ReadChar (); + AddValueChar ((char) c); + continue; + } + else + cond = false; + } while (cond); + string s = (floatingPoint ? "." : "") + CreateValueString (); + return decimal.Parse (s); + } + + private string ReadOneToken () + { + bufferIndex = 0; + bool loop = true; + do { + int c = PeekChar (); + switch (c) { + case -1: + case ' ': + case '\t': + case '\r': + case '\n': + loop = false; + break; + default: + if (!IsTokenContinuable (c)) { + if (c == ':') { + if (prefixName != null) + throw new XmlQueryCompileException ("Invalid colon was found."); + prefixName = CreateValueString (); + } + loop = false; + break; + } + + ReadChar (); + AddValueChar ((char) c); + break; + } + } while (loop); + + return CreateValueString (); + } + + private bool IsTokenContinuable (int c) + { + switch (c) { + case '-': + case '_': + case '.': + return true; + } + return XmlChar.IsNCNameChar (c); + } + + } + + public enum WhitespaceHandling { + Arbitrary, + Explicit, + Significant + } + + public enum ParseState { + Default, + Operator, + NamespaceDecl, + NamespaceKeyword, + XmlSpaceDecl, + ItemType, + KindTest, + KindTestForPI, + CloseKindTest, + OccurenceIndicator, + SchemaContextStep, + VarName, + StartTag, + ElementContent, + EndTag, + XmlComment, + ExprComment, + ExtKey, + XmlPI, + XmlPIContent, + CDataSection, + QuotAttributeContent, + AposAttributeContent, + } + +} +#endif diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XmlQueryCompileException.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XmlQueryCompileException.cs new file mode 100755 index 00000000000..c0edeb22b80 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XmlQueryCompileException.cs @@ -0,0 +1,74 @@ +// +// System.Xml.Query.XmlQueryCompileException +// +// Author: +// Tim Coleman (tim@timcoleman.com) +// Atsushi Enomoto (atsushi@ximian.com) +// +// Copyright (C) Tim Coleman, 2003 +// Copyright (C) Novell Inc., 2004 +// + +// +// 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. +// + +#if NET_2_0 + +using System; +using System.Runtime.Serialization; + +namespace System.Xml.Query +{ + [Serializable] + public class XmlQueryCompileException : XmlQueryException + { + #region Constructors + + protected XmlQueryCompileException (SerializationInfo info, StreamingContext context) + : base (info, context) + { + } + + public XmlQueryCompileException () + : base ("An XML Query Compile Exception has occurred.") + { + } + + public XmlQueryCompileException (string res) + : this (res, null, null, null) + { + } + + public XmlQueryCompileException (string resource, Exception exception) + : this (resource, null, null, exception) + { + } + + internal XmlQueryCompileException (string message, IXmlLineInfo li, string sourceUri, Exception innerException) + : base (message, li, sourceUri, innerException) + { + } + + #endregion // Constructors + } +} + +#endif // NET_2_0 diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XmlQueryException.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XmlQueryException.cs new file mode 100755 index 00000000000..00e967cc32d --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/XmlQueryException.cs @@ -0,0 +1,112 @@ +// +// System.Xml.Query.XmlQueryException +// +// Author: +// Tim Coleman (tim@timcoleman.com) +// +// Copyright (C) Tim Coleman, 2003 +// + +// +// 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. +// + +#if NET_2_0 + +using System; +using System.Runtime.Serialization; + +namespace System.Xml.Query +{ + [Serializable] + public class XmlQueryException : SystemException + { + #region Constructors + + [MonoTODO] + protected XmlQueryException (SerializationInfo info, StreamingContext context) + : base (info, context) + { + throw new NotImplementedException (); + } + + public XmlQueryException () + : base ("An XML Query Exception has occurred.") + { + } + + public XmlQueryException (string res) + : this (res, null, null, null) + { + } + + public XmlQueryException (string resource, Exception exception) + : this (resource, null, null, exception) + { + } + + internal XmlQueryException (string message, IXmlLineInfo lineInfo, string sourceUri, Exception innerException) + : base (BuildMessage (message, lineInfo, sourceUri), innerException) + { + } + + static string BuildMessage (string message, IXmlLineInfo li, string sourceUri) + { + if (li != null && li.HasLineInfo ()) { + message = String.Format ("{0}. Location: {1} ({2}, {3}).", message, sourceUri, li.LineNumber, li.LinePosition); + } + else if (sourceUri != null) + message = String.Format ("{0}. Location: {1}", message, sourceUri); + return message; + } + + #endregion // Constructors + + #region Properties + + [MonoTODO] + public int LineNumber { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public int LinePosition { + get { throw new NotImplementedException (); } + } + + [MonoTODO] + public string SourceUri { + get { throw new NotImplementedException(); } + } + + #endregion // Properties + + #region Methods + + [MonoTODO] + public override void GetObjectData (SerializationInfo info, StreamingContext context) + { + throw new NotImplementedException(); + } + #endregion // Methods + } +} + +#endif // NET_2_0 diff --git a/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/skeleton-2.0.cs b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/skeleton-2.0.cs new file mode 100755 index 00000000000..e6bc3b1b856 --- /dev/null +++ b/mcs/class/Mono.Xml.Ext/Mono.Xml.XPath2/skeleton-2.0.cs @@ -0,0 +1,364 @@ +# jay skeleton + +# character in column 1 determines outcome... +# # is a comment +# . is copied +# t is copied as //t if -t is set +# other lines are interpreted to call jay procedures + +.// created by jay 0.7 (c) 1998 Axel.Schreiner@informatik.uni-osnabrueck.de +. +.#if NET_2_0 +. + prolog ## %{ ... %} prior to the first %% + +. +. /** error output stream. +. It should be changeable. +. */ +. internal System.IO.TextWriter ErrorOutput = System.Console.Out; +. +. /** simplified error message. +. @see yyerror +. */ +. internal void yyerror (string message) { +. yyerror(message, null); +. } +. +. /** (syntax) error message. +. Can be overwritten to control message format. +. @param message text to be displayed. +. @param expected vector of acceptable tokens, if available. +. */ +. internal void yyerror (string message, string[] expected) { +. if ((expected != null) && (expected.Length > 0)) { +. ErrorOutput.Write (message+", expecting"); +. for (int n = 0; n < expected.Length; ++ n) +. ErrorOutput.Write (" "+expected[n]); +. ErrorOutput.WriteLine (); +. } else +. ErrorOutput.WriteLine (message); +. } +. +. /** debugging support, requires the package jay.yydebug. +. Set to null to suppress debugging messages. +. */ +t internal yydebug.yyDebug debug; +. + debug ## tables for debugging support +. +. /** index-checked interface to yyNames[]. +. @param token single character or %token value. +. @return token name or [illegal] or [unknown]. +. */ +t internal static string yyname (int token) { +t if ((token < 0) || (token > yyNames.Length)) return "[illegal]"; +t string name; +t if ((name = yyNames[token]) != null) return name; +t return "[unknown]"; +t } +. +. /** computes list of expected tokens on error by tracing the tables. +. @param state for which to compute the list. +. @return list of token names. +. */ +. internal string[] yyExpecting (int state) { +. int token, n, len = 0; +. bool[] ok = new bool[yyNames.Length]; +. +. if ((n = yySindex[state]) != 0) +. for (token = n < 0 ? -n : 0; +. (token < yyNames.Length) && (n+token < yyTable.Length); ++ token) +. if (yyCheck[n+token] == token && !ok[token] && yyNames[token] != null) { +. ++ len; +. ok[token] = true; +. } +. if ((n = yyRindex[state]) != 0) +. for (token = n < 0 ? -n : 0; +. (token < yyNames.Length) && (n+token < yyTable.Length); ++ token) +. if (yyCheck[n+token] == token && !ok[token] && yyNames[token] != null) { +. ++ len; +. ok[token] = true; +. } +. +. string [] result = new string[len]; +. for (n = token = 0; n < len; ++ token) +. if (ok[token]) result[n++] = yyNames[token]; +. return result; +. } +. +. /** the generated parser, with debugging messages. +. Maintains a state and a value stack, currently with fixed maximum size. +. @param yyLex scanner. +. @param yydebug debug message writer implementing yyDebug, or null. +. @return result of the last reduction, if any. +. @throws yyException on irrecoverable parse error. +. */ +. internal Object yyparse (yyParser.yyInput yyLex, Object yyd) +. { +t this.debug = (yydebug.yyDebug)yyd; +. return yyparse(yyLex); +. } +. +. /** initial size and increment of the state/value stack [default 256]. +. This is not final so that it can be overwritten outside of invocations +. of yyparse(). +. */ +. internal int yyMax; +. +. /** executed at the beginning of a reduce action. +. Used as $$ = yyDefault($1), prior to the user-specified action, if any. +. Can be overwritten to provide deep copy, etc. +. @param first value for $1, or null. +. @return first. +. */ +. internal Object yyDefault (Object first) { +. return first; +. } +. +. /** the generated parser. +. Maintains a state and a value stack, currently with fixed maximum size. +. @param yyLex scanner. +. @return result of the last reduction, if any. +. @throws yyException on irrecoverable parse error. +. */ +. internal Object yyparse (yyParser.yyInput yyLex) +. { +. if (yyMax <= 0) yyMax = 256; // initial size +. int yyState = 0; // state stack ptr +. int [] yyStates = new int[yyMax]; // state stack +. Object yyVal = null; // value stack ptr +. Object [] yyVals = new Object[yyMax]; // value stack +. int yyToken = -1; // current input +. int yyErrorFlag = 0; // #tks to shift +. + local ## %{ ... %} after the first %% + +. int yyTop = 0; +. goto skip; +. yyLoop: +. yyTop++; +. skip: +. for (;; ++ yyTop) { +. if (yyTop >= yyStates.Length) { // dynamically increase +. int[] i = new int[yyStates.Length+yyMax]; +. yyStates.CopyTo (i, 0); +. yyStates = i; +. Object[] o = new Object[yyVals.Length+yyMax]; +. yyVals.CopyTo (o, 0); +. yyVals = o; +. } +. yyStates[yyTop] = yyState; +. yyVals[yyTop] = yyVal; +t if (debug != null) debug.push(yyState, yyVal); +. +. yyDiscarded: for (;;) { // discarding a token does not change stack +. int yyN; +. if ((yyN = yyDefRed[yyState]) == 0) { // else [default] reduce (yyN) +. if (yyToken < 0) { +. yyToken = yyLex.advance() ? yyLex.token() : 0; + +t if (debug != null) +t debug.lex(yyState, yyToken, yyname(yyToken), yyLex.value()); +. } +. if ((yyN = yySindex[yyState]) != 0 && ((yyN += yyToken) >= 0) +. && (yyN < yyTable.Length) && (yyCheck[yyN] == yyToken)) { +t if (debug != null) +t debug.shift(yyState, yyTable[yyN], yyErrorFlag-1); +. yyState = yyTable[yyN]; // shift to yyN +. yyVal = yyLex.value(); +. yyToken = -1; +. if (yyErrorFlag > 0) -- yyErrorFlag; +. goto yyLoop; +. } +. if ((yyN = yyRindex[yyState]) != 0 && (yyN += yyToken) >= 0 +. && yyN < yyTable.Length && yyCheck[yyN] == yyToken) +. yyN = yyTable[yyN]; // reduce (yyN) +. else +. switch (yyErrorFlag) { +. +. case 0: +. yyerror(String.Format ("syntax error, got token `{0}'", yyname (yyToken)), yyExpecting(yyState)); +t if (debug != null) debug.error("syntax error"); +. goto case 1; +. case 1: case 2: +. yyErrorFlag = 3; +. do { +. if ((yyN = yySindex[yyStates[yyTop]]) != 0 +. && (yyN += Token.yyErrorCode) >= 0 && yyN < yyTable.Length +. && yyCheck[yyN] == Token.yyErrorCode) { +t if (debug != null) +t debug.shift(yyStates[yyTop], yyTable[yyN], 3); +. yyState = yyTable[yyN]; +. yyVal = yyLex.value(); +. goto yyLoop; +. } +t if (debug != null) debug.pop(yyStates[yyTop]); +. } while (-- yyTop >= 0); +t if (debug != null) debug.reject(); +. throw new yyParser.yyException("irrecoverable syntax error"); +. +. case 3: +. if (yyToken == 0) { +t if (debug != null) debug.reject(); +. throw new yyParser.yyException("irrecoverable syntax error at end-of-file"); +. } +t if (debug != null) +t debug.discard(yyState, yyToken, yyname(yyToken), +t yyLex.value()); +. yyToken = -1; +. goto yyDiscarded; // leave stack alone +. } +. } +. int yyV = yyTop + 1-yyLen[yyN]; +t if (debug != null) +t debug.reduce(yyState, yyStates[yyV-1], yyN, yyRule[yyN], yyLen[yyN]); +. yyVal = yyDefault(yyV > yyTop ? null : yyVals[yyV]); +. switch (yyN) { + + actions ## code from the actions within the grammar + +. } +. yyTop -= yyLen[yyN]; +. yyState = yyStates[yyTop]; +. int yyM = yyLhs[yyN]; +. if (yyState == 0 && yyM == 0) { +t if (debug != null) debug.shift(0, yyFinal); +. yyState = yyFinal; +. if (yyToken < 0) { +. yyToken = yyLex.advance() ? yyLex.token() : 0; + +t if (debug != null) +t debug.lex(yyState, yyToken,yyname(yyToken), yyLex.value()); +. } +. if (yyToken == 0) { +t if (debug != null) debug.accept(yyVal); +. return yyVal; +. } +. goto yyLoop; +. } +. if (((yyN = yyGindex[yyM]) != 0) && ((yyN += yyState) >= 0) +. && (yyN < yyTable.Length) && (yyCheck[yyN] == yyState)) +. yyState = yyTable[yyN]; +. else +. yyState = yyDgoto[yyM]; +t if (debug != null) debug.shift(yyStates[yyTop], yyState); +. goto yyLoop; +. } +. } +. } +. + tables ## tables for rules, default reduction, and action calls +. + epilog ## text following second %% +.namespace yydebug { +. using System; +. internal interface yyDebug { +. void push (int state, Object value); +. void lex (int state, int token, string name, Object value); +. void shift (int from, int to, int errorFlag); +. void pop (int state); +. void discard (int state, int token, string name, Object value); +. void reduce (int from, int to, int rule, string text, int len); +. void shift (int from, int to); +. void accept (Object value); +. void error (string message); +. void reject (); +. } +. +. class yyDebugSimple : yyDebug { +. void println (string s){ +. Console.Error.WriteLine (s); +. } +. +. public void push (int state, Object value) { +. println ("push\tstate "+state+"\tvalue "+value); +. } +. +. public void lex (int state, int token, string name, Object value) { +. println("lex\tstate "+state+"\treading "+name+"\tvalue "+value); +. } +. +. public void shift (int from, int to, int errorFlag) { +. switch (errorFlag) { +. default: // normally +. println("shift\tfrom state "+from+" to "+to); +. break; +. case 0: case 1: case 2: // in error recovery +. println("shift\tfrom state "+from+" to "+to +. +"\t"+errorFlag+" left to recover"); +. break; +. case 3: // normally +. println("shift\tfrom state "+from+" to "+to+"\ton error"); +. break; +. } +. } +. +. public void pop (int state) { +. println("pop\tstate "+state+"\ton error"); +. } +. +. public void discard (int state, int token, string name, Object value) { +. println("discard\tstate "+state+"\ttoken "+name+"\tvalue "+value); +. } +. +. public void reduce (int from, int to, int rule, string text, int len) { +. println("reduce\tstate "+from+"\tuncover "+to +. +"\trule ("+rule+") "+text); +. } +. +. public void shift (int from, int to) { +. println("goto\tfrom state "+from+" to "+to); +. } +. +. public void accept (Object value) { +. println("accept\tvalue "+value); +. } +. +. public void error (string message) { +. println("error\t"+message); +. } +. +. public void reject () { +. println("reject"); +. } +. +. } +.} +.// %token constants +. class Token { + tokens public const int +. } +. namespace yyParser { +. using System; +. /** thrown for irrecoverable syntax errors and stack overflow. +. */ +. internal class yyException : System.Exception { +. public yyException (string message) : base (message) { +. } +. } +. +. /** must be implemented by a scanner object to supply input to the parser. +. */ +. internal interface yyInput { +. /** move on to next token. +. @return false if positioned beyond tokens. +. @throws IOException on input error. +. */ +. bool advance (); // throws java.io.IOException; +. /** classifies current token. +. Should not be called if advance() returned false. +. @return current %token or single character. +. */ +. int token (); +. /** associated with current token. +. Should not be called if advance() returned false. +. @return value for token(). +. */ +. Object value (); +. } +. } +.} // close outermost namespace, that MUST HAVE BEEN opened in the prolog +. +.#endif + -- cgit v1.2.3