private QilNode RelationalOperator(XPathOperator op, QilNode left, QilNode right) { Debug.Assert(op == XPathOperator.Lt || op == XPathOperator.Le || op == XPathOperator.Gt || op == XPathOperator.Ge); XmlQueryType leftType = left.XmlType; XmlQueryType rightType = right.XmlType; if (_f.IsAnyType(left) || _f.IsAnyType(right)) { return(_f.InvokeRelationalOperator(s_qilOperator[(int)op], left, right)); } else if (leftType.IsNode && rightType.IsNode) { return(CompareNodeSetAndNodeSet(op, left, right, XmlTypeCode.Double)); } else if (leftType.IsNode) { XmlTypeCode compType = rightType.TypeCode == XmlTypeCode.Boolean ? XmlTypeCode.Boolean : XmlTypeCode.Double; return(CompareNodeSetAndValue(op, /*nodeset:*/ left, /*val:*/ right, compType)); } else if (rightType.IsNode) { XmlTypeCode compType = leftType.TypeCode == XmlTypeCode.Boolean ? XmlTypeCode.Boolean : XmlTypeCode.Double; op = InvertOp(op); return(CompareNodeSetAndValue(op, /*nodeset:*/ right, /*val:*/ left, compType)); } else { return(CompareValues(op, left, right, XmlTypeCode.Double)); } }
//----------------------------------------------- // Constructor //----------------------------------------------- /// <summary> /// Construct a node /// </summary> public QilFunction(QilNodeType nodeType, QilNode arguments, QilNode definition, QilNode sideEffects, XmlQueryType resultType) : base(nodeType) { this.arguments = arguments; this.definition = definition; this.sideEffects = sideEffects; this.xmlType = resultType; }
/// <summary> /// Calculate starting xml states that will result when iterating over and constructing an expression of the specified type. /// </summary> private void StartLoop(XmlQueryType typ, XmlILConstructInfo info) { Debug.Assert(!typ.IsSingleton); // This is tricky, because the looping introduces a feedback loop: // 1. Because loops may be executed many times, the beginning set of states must include the ending set of states. // 2. Because loops may be executed 0 times, the final set of states after all looping is complete must include // the initial set of states. // // +-- states-initial // | | // | states-begin-loop <--+ // | | | // | +--------------+ | // | | Construction | | // | +--------------+ | // | | | // | states-end-loop ----+ // | | // +--> states-final // Save starting loop states info.BeginLoopStates = this.xstates; if (typ.MaybeMany) { // If transition might occur from EnumAttrs to WithinContent, then states-end might be WithinContent, which // means states-begin needs to also include WithinContent. if (this.xstates == PossibleXmlStates.EnumAttrs && MaybeContent(typ)) { info.BeginLoopStates = this.xstates = PossibleXmlStates.Any; } } }
/// <summary> /// Add "type" to the list of unique types that are used by this query. Return the index of /// the unique type in the list. /// </summary> public int DeclareXmlType(XmlQueryType type) { _uniqueXmlTypes ??= new UniqueList <XmlQueryType>(); XmlQueryTypeFactory.CheckSerializability(type); return(_uniqueXmlTypes.Add(type)); }
/// <summary> /// Create an XmlQueryType from an Xsd simple type (where variety can be Atomic, List, or Union). /// </summary> /// <param name="schemaType">the simple Xsd schema type of the atomic value</param> /// <param name="isStrict">true if the dynamic type is guaranteed to match the static type exactly</param> /// <returns>the atomic value type</returns> public static XmlQueryType Type(XmlSchemaSimpleType schemaType, bool isStrict) { if (schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic) { // We must special-case xs:anySimpleType because it is broken in Xsd and is sometimes treated as // an atomic value and sometimes as a list value. In XQuery, it always maps to xdt:anyAtomicType*. if (schemaType == DatatypeImplementation.AnySimpleType) return AnyAtomicTypeS; return ItemType.Create(schemaType, isStrict); } // Skip restrictions. It is safe to do that because this is a list or union, so it's not a build in type while (schemaType.DerivedBy == XmlSchemaDerivationMethod.Restriction) schemaType = (XmlSchemaSimpleType) schemaType.BaseXmlSchemaType; // Convert Xsd list if (schemaType.DerivedBy == XmlSchemaDerivationMethod.List) return PrimeProduct(Type(((XmlSchemaSimpleTypeList) schemaType.Content).BaseItemType, isStrict), XmlQueryCardinality.ZeroOrMore); // Convert Xsd union Debug.Assert(schemaType.DerivedBy == XmlSchemaDerivationMethod.Union); XmlSchemaSimpleType[] baseMemberTypes = ((XmlSchemaSimpleTypeUnion) schemaType.Content).BaseMemberTypes; XmlQueryType[] queryMemberTypes = new XmlQueryType[baseMemberTypes.Length]; for (int i = 0; i < baseMemberTypes.Length; i++) queryMemberTypes[i] = Type(baseMemberTypes[i], isStrict); return Choice(queryMemberTypes); }
public QilNode SafeDocOrderDistinct(QilNode n) { XmlQueryType xt = n.XmlType !; if (xt.MaybeMany) { if (xt.IsNode && xt.IsNotRtf) { // node-set return(DocOrderDistinct(n)); } else if (!xt.IsAtomicValue) { QilIterator i; return(Loop(i = Let(n), Conditional(Gt(Length(i), Int32(1)), DocOrderDistinct(TypeAssert(i, T.NodeNotRtfS)), i ) )); } } return(n); }
/// <summary> /// Return the default Clr data type that will be used to store instances of the QilNode's type. /// </summary> public static Type GetStorageType(XmlQueryType qyTyp) { Type storageType; if (qyTyp.IsSingleton) { storageType = TypeCodeToStorage[(int)qyTyp.TypeCode]; // Non-strict items must store the type along with the value, so use XPathItem if (!qyTyp.IsStrict && storageType != typeof(XPathNavigator)) { return(typeof(XPathItem)); } } else { storageType = TypeCodeToCachedStorage[(int)qyTyp.TypeCode]; // Non-strict items must store the type along with the value, so use XPathItem if (!qyTyp.IsStrict && storageType != typeof(IList <XPathNavigator>)) { return(typeof(IList <XPathItem>)); } } return(storageType); }
public QilNode XsltInvokeEarlyBound(QilNode name, MethodInfo d, XmlQueryType t, IList <QilNode> args) { QilList list = _f.ActualParameterList(); list.Add(args); return(_f.XsltInvokeEarlyBound(name, _f.LiteralObject(d), list, t)); }
QilNode IXPathEnvironment.ResolveVariable(string prefix, string name) { if (!_allowVariables) { throw new XslLoadException(SR.Xslt_VariablesNotAllowed); } string ns = ResolvePrefixThrow(/*ignoreDefaultNs:*/ true, prefix); Debug.Assert(ns != null); // Look up in params and variables of the current scope and all outer ones QilNode?var = _scope.LookupVariable(name, ns); if (var == null) { throw new XslLoadException(SR.Xslt_InvalidVariable, Compiler.ConstructQName(prefix, name)); } // All Node* parameters are guaranteed to be in document order with no duplicates, so TypeAssert // this so that optimizer can use this information to avoid redundant sorts and duplicate removal. XmlQueryType varType = var.XmlType !; if (var.NodeType == QilNodeType.Parameter && varType.IsNode && varType.IsNotRtf && varType.MaybeMany && !varType.IsDod) { var = _f.TypeAssert(var, XmlQueryTypeFactory.NodeSDod); } return(var); }
public XmlQueryType CheckAverage(QilUnary node) { XmlQueryType xmlType = node.Child.XmlType; CheckNumericXS(node.Child); return(XmlQueryTypeFactory.PrimeProduct(xmlType, xmlType.MaybeEmpty ? XmlQueryCardinality.ZeroOrOne : XmlQueryCardinality.One)); }
public void CheckXsltType(QilNode n) { // Five possible types are: anyType, node-set, string, boolean, and number XmlQueryType xt = n.XmlType !; switch (xt.TypeCode) { case XmlTypeCode.String: case XmlTypeCode.Boolean: case XmlTypeCode.Double: Debug.Assert(xt.IsSingleton && xt.IsStrict, "Xslt assumes that these types will always be singleton and strict"); break; case XmlTypeCode.Item: case XmlTypeCode.None: break; case XmlTypeCode.QName: Debug.Assert(IsDebug, "QName is reserved as the marker for missing values"); break; default: Debug.Assert(xt.IsNode, $"Unexpected expression type: {xt}"); break; } }
/// <summary> /// Return true if the type of every item in "seq" matches the xml type identified by "idxType". /// </summary> public bool MatchesXmlType(IList <XPathItem> seq, int indexType) { XmlQueryType typBase = GetXmlType(indexType); XmlQueryCardinality card = seq.Count switch { 0 => XmlQueryCardinality.Zero, 1 => XmlQueryCardinality.One, _ => XmlQueryCardinality.More, }; if (!(card <= typBase.Cardinality)) { return(false); } typBase = typBase.Prime; for (int i = 0; i < seq.Count; i++) { if (!CreateXmlType(seq[0]).IsSubtypeOf(typBase)) { return(false); } } return(true); }
private QilNode EqualityOperator(XPathOperator op, QilNode left, QilNode right) { Debug.Assert(op == XPathOperator.Eq || op == XPathOperator.Ne); XmlQueryType leftType = left.XmlType; XmlQueryType rightType = right.XmlType; if (_f.IsAnyType(left) || _f.IsAnyType(right)) { return(_f.InvokeEqualityOperator(s_qilOperator[(int)op], left, right)); } else if (leftType.IsNode && rightType.IsNode) { return(CompareNodeSetAndNodeSet(op, left, right, XmlTypeCode.String)); } else if (leftType.IsNode) { return(CompareNodeSetAndValue(op, /*nodeset:*/ left, /*val:*/ right, rightType.TypeCode)); } else if (rightType.IsNode) { return(CompareNodeSetAndValue(op, /*nodeset:*/ right, /*val:*/ left, leftType.TypeCode)); } else { XmlTypeCode compType = ( leftType.TypeCode == XmlTypeCode.Boolean || rightType.TypeCode == XmlTypeCode.Boolean ? XmlTypeCode.Boolean : leftType.TypeCode == XmlTypeCode.Double || rightType.TypeCode == XmlTypeCode.Double ? XmlTypeCode.Double : /*default:*/ XmlTypeCode.String ); return(CompareValues(op, left, right, compType)); } }
// Return true if inferred type of the given expression is never a subtype of T.NodeS public bool CannotBeNodeSet(QilNode n) { XmlQueryType xt = n.XmlType !; // Do not report compile error if n is a VarPar, whose inferred type forbids nodes (SQLBUDT 339398) return(xt.IsAtomicValue && !xt.IsEmpty && !(n is QilIterator)); }
/// <summary> /// Return true if the type of every item in "seq" matches the xml type identified by "idxType". /// </summary> public bool MatchesXmlType(IList <XPathItem> seq, int indexType) { XmlQueryType typBase = GetXmlType(indexType); XmlQueryCardinality card; switch (seq.Count) { case 0: card = XmlQueryCardinality.Zero; break; case 1: card = XmlQueryCardinality.One; break; default: card = XmlQueryCardinality.More; break; } if (!(card <= typBase.Cardinality)) { return(false); } typBase = typBase.Prime; for (int i = 0; i < seq.Count; i++) { if (!CreateXmlType(seq[0]).IsSubtypeOf(typBase)) { return(false); } } return(true); }
/// <summary> /// If type might contain attributes or namespaces, set appropriate parent element flags. /// </summary> private void CheckAttributeNamespaceConstruct(XmlQueryType typ) { // If content might contain attributes, if ((typ.NodeKinds & XmlNodeKindFlags.Attribute) != XmlNodeKindFlags.None) { // Mark element as possibly having attributes and duplicate attributes (since we don't know the names) this.parentInfo.MightHaveAttributes = true; this.parentInfo.MightHaveDuplicateAttributes = true; // Attribute namespaces might be declared this.parentInfo.MightHaveNamespaces = true; } // If content might contain namespaces, if ((typ.NodeKinds & XmlNodeKindFlags.Namespace) != XmlNodeKindFlags.None) { // Then element might have namespaces, this.parentInfo.MightHaveNamespaces = true; // If attributes might already have been constructed, if (this.parentInfo.MightHaveAttributes) { // Then attributes might precede namespace declarations this.parentInfo.MightHaveNamespacesAfterAttributes = true; } } }
private QilNode MatchPatterns(QilIterator it, XmlQueryType xt, List <Pattern> patternList, QilNode otherwise) { if (patternList.Count == 0) { return(otherwise); } return(_f.Conditional(_f.IsType(it, xt), MatchPatterns(it, patternList), otherwise)); }
public QilLiteral LiteralType(XmlQueryType value) { QilLiteral n = new QilLiteral(QilNodeType.LiteralType, value); n.XmlType = this.typeCheck.CheckLiteralType(n); TraceNode(n); return(n); }
public QilParameter Parameter(QilNode defaultValue, QilNode name, XmlQueryType xmlType) { QilParameter n = new QilParameter(QilNodeType.Parameter, defaultValue, name, xmlType); n.XmlType = this.typeCheck.CheckParameter(n); TraceNode(n); return(n); }
public QilNode Unknown(XmlQueryType xmlType) { QilNode n = new QilNode(QilNodeType.Unknown, xmlType); n.XmlType = this.typeCheck.CheckUnknown(n); TraceNode(n); return(n); }
public bool IsAnyType(QilNode n) { XmlQueryType xt = n.XmlType; bool result = !(xt.IsStrict || xt.IsNode); Debug.Assert(result == (xt.TypeCode == XmlTypeCode.Item || xt.TypeCode == XmlTypeCode.AnyAtomicType), "What else can it be?"); return(result); }
/// <summary> /// Add "type" to the list of unique types that are used by this query. Return the index of /// the unique type in the list. /// </summary> public int DeclareXmlType(XmlQueryType type) { if (this.uniqueXmlTypes == null) { this.uniqueXmlTypes = new UniqueList <XmlQueryType>(); } return(this.uniqueXmlTypes.Add(type)); }
//----------------------------------------------- // sorting //----------------------------------------------- public XmlQueryType CheckSort(QilLoop node) { XmlQueryType varType = node.Variable.Binding.XmlType; CheckClassAndNodeType(node[0], typeof(QilIterator), QilNodeType.For); CheckClassAndNodeType(node[1], typeof(QilList), QilNodeType.SortKeyList); // Sort does not preserve DocOrderDistinct return(XmlQueryTypeFactory.PrimeProduct(varType, varType.Cardinality)); }
/// <summary> /// Add "type" to the list of unique types that are used by this query. Return the index of /// the unique type in the list. /// </summary> public int DeclareXmlType(XmlQueryType type) { if (this.uniqueXmlTypes == null) { this.uniqueXmlTypes = new UniqueList <XmlQueryType>(); } XmlQueryTypeFactory.CheckSerializability(type); return(this.uniqueXmlTypes.Add(type)); }
//----------------------------------------------- // loops //----------------------------------------------- public XmlQueryType CheckLoop(QilLoop node) { CheckClass(node[0], typeof(QilIterator)); Check(node.Variable.NodeType == QilNodeType.For || node.Variable.NodeType == QilNodeType.Let, node, "Loop variable must be a For or Let iterator"); XmlQueryType bodyType = node.Body.XmlType; XmlQueryCardinality variableCard = node.Variable.NodeType == QilNodeType.Let ? XmlQueryCardinality.One : node.Variable.Binding.XmlType.Cardinality; // Loops do not preserve DocOrderDistinct return(XmlQueryTypeFactory.PrimeProduct(bodyType, variableCard * bodyType.Cardinality)); }
/// <summary> /// Bind to the specified MethodInfo. /// </summary> private void Bind(MethodInfo meth) { ParameterInfo[] paramInfo = meth.GetParameters(); int i; // Save the MethodInfo _meth = meth; // Get the Clr type of each parameter _argClrTypes = new Type[paramInfo.Length]; for (i = 0; i < paramInfo.Length; i++) { _argClrTypes[i] = GetClrType(paramInfo[i].ParameterType); } // Get the Clr type of the return value _retClrType = GetClrType(_meth.ReturnType); // Infer an Xml type for each Clr type _argXmlTypes = new XmlQueryType[paramInfo.Length]; for (i = 0; i < paramInfo.Length; i++) { _argXmlTypes[i] = InferXmlType(_argClrTypes[i]); // BUGBUG: // 1. A couple built-in Xslt functions allow Rtf as argument, which is // different from what InferXmlType returns. Until XsltEarlyBound references // a Qil function, we'll work around this case by assuming that all built-in // Xslt functions allow Rtf. // 2. Script arguments should allow node-sets which are not statically known // to be Dod to be passed, so relax static typing in this case. if (_namespaceUri.Length == 0) { if ((object)_argXmlTypes[i] == (object)XmlQueryTypeFactory.NodeNotRtf) { _argXmlTypes[i] = XmlQueryTypeFactory.Node; } else if ((object)_argXmlTypes[i] == (object)XmlQueryTypeFactory.NodeSDod) { _argXmlTypes[i] = XmlQueryTypeFactory.NodeS; } } else { if ((object)_argXmlTypes[i] == (object)XmlQueryTypeFactory.NodeSDod) { _argXmlTypes[i] = XmlQueryTypeFactory.NodeNotRtfS; } } } // Infer an Xml type for the return Clr type _retXmlType = InferXmlType(_retClrType); }
public QilNode GenerateInvoke(QilFunction func, IList <XslNode> actualArgs) { _iterStack.Clear(); _formalArgs = func.Arguments; _invokeArgs = _fac.ActualParameterList(); // curArg is an instance variable used in Clone() method for (_curArg = 0; _curArg < _formalArgs.Count; _curArg++) { // Find actual value for a given formal arg QilParameter formalArg = (QilParameter)_formalArgs[_curArg]; QilNode? invokeArg = FindActualArg(formalArg, actualArgs); // If actual value was not specified, use the default value and copy its debug comment if (invokeArg == null) { if (_debug) { if (formalArg.Name !.NamespaceUri == XmlReservedNs.NsXslDebug) { Debug.Assert(formalArg.Name.LocalName == "namespaces", "Cur,Pos,Last don't have default values and should be always added to by caller in AddImplicitArgs()"); Debug.Assert(formalArg.DefaultValue != null, "PrecompileProtoTemplatesHeaders() set it"); invokeArg = Clone(formalArg.DefaultValue); } else { invokeArg = _fac.DefaultValueMarker(); } } else { Debug.Assert(formalArg.Name !.NamespaceUri != XmlReservedNs.NsXslDebug, "Cur,Pos,Last don't have default values and should be always added to by caller in AddImplicitArgs(). We don't have $namespaces in !debug."); invokeArg = Clone(formalArg.DefaultValue !); } } XmlQueryType formalType = formalArg.XmlType !; XmlQueryType invokeType = invokeArg.XmlType !; // Possible arg types: anyType, node-set, string, boolean, and number _fac.CheckXsltType(formalArg); _fac.CheckXsltType(invokeArg); if (!invokeType.IsSubtypeOf(formalType)) { // This may occur only if inferred type of invokeArg is XslFlags.None Debug.Assert(invokeType == T.ItemS, "Actual argument type is not a subtype of formal argument type"); invokeArg = _fac.TypeAssert(invokeArg, formalType); } _invokeArgs.Add(invokeArg); }
/// <summary> /// Calculate ending xml states that will result when iterating over and constructing an expression of the specified type. /// </summary> private void EndLoop(XmlQueryType typ, XmlILConstructInfo info) { Debug.Assert(!typ.IsSingleton); // Save ending loop states info.EndLoopStates = this.xstates; // If it's possible to loop zero times, then states-final needs to include states-initial if (typ.MaybeEmpty && info.InitialStates != this.xstates) { this.xstates = PossibleXmlStates.Any; } }
//----------------------------------------------- // QilReplaceVisitor methods //----------------------------------------------- /// <summary> /// Once children have been replaced, the Xml type is recalculated. /// </summary> protected virtual void RecalculateType(QilNode node, XmlQueryType oldType) { XmlQueryType newType; newType = f.TypeChecker.Check(node); // Note the use of AtMost to account for cases when folding of Error nodes in the graph cause // cardinality to be recalculated. // For example, (Sequence (TextCtor (Error "error")) (Int32 1)) => (Sequence (Error "error") (Int32 1)) // In this case, cardinality has gone from More to One Debug.Assert(newType.IsSubtypeOf(XmlQueryTypeFactory.AtMost(oldType, oldType.Cardinality)), "Replace shouldn't relax original type"); node.XmlType = newType; }
/// <summary> /// Bind to the specified MethodInfo. /// </summary> private void Bind(MethodInfo meth) { ParameterInfo[] paramInfo = meth.GetParameters(); int i; // Save the MethodInfo this.meth = meth; // Get the Clr type of each parameter this.argClrTypes = new Type[paramInfo.Length]; for (i = 0; i < paramInfo.Length; i++) { this.argClrTypes[i] = GetClrType(paramInfo[i].ParameterType); } // Get the Clr type of the return value this.retClrType = GetClrType(this.meth.ReturnType); // Infer an Xml type for each Clr type this.argXmlTypes = new XmlQueryType[paramInfo.Length]; for (i = 0; i < paramInfo.Length; i++) { this.argXmlTypes[i] = InferXmlType(this.argClrTypes[i]); // if (this.namespaceUri.Length == 0) { if ((object)this.argXmlTypes[i] == (object)XmlQueryTypeFactory.NodeNotRtf) { this.argXmlTypes[i] = XmlQueryTypeFactory.Node; } else if ((object)this.argXmlTypes[i] == (object)XmlQueryTypeFactory.NodeSDod) { this.argXmlTypes[i] = XmlQueryTypeFactory.NodeS; } } else { if ((object)this.argXmlTypes[i] == (object)XmlQueryTypeFactory.NodeSDod) { this.argXmlTypes[i] = XmlQueryTypeFactory.NodeNotRtfS; } } } // Infer an Xml type for the return Clr type this.retXmlType = InferXmlType(this.retClrType); }
private XmlQueryType DistinctType(XmlQueryType type) { if (type.Cardinality == XmlQueryCardinality.More) { return(XmlQueryTypeFactory.PrimeProduct(type, XmlQueryCardinality.OneOrMore)); } if (type.Cardinality == XmlQueryCardinality.NotOne) { return(XmlQueryTypeFactory.PrimeProduct(type, XmlQueryCardinality.ZeroOrMore)); } return(type); }
public XmlQueryType CheckFilter(QilLoop node) { CheckClass(node[0], typeof(QilIterator)); Check(node.Variable.NodeType == QilNodeType.For || node.Variable.NodeType == QilNodeType.Let, node, "Filter variable must be a For or Let iterator"); CheckXmlType(node.Body, XmlQueryTypeFactory.BooleanX); // Attempt to restrict filter's type by checking condition XmlQueryType filterType = FindFilterType(node.Variable, node.Body); if (filterType != null) { return(filterType); } return(XmlQueryTypeFactory.AtMost(node.Variable.Binding.XmlType, node.Variable.Binding.XmlType.Cardinality)); }
/// <summary> /// Return the default Clr data type that will be used to store instances of the QilNode's type. /// </summary> public static Type GetStorageType(XmlQueryType qyTyp) { Type storageType; if (qyTyp.IsSingleton) { storageType = TypeCodeToStorage[(int) qyTyp.TypeCode]; // Non-strict items must store the type along with the value, so use XPathItem if (!qyTyp.IsStrict && storageType != typeof(XPathNavigator)) return typeof(XPathItem); } else { storageType = TypeCodeToCachedStorage[(int) qyTyp.TypeCode]; // Non-strict items must store the type along with the value, so use XPathItem if (!qyTyp.IsStrict && storageType != typeof(IList<XPathNavigator>)) return typeof(IList<XPathItem>); } return storageType; }
private XmlQueryCardinality AddDescendantParticle(List<XmlQueryType> list, Dictionary<XmlQualifiedName, XmlQueryCardinality> allTypes, XmlSchemaParticle particle, XmlQueryType filter) { XmlQueryCardinality card = XmlQueryCardinality.None; XmlSchemaElement element = particle as XmlSchemaElement; if (element != null) { // Single element XmlQueryType elementType = CreateElementType(element); // Add it card = AddFilteredPrime(list, elementType, filter); // Descend card += AddElementOrTextDescendants(list, allTypes, elementType.SchemaType, filter); } else { XmlSchemaAny any = particle as XmlSchemaAny; if (any != null) { // Descendants of any card = AddFilteredPrime(list, Element, filter); } else { XmlSchemaGroupBase group = particle as XmlSchemaGroupBase; if (group.Items.Count != 0) { if (particle is XmlSchemaChoice) { foreach (XmlSchemaParticle p in group.Items) { card |= AddDescendantParticle(list, allTypes, p, filter); } } else { // Sequence and All foreach (XmlSchemaParticle p in group.Items) { card += AddDescendantParticle(list, allTypes, p, filter); } } } } } return card * CardinalityOfParticle(particle); }
private XmlQueryCardinality AddElementOrTextDescendants(List<XmlQueryType> list, Dictionary<XmlQualifiedName, XmlQueryCardinality> allTypes, XmlSchemaType sourceSchemaType, XmlQueryType filter) { XmlQueryCardinality card = XmlQueryCardinality.None; if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType) { card = AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrMore; card += AddFilteredPrime(list, Text, filter); } else if (sourceSchemaType.Datatype != null) { // Text is the only child node simple content of complext type card = AddFilteredPrime(list, Text, filter, true) * XmlQueryCardinality.ZeroOrOne; } else { // Complex content XmlSchemaComplexType complexType = (XmlSchemaComplexType)sourceSchemaType; if (complexType.QualifiedName.IsEmpty || !allTypes.TryGetValue(complexType.QualifiedName, out card)) { allTypes[complexType.QualifiedName] = XmlQueryCardinality.ZeroOrMore; // take care of left recursion card = AddDescendantParticle(list, allTypes, complexType.ContentTypeParticle, filter); allTypes[complexType.QualifiedName] = card; //set correct card if (complexType.ContentType == XmlSchemaContentType.Mixed) { card += AddFilteredPrime(list, Text, filter); } } } return card; }
/// <summary> /// Adds itemType to a union. Returns false if new item is a subtype of one of the types in the list. /// </summary> private static void AddItemToChoice(List<XmlQueryType> accumulator, XmlQueryType itemType) { Debug.Assert(itemType.IsSingleton, "All types should be prime."); bool addToList = true; for (int i = 0; i < accumulator.Count; i++) { // If new prime is a subtype of existing prime, don't add it to the union if (itemType.IsSubtypeOf(accumulator[i])) { return; } // If new prime is a subtype of existing prime, then replace the existing prime with new prime if (accumulator[i].IsSubtypeOf(itemType)) { if (addToList) { addToList = false; accumulator[i] = itemType; } else { accumulator.RemoveAt(i); i --; } } } if (addToList) { accumulator.Add(itemType); } }
/// <summary> /// Each XmlQueryType has multiple legal CLR representations. Ensure that all items returned by this iterator are in /// the Clr representation specified by "storageTypeDest". /// </summary> public void EnsureItemStorageType(XmlQueryType xmlType, Type storageTypeDest) { // If source type = destination type, then done if (this.storage.ItemStorageType == storageTypeDest) goto SetStorageType; Debug.Assert(this.storage.ItemStorageType == typeof(XPathItem) || storageTypeDest == typeof(XPathItem), "EnsureItemStorageType must convert to or from Item"); // If items are cached, if (this.storage.IsCached) { // Check for special case of IList<XPathNavigator> -> IList<XPathItem> if (this.storage.ItemStorageType == typeof(XPathNavigator)) { EnsureStack(); this.helper.Call(XmlILMethods.NavsToItems); goto SetStorageType; } // Check for special case of IList<XPathItem> -> IList<XPathNavigator> if (storageTypeDest == typeof(XPathNavigator)) { EnsureStack(); this.helper.Call(XmlILMethods.ItemsToNavs); goto SetStorageType; } } // Iterate over each item, and convert each to the destination type EnsureStackNoCache(); // If source type is Item, if (this.storage.ItemStorageType == typeof(XPathItem)) { // Then downcast to Navigator if (storageTypeDest == typeof(XPathNavigator)) { this.helper.Emit(OpCodes.Castclass, typeof(XPathNavigator)); } else { // Call ValueAs methods for atomic types this.helper.CallValueAs(storageTypeDest); } goto SetStorageType; } else if (this.storage.ItemStorageType == typeof(XPathNavigator)) { // No-op if converting from XPathNavigator to XPathItem Debug.Assert(storageTypeDest == typeof(XPathItem), "Must be converting from XPathNavigator to XPathItem"); goto SetStorageType; } // Destination type must be item, so generate code to create an XmlAtomicValue this.helper.LoadInteger(this.helper.StaticData.DeclareXmlType(xmlType)); this.helper.LoadQueryRuntime(); this.helper.Call(XmlILMethods.StorageMethods[this.storage.ItemStorageType].ToAtomicValue); SetStorageType: this.storage = this.storage.ToStorageType(storageTypeDest); }
public QilNode XsltInvokeEarlyBound(QilNode name, MethodInfo d, XmlQueryType t, IList<QilNode> args) { QilList list = f.ActualParameterList(); list.Add(args); return f.XsltInvokeEarlyBound(name, f.LiteralObject(d), list, t); }
//----------------------------------------------- // Type operators //----------------------------------------------- public QilNode TypeAssert(QilNode expr, XmlQueryType t) { return f.TypeAssert(expr, t); }
//----------------------------------------------- // function definition and invocation //----------------------------------------------- public QilFunction Function(QilList args, QilNode sideEffects, XmlQueryType resultType) { Debug.Assert(args.NodeType == QilNodeType.FormalParameterList); return f.Function(args, sideEffects, resultType); }
private XmlQueryCardinality AddFilteredPrime(List<XmlQueryType> list, XmlQueryType source, XmlQueryType filter, bool forseSingle) { Debug.Assert(source.IsNode && source.IsSingleton); Debug.Assert(filter.IsNode && filter.IsSingleton); // Intersect types XmlQueryType intersection = IntersectItemTypes(source, filter); if ((object)intersection == (object)None) { return XmlQueryCardinality.Zero; } AddItemToChoice(list, intersection); // In the case of forseSingle - filtering all nodes behave as singletones XmlTypeCode typeCode = (forseSingle ? XmlTypeCode.Node : intersection.TypeCode); switch (typeCode) { case XmlTypeCode.Node: case XmlTypeCode.Document: case XmlTypeCode.Element: // Filter can result in empty sequence if filter is not wider then source if (intersection == source) return XmlQueryCardinality.One; else return XmlQueryCardinality.ZeroOrOne; case XmlTypeCode.Attribute: // wildcard attribute matches more then one node if (!intersection.NameTest.IsSingleName) return XmlQueryCardinality.ZeroOrMore; else if (intersection == source) return XmlQueryCardinality.One; else return XmlQueryCardinality.ZeroOrOne; case XmlTypeCode.Comment: case XmlTypeCode.Text: case XmlTypeCode.ProcessingInstruction: case XmlTypeCode.Namespace: return XmlQueryCardinality.ZeroOrMore; default: Debug.Assert(false); return XmlQueryCardinality.None; } }
/// <summary> /// Construct the intersection of two lists of prime XmlQueryTypes. /// </summary> private XmlQueryType IntersectItemTypes(XmlQueryType left, XmlQueryType right) { Debug.Assert(left.Count == 1 && left.IsSingleton, "left should be an item"); Debug.Assert(right.Count == 1 && right.IsSingleton, "right should be an item"); if (left.TypeCode == right.TypeCode && (left.NodeKinds & (XmlNodeKindFlags.Document | XmlNodeKindFlags.Element | XmlNodeKindFlags.Attribute)) != 0) { if (left.TypeCode == XmlTypeCode.Node) { return left; } // Intersect name tests XmlQualifiedNameTest nameTest = left.NameTest.Intersect(right.NameTest); // Intersect types XmlSchemaType type = XmlSchemaType.IsDerivedFrom(left.SchemaType, right.SchemaType, /* except:*/XmlSchemaDerivationMethod.Empty) ? left.SchemaType : XmlSchemaType.IsDerivedFrom(right.SchemaType, left.SchemaType, /* except:*/XmlSchemaDerivationMethod.Empty) ? right.SchemaType : null; bool isNillable = left.IsNillable && right.IsNillable; if ((object)nameTest == (object)left.NameTest && type == left.SchemaType && isNillable == left.IsNillable) { // left is a subtype of right return left return left; } else if ((object)nameTest == (object)right.NameTest && type == right.SchemaType && isNillable == right.IsNillable) { // right is a subtype of left return right return right; } else if (nameTest != null && type != null) { // create a new type return ItemType.Create(left.TypeCode, nameTest, type, isNillable); } } else if (left.IsSubtypeOf(right)) { // left is a subset of right, so left is in the intersection return left; } else if (right.IsSubtypeOf(left)) { // right is a subset of left, so right is in the intersection return right; } return None; }
private XmlQueryType DistinctType(XmlQueryType type) { if (type.Cardinality == XmlQueryCardinality.More) return XmlQueryTypeFactory.PrimeProduct(type, XmlQueryCardinality.OneOrMore); if (type.Cardinality == XmlQueryCardinality.NotOne) return XmlQueryTypeFactory.PrimeProduct(type, XmlQueryCardinality.ZeroOrMore); return type; }
private void CheckXmlType(QilNode node, XmlQueryType xmlType) { Check(node.XmlType.IsSubtypeOf(xmlType), node, "Node's type " + node.XmlType + " is not a subtype of " + xmlType); }
/// <summary> /// Convert from the Clr type of "value" to the default Clr type that ILGen uses to represent the xml type, using /// the conversion rules of the xml type. /// </summary> internal object ChangeTypeXsltResult(XmlQueryType xmlType, object value) { if (value == null) throw new XslTransformException(Res.Xslt_ItemNull, string.Empty); switch (xmlType.TypeCode) { case XmlTypeCode.String: if (value.GetType() == XsltConvert.DateTimeType) value = XsltConvert.ToString((DateTime) value); break; case XmlTypeCode.Double: if (value.GetType() != XsltConvert.DoubleType) value = ((IConvertible) value).ToDouble(null); break; case XmlTypeCode.Node: if (!xmlType.IsSingleton) { XPathArrayIterator iter = value as XPathArrayIterator; // Special-case XPathArrayIterator in order to avoid copies if (iter != null && iter.AsList is XmlQueryNodeSequence) { value = iter.AsList as XmlQueryNodeSequence; } else { // Iterate over list and ensure it only contains nodes XmlQueryNodeSequence seq = new XmlQueryNodeSequence(); IList list = value as IList; if (list != null) { for (int i = 0; i < list.Count; i++) seq.Add(EnsureNavigator(list[i])); } else { foreach (object o in (IEnumerable) value) seq.Add(EnsureNavigator(o)); } value = seq; } // Always sort node-set by document order value = ((XmlQueryNodeSequence) value).DocOrderDistinct(this.docOrderCmp); } break; case XmlTypeCode.Item: { Type sourceType = value.GetType(); IXPathNavigable navigable; // If static type is item, then infer type based on dynamic value switch (XsltConvert.InferXsltType(sourceType).TypeCode) { case XmlTypeCode.Boolean: value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Boolean), value)); break; case XmlTypeCode.Double: value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.Double), ((IConvertible) value).ToDouble(null))); break; case XmlTypeCode.String: if (sourceType == XsltConvert.DateTimeType) value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String), XsltConvert.ToString((DateTime) value))); else value = new XmlQueryItemSequence(new XmlAtomicValue(XmlSchemaType.GetBuiltInSimpleType(XmlTypeCode.String), value)); break; case XmlTypeCode.Node: // Support XPathNavigator[] value = ChangeTypeXsltResult(XmlQueryTypeFactory.NodeS, value); break; case XmlTypeCode.Item: // Support XPathNodeIterator if (value is XPathNodeIterator) { value = ChangeTypeXsltResult(XmlQueryTypeFactory.NodeS, value); break; } // Support IXPathNavigable and XPathNavigator navigable = value as IXPathNavigable; if (navigable != null) { if (value is XPathNavigator) value = new XmlQueryNodeSequence((XPathNavigator) value); else value = new XmlQueryNodeSequence(navigable.CreateNavigator()); break; } throw new XslTransformException(Res.Xslt_UnsupportedClrType, sourceType.Name); } break; } } Debug.Assert(XmlILTypeHelper.GetStorageType(xmlType).IsAssignableFrom(value.GetType()), "Xml type " + xmlType + " is not represented in ILGen as " + value.GetType().Name); return value; }
/// <summary> /// Convert from the Clr type of "value" to Clr type "destinationType" using V1 Xslt rules. /// These rules include converting any Rtf values to Nodes. /// </summary> internal object ChangeTypeXsltArgument(XmlQueryType xmlType, object value, Type destinationType) { Debug.Assert(XmlILTypeHelper.GetStorageType(xmlType).IsAssignableFrom(value.GetType()), "Values passed to ChangeTypeXsltArgument should be in ILGen's default Clr representation."); Debug.Assert(destinationType == XsltConvert.ObjectType || !destinationType.IsAssignableFrom(value.GetType()), "No need to call ChangeTypeXsltArgument since value is already assignable to destinationType " + destinationType); switch (xmlType.TypeCode) { case XmlTypeCode.String: if (destinationType == XsltConvert.DateTimeType) value = XsltConvert.ToDateTime((string) value); break; case XmlTypeCode.Double: if (destinationType != XsltConvert.DoubleType) value = Convert.ChangeType(value, destinationType, CultureInfo.InvariantCulture); break; case XmlTypeCode.Node: Debug.Assert(xmlType != XmlQueryTypeFactory.Node && xmlType != XmlQueryTypeFactory.NodeS, "Rtf values should have been eliminated by caller."); if (destinationType == XsltConvert.XPathNodeIteratorType) { value = new XPathArrayIterator((IList) value); } else if (destinationType == XsltConvert.XPathNavigatorArrayType) { // Copy sequence to XPathNavigator[] IList<XPathNavigator> seq = (IList<XPathNavigator>) value; XPathNavigator[] navArray = new XPathNavigator[seq.Count]; for (int i = 0; i < seq.Count; i++) navArray[i] = seq[i]; value = navArray; } break; case XmlTypeCode.Item: { // Only typeof(object) is supported as a destination type if (destinationType != XsltConvert.ObjectType) throw new XslTransformException(Res.Xslt_UnsupportedClrType, destinationType.Name); // Convert to default, backwards-compatible representation // 1. NodeSet: System.Xml.XPath.XPathNodeIterator // 2. Rtf: System.Xml.XPath.XPathNavigator // 3. Other: Default V1 representation IList<XPathItem> seq = (IList<XPathItem>) value; if (seq.Count == 1) { XPathItem item = seq[0]; if (item.IsNode) { // Node or Rtf RtfNavigator rtf = item as RtfNavigator; if (rtf != null) value = rtf.ToNavigator(); else value = new XPathArrayIterator((IList) value); } else { // Atomic value value = item.TypedValue; } } else { // Nodeset value = new XPathArrayIterator((IList) value); } break; } } Debug.Assert(destinationType.IsAssignableFrom(value.GetType()), "ChangeType from type " + value.GetType().Name + " to type " + destinationType.Name + " failed"); return value; }
public QilParameter Parameter(XmlQueryType t) { return f.Parameter(t); }
public QilParameter Parameter(QilNode defaultValue, QilName name, XmlQueryType t) { return f.Parameter(defaultValue, name, t); }
/// <summary> /// Apply filter an item type, add the result to a list, return cardinality /// </summary> private XmlQueryCardinality AddFilteredPrime(List<XmlQueryType> list, XmlQueryType source, XmlQueryType filter) { return AddFilteredPrime(list, source, filter, false); }
public QilNode Unknown(XmlQueryType t) { return f.Unknown(t); }
/// <summary> /// Construct the union of two XmlQueryTypes /// </summary> /// <param name="left">the left type</param> /// <param name="right">the right type</param> /// <returns>the union type</returns> public static XmlQueryType Choice(XmlQueryType left, XmlQueryType right) { return SequenceType.Create(ChoiceType.Create(PrimeChoice(new List<XmlQueryType>(left), right)), left.Cardinality | right.Cardinality); }
public QilNode IsType(QilNode expr, XmlQueryType t) { Debug.Assert(t != null, "Type can't be null"); return f.IsType(expr, t); }
/// <summary> /// Descend though the content model /// </summary> private XmlQueryCardinality AddChildParticle(List<XmlQueryType> list, XmlSchemaParticle particle, XmlQueryType filter) { XmlQueryCardinality card = XmlQueryCardinality.None; XmlSchemaElement element = particle as XmlSchemaElement; if (element != null) { // Single element card = AddFilteredPrime(list, CreateElementType(element), filter); } else { // XmlSchemaAny matches more then one element XmlSchemaAny any = particle as XmlSchemaAny; if (any != null) { XmlSchemaType elementSchemaType = any.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? XmlSchemaComplexType.UntypedAnyType : XmlSchemaComplexType.AnyType; switch (any.NamespaceList.Type) { case NamespaceList.ListType.Set: // Add a separate type for each namespace in the list foreach (string ns in any.NamespaceList.Enumerate) { card |= AddFilteredPrime(list, CreateElementType(ns, false, elementSchemaType), filter); } break; case NamespaceList.ListType.Other: // Add ##other card = AddFilteredPrime(list, CreateElementType(any.NamespaceList.Excluded, true, elementSchemaType), filter); break; case NamespaceList.ListType.Any: default: // Add ##any card = AddFilteredPrime(list, any.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? UntypedElement : Element, filter); break; } } else { // recurse into particle group XmlSchemaGroupBase group = particle as XmlSchemaGroupBase; if (group.Items.Count != 0) { if (particle is XmlSchemaChoice) { foreach (XmlSchemaParticle p in group.Items) { card |= AddChildParticle(list, p, filter); } } else { // Sequence and All foreach (XmlSchemaParticle p in group.Items) { card += AddChildParticle(list, p, filter); } } } } } return card * CardinalityOfParticle(particle); }
public QilNode XsltConvert(QilNode expr, XmlQueryType t) { return f.XsltConvert(expr, t); }
//----------------------------------------------- // XmlSortKeyAccumulator methods //----------------------------------------------- public void AddSortKey(XmlQueryType keyType) { MethodInfo meth = null; if (keyType == null) { meth = XmlILMethods.SortKeyEmpty; } else { Debug.Assert(keyType.IsAtomicValue, "Sort key must have atomic value type."); switch (keyType.TypeCode) { case XmlTypeCode.String: meth = XmlILMethods.SortKeyString; break; case XmlTypeCode.Decimal: meth = XmlILMethods.SortKeyDecimal; break; case XmlTypeCode.Integer: meth = XmlILMethods.SortKeyInteger; break; case XmlTypeCode.Int: meth = XmlILMethods.SortKeyInt; break; case XmlTypeCode.Boolean: meth = XmlILMethods.SortKeyInt; break; case XmlTypeCode.Double: meth = XmlILMethods.SortKeyDouble; break; case XmlTypeCode.DateTime: meth = XmlILMethods.SortKeyDateTime; break; case XmlTypeCode.None: // Empty sequence, so this path will never actually be taken Emit(OpCodes.Pop); meth = XmlILMethods.SortKeyEmpty; break; case XmlTypeCode.AnyAtomicType: Debug.Assert(false, "Heterogenous sort key is not allowed."); return; default: Debug.Assert(false, "Sorting over datatype " + keyType.TypeCode + " is not allowed."); break; } } Call(meth); }
/// <summary> /// Create sequence type from prime and cardinality. /// </summary> public static XmlQueryType Create(XmlQueryType prime, XmlQueryCardinality card) { Debug.Assert(prime != null, "SequenceType can only modify the cardinality of a non-null XmlQueryType."); Debug.Assert(prime.IsSingleton, "Prime type must have cardinality one."); if (prime.TypeCode == XmlTypeCode.None) { // If cardinality includes zero, then return (None, Zero), else return (None, None). return XmlQueryCardinality.Zero <= card ? Zero : None; } // Normalize sequences with these cardinalities: None, Zero, One if (card == XmlQueryCardinality.None) { return None; } else if (card == XmlQueryCardinality.Zero) { return Zero; } else if (card == XmlQueryCardinality.One) { return prime; } return new SequenceType(prime, card); }
/// <summary> /// Construct arrays of built-in types. /// </summary> static ItemType() { #if DEBUG Array arrEnum = Enum.GetValues(typeof(XmlTypeCode)); Debug.Assert((XmlTypeCode) arrEnum.GetValue(arrEnum.Length - 1) == XmlTypeCode.DayTimeDuration, "DayTimeDuration is no longer the last item in XmlTypeCode. This code expects it to be."); #endif int typeCount = (int) XmlTypeCode.DayTimeDuration + 1; BuiltInItemTypes = new XmlQueryType[typeCount]; BuiltInItemTypesStrict = new XmlQueryType[typeCount]; for (int i = 0; i < typeCount; i++) { XmlTypeCode typeCode = (XmlTypeCode)i; switch ((XmlTypeCode) i) { case XmlTypeCode.None: BuiltInItemTypes[i] = ChoiceType.None; BuiltInItemTypesStrict[i] = ChoiceType.None; continue; case XmlTypeCode.Item: case XmlTypeCode.Node: BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, false); BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; break; case XmlTypeCode.Document: case XmlTypeCode.Element: case XmlTypeCode.Namespace: case XmlTypeCode.ProcessingInstruction: case XmlTypeCode.Comment: case XmlTypeCode.Text: BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true); BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; break; case XmlTypeCode.Attribute: BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.AnySimpleType, false, false, true); BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; break; case XmlTypeCode.AnyAtomicType: BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.AnyAtomicType, false, false, true); BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; break; case XmlTypeCode.UntypedAtomic: // xdt:untypedAtomic is sealed, and therefore always strict BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.UntypedAtomicType, false, true, true); BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; break; default: XmlSchemaType builtInType = XmlSchemaType.GetBuiltInSimpleType(typeCode); BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, builtInType, false, false, true); BuiltInItemTypesStrict[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, builtInType, false, true, true); break; } } UntypedDocument = new ItemType(XmlTypeCode.Document, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.UntypedAnyType, false, false, true); UntypedElement = new ItemType(XmlTypeCode.Element, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.UntypedAnyType, false, false, true); UntypedAttribute = new ItemType(XmlTypeCode.Attribute, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.UntypedAtomicType, false, false, true); NodeNotRtf = new ItemType(XmlTypeCode.Node, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true); SpecialBuiltInItemTypes = new XmlQueryType[4] { UntypedDocument, UntypedElement, UntypedAttribute, NodeNotRtf }; }
/// <summary> /// Compute a sequence of zero to some max cardinality. /// </summary> /// <param name="t">the type to sequence</param> /// <param name="c">the upper bound</param> /// <returns>the sequence of t from 0 to c</returns> public static XmlQueryType AtMost(XmlQueryType t, XmlQueryCardinality c) { return PrimeProduct(t, c.AtMost()); }
/// <summary> /// Private constructor. Create methods should be used to create instances. /// </summary> private SequenceType(XmlQueryType prime, XmlQueryCardinality card) { this.prime = prime; this.card = card; }