/* NOTE: This code depends on the form of Qil expressions generated by XPathPatternBuilder. * More specifically, it recognizes the following two patterns: * * A) /, *, @*, text(), comment(), processing-instruction(): * (And* $x:(IsType RefTo LiteralType)) * * B) foo, @ns:foo, processing-instruction('foo'): * (And* $x:(And (IsType RefTo LiteralType) (Eq (NameOf RefTo) LiteralQName))) * * where all RefTo refer to 'it', and LiteralType has exactly one NodeKind bit set. * * If one of patterns recognized, we nip $x off of the nested And sequence: * (And* (And2 (And1 $x:* $y:*) $z:*)) => (And* (And2 $y:* $z:*)) */ 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; } }
private bool CheckNamespaceInScope(QilBinary nd) { QilName? ndName; string prefix, ns; string? prefixExisting, nsExisting; XPathNodeType nodeType; switch (nd.NodeType) { case QilNodeType.ElementCtor: case QilNodeType.AttributeCtor: ndName = nd.Left as QilName; if (ndName != null) { prefix = ndName.Prefix; ns = ndName.NamespaceUri; nodeType = (nd.NodeType == QilNodeType.ElementCtor) ? XPathNodeType.Element : XPathNodeType.Attribute; break; } // Not a literal name, so return false return(false); default: Debug.Assert(nd.NodeType == QilNodeType.NamespaceDecl); prefix = (string)(QilLiteral)nd.Left; ns = (string)(QilLiteral)nd.Right; nodeType = XPathNodeType.Namespace; break; } // Attribute with null namespace and xmlns:xml are always in-scope if (nd.NodeType == QilNodeType.AttributeCtor && ns.Length == 0 || prefix == "xml" && ns == XmlReservedNs.NsXml) { XmlILConstructInfo.Write(nd).IsNamespaceInScope = true; return(true); } // Don't process names that are invalid if (!ValidateNames.ValidateName(prefix, string.Empty, ns, nodeType, ValidateNames.Flags.CheckPrefixMapping)) { return(false); } // Atomize names prefix = _nsmgr.NameTable !.Add(prefix); ns = _nsmgr.NameTable.Add(ns); // Determine whether namespace is already in-scope for (int iNmsp = 0; iNmsp < _cntNmsp; iNmsp++) { _nsmgr.GetNamespaceDeclaration(iNmsp, out prefixExisting, out nsExisting); // If prefix is already declared, if ((object)prefix == (object?)prefixExisting) { // Then if the namespace is the same, this namespace is redundant if ((object)ns == (object?)nsExisting) { XmlILConstructInfo.Write(nd).IsNamespaceInScope = true; } // Else quit searching, because any further matching prefixes will be hidden (not in-scope) Debug.Assert(nd.NodeType != QilNodeType.NamespaceDecl || !_nsmgr.HasNamespace(prefix) || _nsmgr.LookupNamespace(prefix) == ns, "Compilers must ensure that namespace declarations do not conflict with the namespace used by the element constructor."); break; } } // If not in-scope, then add if it's allowed if (_addInScopeNmsp) { _nsmgr.AddNamespace(prefix, ns); _cntNmsp++; } return(true); }