// also called by XPathPatternBuilder public static XmlNodeKindFlags AxisTypeMask(XmlNodeKindFlags inputTypeMask, XPathNodeType nodeType, XPathAxis xpathAxis) { return((XmlNodeKindFlags)( (int)inputTypeMask & (int)s_XPathNodeType2QilXmlNodeKind[(int)nodeType] & (int)s_XPathAxisMask[(int)xpathAxis] )); }
public QilNode BuildMatcher(QilIterator it, IList <XslNode> actualArgs, QilNode otherwise) { QilNode result = otherwise; foreach (List <TemplateMatch> list in allMatches) { foreach (TemplateMatch match in list) { XmlNodeKindFlags nodeKind = match.NodeKind; QilName qname = match.QName; QilNode cond = match.Condition; if (cond != null) { // We have to clone, because the same pattern may be used // in many different xsl:apply-templates/imports functions cond = cond.DeepClone(f.BaseFactory); cond = refReplacer.Replace(cond, match.Iterator, it); } if (nodeKind != 0) { XmlQueryType nodeType; switch (nodeKind) { case XmlNodeKindFlags.Element: nodeType = T.Element; break; case XmlNodeKindFlags.Attribute: nodeType = T.Attribute; break; case XmlNodeKindFlags.Text: nodeType = T.Text; break; case XmlNodeKindFlags.Document: nodeType = T.Document; break; case XmlNodeKindFlags.Comment: nodeType = T.Comment; break; case XmlNodeKindFlags.PI: nodeType = T.PI; break; default: nodeType = null; break; } Debug.Assert(nodeType != null, "Unexpected nodeKind: " + nodeKind); QilNode typeNameCheck = f.IsType(it, nodeType); if (qname != null) { typeNameCheck = f.And(typeNameCheck, f.Eq(f.NameOf(it), qname.ShallowClone(f.BaseFactory))); } cond = (cond == null) ? typeNameCheck : f.And(typeNameCheck, cond); } result = f.Conditional(cond, invkGen.GenerateInvoke(match.TemplateFunction, actualArgs), result ); } } return(result); }
QilNode BuildAxisFilter(QilNode qilAxis, XPathAxis xpathAxis, XPathNodeType nodeType, string name, string nsUri) { XmlNodeKindFlags original = qilAxis.XmlType.NodeKinds; XmlNodeKindFlags required = AxisTypeMask(original, nodeType, xpathAxis); QilIterator itr; if (required == 0) { return(f.Sequence()); } else if (required == original) { } else { qilAxis = f.Filter(itr = f.For(qilAxis), f.IsType(itr, T.NodeChoice(required))); qilAxis.XmlType = T.PrimeProduct(T.NodeChoice(required), qilAxis.XmlType.Cardinality); // Without code bellow IlGeneragion gives stack overflow exception for the following passage. //<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> // <xsl:template match="/"> // <xsl:value-of select="descendant::author/@id | comment()" /> // </xsl:template> //</xsl:stylesheet> // ToDo: remove this code when IlGen bug will be fixed. if (qilAxis.NodeType == QilNodeType.Filter) { QilLoop filter = (QilLoop)qilAxis; filter.Body = f.And(filter.Body, name != null && nsUri != null ? f.Eq(f.NameOf(itr), f.QName(name, nsUri)) : // ns:bar || bar nsUri != null ? f.Eq(f.NamespaceUriOf(itr), f.String(nsUri)) : // ns:* name != null ? f.Eq(f.LocalNameOf(itr), f.String(name)) : // *:foo /*name == nsUri == null*/ f.True() // * ); return(filter); } } return(f.Filter(itr = f.For(qilAxis), name != null && nsUri != null ? f.Eq(f.NameOf(itr), f.QName(name, nsUri)) : // ns:bar || bar nsUri != null ? f.Eq(f.NamespaceUriOf(itr), f.String(nsUri)) : // ns:* name != null ? f.Eq(f.LocalNameOf(itr), f.String(name)) : // *:foo /*name == nsUri == null*/ f.True() // * )); }
public QilNode GetPosition() { QilLoop clone = (QilLoop)cloner.Clone(baseContext); XmlNodeKindFlags nodeKinds = baseContext.XmlType.NodeKinds; // baseContext either always returns attributes (attribute::), or never returns attributes or namespaces (child::) if (nodeKinds == XmlNodeKindFlags.Attribute) { QilIterator i = f.For(f.Parent(GetCurrent())); clone.Variable.Binding = f.Content(i); clone.Body = f.And(clone.Body, f.Before(clone.Variable, GetCurrent())); clone = f.BaseFactory.Loop(i, clone); } else { Debug.Assert((nodeKinds & (XmlNodeKindFlags.Attribute | XmlNodeKindFlags.Namespace)) == XmlNodeKindFlags.None); clone.Variable.Binding = f.PrecedingSibling(GetCurrent()); } return(f.Add(f.Double(1), f.XsltConvert(f.Length(clone), T.DoubleX))); }
QilNode BuildAxisFilter(QilNode qilAxis, XPathAxis xpathAxis, XPathNodeType nodeType, string name, string nsUri) { XmlNodeKindFlags original = qilAxis.XmlType.NodeKinds; XmlNodeKindFlags required = AxisTypeMask(original, nodeType, xpathAxis); QilIterator itr; if (required == 0) { return(f.Sequence()); } else if (required == original) { } else { qilAxis = f.Filter(itr = f.For(qilAxis), f.IsType(itr, T.NodeChoice(required))); qilAxis.XmlType = T.PrimeProduct(T.NodeChoice(required), qilAxis.XmlType.Cardinality); if (qilAxis.NodeType == QilNodeType.Filter) { QilLoop filter = (QilLoop)qilAxis; filter.Body = f.And(filter.Body, name != null && nsUri != null ? f.Eq(f.NameOf(itr), f.QName(name, nsUri)) : // ns:bar || bar nsUri != null ? f.Eq(f.NamespaceUriOf(itr), f.String(nsUri)) : // ns:* name != null ? f.Eq(f.LocalNameOf(itr), f.String(name)) : // *:foo /*name == nsUri == null*/ f.True() // * ); return(filter); } } return(f.Filter(itr = f.For(qilAxis), name != null && nsUri != null ? f.Eq(f.NameOf(itr), f.QName(name, nsUri)) : // ns:bar || bar nsUri != null ? f.Eq(f.NamespaceUriOf(itr), f.String(nsUri)) : // ns:* name != null ? f.Eq(f.LocalNameOf(itr), f.String(name)) : // *:foo /*name == nsUri == null*/ f.True() // * )); }
private static QilLoop BuildAxisFilter(QilPatternFactory f, QilIterator itr, XPathAxis xpathAxis, XPathNodeType nodeType, string name, string nsUri) { QilNode nameTest = ( name != null && nsUri != null ? f.Eq(f.NameOf(itr), f.QName(name, nsUri)) : // ns:bar || bar nsUri != null ? f.Eq(f.NamespaceUriOf(itr), f.String(nsUri)) : // ns:* name != null ? f.Eq(f.LocalNameOf(itr), f.String(name)) : // *:foo /*name == nsUri == null*/ f.True() // * ); XmlNodeKindFlags intersection = XPathBuilder.AxisTypeMask(itr.XmlType.NodeKinds, nodeType, xpathAxis); QilNode typeTest = ( intersection == 0 ? f.False() : // input & required doesn't intersect intersection == itr.XmlType.NodeKinds ? f.True() : // input is subset of required /*else*/ f.IsType(itr, T.NodeChoice(intersection)) ); QilLoop filter = f.BaseFactory.Filter(itr, f.And(typeTest, nameTest)); filter.XmlType = T.PrimeProduct(T.NodeChoice(intersection), filter.XmlType.Cardinality); return(filter); }
private void NipOffTypeNameCheck() { QilBinary[] leftPath = new QilBinary[4]; // Circular buffer for last 4 And nodes int idx = -1; // Index of last element in leftPath QilNode node = _condition !; // Walker through left path of the tree _nodeKind = XmlNodeKindFlags.None; _qname = null; while (node.NodeType == QilNodeType.And) { node = (leftPath[++idx & 3] = (QilBinary)node).Left; } // Recognizing (IsType RefTo LiteralType) if (!(node.NodeType == QilNodeType.IsType)) { return; } QilBinary isType = (QilBinary)node; if (!(isType.Left == _iterator && isType.Right.NodeType == QilNodeType.LiteralType)) { return; } XmlNodeKindFlags nodeKinds = isType.Right.XmlType !.NodeKinds; if (!Bits.ExactlyOne((uint)nodeKinds)) { return; } // Recognized pattern A, check for B QilNode x = isType; _nodeKind = nodeKinds; QilBinary lastAnd = leftPath[idx & 3]; if (lastAnd != null && lastAnd.Right.NodeType == QilNodeType.Eq) { QilBinary eq = (QilBinary)lastAnd.Right; // Recognizing (Eq (NameOf RefTo) LiteralQName) if (eq.Left.NodeType == QilNodeType.NameOf && ((QilUnary)eq.Left).Child == _iterator && eq.Right.NodeType == QilNodeType.LiteralQName ) { // Recognized pattern B x = lastAnd; _qname = (QilName?)((QilLiteral)eq.Right).Value; idx--; } } // Nip $x off the condition QilBinary and1 = leftPath[idx & 3]; QilBinary and2 = leftPath[--idx & 3]; if (and2 != null) { and2.Left = and1.Right; } else if (and1 != null) { _condition = and1.Right; } else { _condition = null; } }
/// <summary> /// Private constructor. Create methods should be used to create instances. /// </summary> private ChoiceType(List<XmlQueryType> members) { Debug.Assert(members != null && members.Count != 1, "ChoiceType must contain a list with 0 or >1 types."); this.members = members; // Compute supertype of all member types for (int i = 0; i < members.Count; i++) { XmlQueryType t = members[i]; Debug.Assert(t.Cardinality == XmlQueryCardinality.One, "ChoiceType member types must be prime types."); // Summarize the union of member types as a single type if (this.code == XmlTypeCode.None) { // None combined with member type is the member type this.code = t.TypeCode; this.schemaType = t.SchemaType; } else if (IsNode && t.IsNode) { // Node combined with node is node if (this.code == t.TypeCode) { // Element or attribute combined with element or attribute can be summarized as element(*, XmlSchemaComplexType.AnyType) or attribute(*, DatatypeImplementation.AnySimpleType) if (this.code == XmlTypeCode.Element) this.schemaType = XmlSchemaComplexType.AnyType; else if (this.code == XmlTypeCode.Attribute) this.schemaType = DatatypeImplementation.AnySimpleType; } else { this.code = XmlTypeCode.Node; this.schemaType = null; } } else if (IsAtomicValue && t.IsAtomicValue) { // Atomic value combined with atomic value is atomic value this.code = XmlTypeCode.AnyAtomicType; this.schemaType = DatatypeImplementation.AnyAtomicType; } else { // Else we'll summarize types as Item this.code = XmlTypeCode.Item; this.schemaType = null; } // Always track union of node kinds this.nodeKinds |= t.NodeKinds; } }
/// <summary> /// Create choice between node kinds. /// </summary> public static XmlQueryType Create(XmlNodeKindFlags nodeKinds) { List<XmlQueryType> members; // If exactly one kind is set, then create singleton ItemType if (Bits.ExactlyOne((uint) nodeKinds)) return ItemType.Create(NodeKindToTypeCode[Bits.LeastPosition((uint) nodeKinds)], false); members = new List<XmlQueryType>(); while (nodeKinds != XmlNodeKindFlags.None) { members.Add(ItemType.Create(NodeKindToTypeCode[Bits.LeastPosition((uint) nodeKinds)], false)); nodeKinds = (XmlNodeKindFlags) Bits.ClearLeast((uint) nodeKinds); } return Create(members); }
/// <summary> /// Private constructor. Create methods should be used to create instances. /// </summary> private ItemType(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType schemaType, bool isNillable, bool isStrict, bool isNotRtf) { Debug.Assert(nameTest != null, "nameTest cannot be null"); Debug.Assert(schemaType != null, "schemaType cannot be null"); this.code = code; this.nameTest = nameTest; this.schemaType = schemaType; this.isNillable = isNillable; this.isStrict = isStrict; this.isNotRtf = isNotRtf; Debug.Assert(!IsAtomicValue || schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic); switch (code) { case XmlTypeCode.Item: this.nodeKinds = XmlNodeKindFlags.Any; break; case XmlTypeCode.Node: this.nodeKinds = XmlNodeKindFlags.Any; break; case XmlTypeCode.Document: this.nodeKinds = XmlNodeKindFlags.Document; break; case XmlTypeCode.Element: this.nodeKinds = XmlNodeKindFlags.Element; break; case XmlTypeCode.Attribute: this.nodeKinds = XmlNodeKindFlags.Attribute; break; case XmlTypeCode.Namespace: this.nodeKinds = XmlNodeKindFlags.Namespace; break; case XmlTypeCode.ProcessingInstruction: this.nodeKinds = XmlNodeKindFlags.PI; break; case XmlTypeCode.Comment: this.nodeKinds = XmlNodeKindFlags.Comment; break; case XmlTypeCode.Text: this.nodeKinds = XmlNodeKindFlags.Text; break; default: this.nodeKinds = XmlNodeKindFlags.None; break; } }
/// <summary> /// Create a Node XmlQueryType which is the choice between several different node kinds. /// </summary> /// <param name="kinds">the node kinds which will make up the choice</param> /// <returns>the node type</returns> public static XmlQueryType NodeChoice(XmlNodeKindFlags kinds) { return ChoiceType.Create(kinds); }
/// <summary> /// Return true if more than one node type is set. /// </summary> private static bool IsNodeTypeUnion(XmlNodeKindFlags xmlTypes) { return ((int)xmlTypes & ((int)xmlTypes - 1)) != 0; }
/// <summary> /// Load an XmlNavigatorFilter that matches only the specified name and types onto the stack. /// </summary> private void LoadSelectFilter(XmlNodeKindFlags xmlTypes, QilName ndName) { if (ndName != null) { // Push NameFilter Debug.Assert(xmlTypes == XmlNodeKindFlags.Element); _helper.CallGetNameFilter(_helper.StaticData.DeclareNameFilter(ndName.LocalName, ndName.NamespaceUri)); } else { // Either type cannot be a union, or else it must be >= union of all Content types bool isXmlTypeUnion = IsNodeTypeUnion(xmlTypes); Debug.Assert(!isXmlTypeUnion || (xmlTypes & XmlNodeKindFlags.Content) == XmlNodeKindFlags.Content); if (isXmlTypeUnion) { if ((xmlTypes & XmlNodeKindFlags.Attribute) != 0) { // Union includes attributes, so allow all node kinds _helper.CallGetTypeFilter(XPathNodeType.All); } else { // Filter attributes _helper.CallGetTypeFilter(XPathNodeType.Attribute); } } else { // Filter nodes of all but one type _helper.CallGetTypeFilter(QilXmlToXPathNodeType(xmlTypes)); } } }
/// <summary> /// Map the XmlNodeKindFlags enumeration into the XPathNodeType enumeration. /// </summary> private XPathNodeType QilXmlToXPathNodeType(XmlNodeKindFlags xmlTypes) { switch (xmlTypes) { case XmlNodeKindFlags.Element: return XPathNodeType.Element; case XmlNodeKindFlags.Attribute: return XPathNodeType.Attribute; case XmlNodeKindFlags.Text: return XPathNodeType.Text; case XmlNodeKindFlags.Comment: return XPathNodeType.Comment; } Debug.Assert(xmlTypes == XmlNodeKindFlags.PI); return XPathNodeType.ProcessingInstruction; }
/// <summary> /// Generate boiler-plate code to create an Xml iterator that controls a nested iterator. /// </summary> /// <remarks> /// Iterator iter; /// iter.Create(filter [, orSelf]); /// ...nested iterator... /// navInput = nestedNested; /// goto LabelCall; /// LabelNext: /// navInput = null; /// LabelCall: /// switch (iter.MoveNext(navInput)) { /// case IteratorState.NoMoreNodes: goto LabelNextCtxt; /// case IteratorState.NextInputNode: goto LabelNextNested; /// } /// </remarks> private void CreateContainerIterator(QilUnary ndDod, string iterName, Type iterType, MethodInfo methCreate, MethodInfo methNext, XmlNodeKindFlags kinds, QilName ndName, TriState orSelf) { // Iterator iter; LocalBuilder locIter = _helper.DeclareLocal(iterName, iterType); Label lblOnEndNested; QilLoop ndLoop = (QilLoop)ndDod.Child; Debug.Assert(ndDod.NodeType == QilNodeType.DocOrderDistinct && ndLoop != null); // iter.Create(filter [, orSelf]); _helper.Emit(OpCodes.Ldloca, locIter); LoadSelectFilter(kinds, ndName); if (orSelf != TriState.Unknown) _helper.LoadBoolean(orSelf == TriState.True); _helper.Call(methCreate); // Generate nested iterator (branch to lblOnEndNested when iteration is complete) lblOnEndNested = _helper.DefineLabel(); StartNestedIterator(ndLoop, lblOnEndNested); StartBinding(ndLoop.Variable); EndBinding(ndLoop.Variable); EndNestedIterator(ndLoop.Variable); _iterCurr.Storage = _iterNested.Storage; GenerateContainerIterator(ndDod, locIter, lblOnEndNested, methNext, typeof(XPathNavigator)); }
/// <summary> /// Generate boiler-plate code to create an Xml iterator that uses an XmlNavigatorFilter to filter items. /// </summary> /// <remarks> /// Iterator iter; /// iter.Create(navCtxt, filter [, orSelf] [, navEnd]); /// LabelNext: /// if (!iter.MoveNext()) /// goto LabelNextCtxt; /// </remarks> private void CreateFilteredIterator(QilNode ndCtxt, string iterName, Type iterType, MethodInfo methCreate, MethodInfo methNext, XmlNodeKindFlags kinds, QilName ndName, TriState orSelf, QilNode ndEnd) { // Iterator iter; LocalBuilder locIter = _helper.DeclareLocal(iterName, iterType); // iter.Create(navCtxt, filter [, orSelf], [, navEnd]); _helper.Emit(OpCodes.Ldloca, locIter); NestedVisitEnsureStack(ndCtxt); LoadSelectFilter(kinds, ndName); if (orSelf != TriState.Unknown) _helper.LoadBoolean(orSelf == TriState.True); if (ndEnd != null) NestedVisitEnsureStack(ndEnd); _helper.Call(methCreate); GenerateSimpleIterator(typeof(XPathNavigator), locIter, methNext); }