private bool HandleFilterPatterns(QilLoop ndFilter) {
OptimizerPatterns patt = OptimizerPatterns.Read(ndFilter);
LocalBuilder locIter;
XmlNodeKindFlags kinds;
QilName name;
QilNode input, step;
bool isFilterElements;
// Handle FilterElements and FilterContentKind patterns
isFilterElements = patt.MatchesPattern(OptimizerPatternName.FilterElements);
if (isFilterElements || patt.MatchesPattern(OptimizerPatternName.FilterContentKind)) {
if (isFilterElements) {
// FilterElements pattern, so Kind = Element and Name = Argument
kinds = XmlNodeKindFlags.Element;
name = (QilName) patt.GetArgument(OptimizerPatternArgument.ElementQName);
}
else {
// FilterKindTest pattern, so Kind = Argument and Name = null
kinds = ((XmlQueryType) patt.GetArgument(OptimizerPatternArgument.KindTestType)).NodeKinds;
name = null;
}
step = (QilNode) patt.GetArgument(OptimizerPatternArgument.StepNode);
input = (QilNode) patt.GetArgument(OptimizerPatternArgument.StepInput);
switch (step.NodeType) {
case QilNodeType.Content:
if (isFilterElements) {
// Iterator iter;
locIter = this.helper.DeclareLocal("$$$iterElemContent", typeof(ElementContentIterator));
// iter.Create(navCtxt, locName, ns);
this.helper.Emit(OpCodes.Ldloca, locIter);
NestedVisitEnsureStack(input);
this.helper.CallGetAtomizedName(this.helper.StaticData.DeclareName(name.LocalName));
this.helper.CallGetAtomizedName(this.helper.StaticData.DeclareName(name.NamespaceUri));
this.helper.Call(XmlILMethods.ElemContentCreate);
GenerateSimpleIterator(typeof(XPathNavigator), locIter, XmlILMethods.ElemContentNext);
}
else {
if (kinds == XmlNodeKindFlags.Content) {
CreateSimpleIterator(input, "$$$iterContent", typeof(ContentIterator), XmlILMethods.ContentCreate, XmlILMethods.ContentNext);
}
else {
// Iterator iter;
locIter = this.helper.DeclareLocal("$$$iterContent", typeof(NodeKindContentIterator));
// iter.Create(navCtxt, nodeType);
this.helper.Emit(OpCodes.Ldloca, locIter);
NestedVisitEnsureStack(input);
this.helper.LoadInteger((int) QilXmlToXPathNodeType(kinds));
this.helper.Call(XmlILMethods.KindContentCreate);
GenerateSimpleIterator(typeof(XPathNavigator), locIter, XmlILMethods.KindContentNext);
}
}
return true;
case QilNodeType.Parent:
CreateFilteredIterator(input, "$$$iterPar", typeof(ParentIterator), XmlILMethods.ParentCreate, XmlILMethods.ParentNext,
kinds, name, TriState.Unknown, null);
return true;
case QilNodeType.Ancestor:
case QilNodeType.AncestorOrSelf:
CreateFilteredIterator(input, "$$$iterAnc", typeof(AncestorIterator), XmlILMethods.AncCreate, XmlILMethods.AncNext,
kinds, name, (step.NodeType == QilNodeType.Ancestor) ? TriState.False : TriState.True, null);
return true;
case QilNodeType.Descendant:
case QilNodeType.DescendantOrSelf:
CreateFilteredIterator(input, "$$$iterDesc", typeof(DescendantIterator), XmlILMethods.DescCreate, XmlILMethods.DescNext,
kinds, name, (step.NodeType == QilNodeType.Descendant) ? TriState.False : TriState.True, null);
return true;
case QilNodeType.Preceding:
CreateFilteredIterator(input, "$$$iterPrec", typeof(PrecedingIterator), XmlILMethods.PrecCreate, XmlILMethods.PrecNext,
kinds, name, TriState.Unknown, null);
return true;
case QilNodeType.FollowingSibling:
CreateFilteredIterator(input, "$$$iterFollSib", typeof(FollowingSiblingIterator), XmlILMethods.FollSibCreate, XmlILMethods.FollSibNext,
kinds, name, TriState.Unknown, null);
return true;
case QilNodeType.PrecedingSibling:
CreateFilteredIterator(input, "$$$iterPreSib", typeof(PrecedingSiblingIterator), XmlILMethods.PreSibCreate, XmlILMethods.PreSibNext,
kinds, name, TriState.Unknown, null);
return true;
case QilNodeType.NodeRange:
CreateFilteredIterator(input, "$$$iterRange", typeof(NodeRangeIterator), XmlILMethods.NodeRangeCreate, XmlILMethods.NodeRangeNext,
kinds, name, TriState.Unknown, ((QilBinary) step).Right);
return true;
case QilNodeType.XPathFollowing:
CreateFilteredIterator(input, "$$$iterFoll", typeof(XPathFollowingIterator), XmlILMethods.XPFollCreate, XmlILMethods.XPFollNext,
kinds, name, TriState.Unknown, null);
return true;
case QilNodeType.XPathPreceding:
CreateFilteredIterator(input, "$$$iterPrec", typeof(XPathPrecedingIterator), XmlILMethods.XPPrecCreate, XmlILMethods.XPPrecNext,
kinds, name, TriState.Unknown, null);
return true;
default:
Debug.Assert(false, "Pattern " + step.NodeType + " should have been handled.");
break;
}
}
else if (patt.MatchesPattern(OptimizerPatternName.FilterAttributeKind)) {
// Handle FilterAttributeKind pattern
input = (QilNode) patt.GetArgument(OptimizerPatternArgument.StepInput);
CreateSimpleIterator(input, "$$$iterAttr", typeof(AttributeIterator), XmlILMethods.AttrCreate, XmlILMethods.AttrNext);
return true;
}
else if (patt.MatchesPattern(OptimizerPatternName.EqualityIndex)) {
// Handle EqualityIndex pattern
Label lblOnEnd = this.helper.DefineLabel();
Label lblLookup = this.helper.DefineLabel();
QilIterator nodes = (QilIterator) patt.GetArgument(OptimizerPatternArgument.IndexedNodes);
QilNode keys = (QilNode) patt.GetArgument(OptimizerPatternArgument.KeyExpression);
// XmlILIndex index;
// if (runtime.FindIndex(navCtxt, indexId, out index)) goto LabelLookup;
LocalBuilder locIndex = this.helper.DeclareLocal("$$$index", typeof(XmlILIndex));
this.helper.LoadQueryRuntime();
this.helper.Emit(OpCodes.Ldarg_1);
this.helper.LoadInteger(this.indexId);
this.helper.Emit(OpCodes.Ldloca, locIndex);
this.helper.Call(XmlILMethods.FindIndex);
this.helper.Emit(OpCodes.Brtrue, lblLookup);
// runtime.AddNewIndex(navCtxt, indexId, [build index]);
this.helper.LoadQueryRuntime();
this.helper.Emit(OpCodes.Ldarg_1);
this.helper.LoadInteger(this.indexId);
this.helper.Emit(OpCodes.Ldloc, locIndex);
// Generate code to iterate over the the nodes which are being indexed ($iterNodes in the pattern)
StartNestedIterator(nodes, lblOnEnd);
StartBinding(nodes);
// Generate code to iterate over the keys for each node ($bindingKeys in the pattern)
Visit(keys);
// index.Add(key, value);
this.iterCurr.EnsureStackNoCache();
VisitFor(nodes);
this.iterCurr.EnsureStackNoCache();
this.iterCurr.EnsureItemStorageType(nodes.XmlType, typeof(XPathNavigator));
this.helper.Call(XmlILMethods.IndexAdd);
this.helper.Emit(OpCodes.Ldloc, locIndex);
// LabelOnEnd:
this.iterCurr.LoopToEnd(lblOnEnd);
EndBinding(nodes);
EndNestedIterator(nodes);
// runtime.AddNewIndex(navCtxt, indexId, [build index]);
this.helper.Call(XmlILMethods.AddNewIndex);
// LabelLookup:
// results = index.Lookup(keyValue);
this.helper.MarkLabel(lblLookup);
this.helper.Emit(OpCodes.Ldloc, locIndex);
this.helper.Emit(OpCodes.Ldarg_2);
this.helper.Call(XmlILMethods.IndexLookup);
this.iterCurr.Storage = StorageDescriptor.Stack(typeof(XPathNavigator), true);
this.indexId++;
return true;
}
return false;
}