public virtual QilNode Operator(XPathOperator op, QilNode?left, QilNode?right) { Debug.Assert(op != XPathOperator.Unknown); XPathOperatorGroup opGroup = s_operatorGroup[(int)op]; Debug.Assert((opGroup != XPathOperatorGroup.Negate && right != null) || (opGroup == XPathOperatorGroup.Negate && right == null)); switch (opGroup) { case XPathOperatorGroup.Logical: return(LogicalOperator(op, left !, right !)); case XPathOperatorGroup.Equality: return(EqualityOperator(op, left !, right !)); case XPathOperatorGroup.Relational: return(RelationalOperator(op, left !, right !)); case XPathOperatorGroup.Arithmetic: return(ArithmeticOperator(op, left !, right !)); case XPathOperatorGroup.Negate: return(NegateOperator(op, left !)); case XPathOperatorGroup.Union: return(UnionOperator(op, left, right !)); default: Debug.Fail($"{op} is not a valid XPathOperator"); return(null); } }
public virtual QilNode?EndBuild(QilNode?result) { if (result == null) { // special door to clean builder state in exception handlers _inTheBuild = false; return(result); } Debug.Assert(_inTheBuild, "StartBuild() wasn't called"); if (result.XmlType !.MaybeMany && result.XmlType.IsNode && result.XmlType.IsNotRtf) { result = _f.DocOrderDistinct(result); } result = _fixupVisitor.Fixup(result, /*environment:*/ _environment); numFixupCurrent -= _fixupVisitor.numCurrent; numFixupPosition -= _fixupVisitor.numPosition; numFixupLast -= _fixupVisitor.numLast; // All these variables will be positive for "false() and (. = position() + last())" // since QilPatternFactory eliminates the right operand of 'and' Debug.Assert(numFixupCurrent >= 0, "Context fixup error"); Debug.Assert(numFixupPosition >= 0, "Context fixup error"); Debug.Assert(numFixupLast >= 0, "Context fixup error"); _inTheBuild = false; return(result); }
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 QilNode ConvertReletive2Absolute(QilNode node, QilNode fixup) { QilDepthChecker.Check(node); Debug.Assert(node != null); Debug.Assert(fixup != null); _fixup = fixup; return(this.Visit(node)); }
public QilParameter Parameter(QilNode?defaultValue, QilNode?name, XmlQueryType xmlType) { QilParameter n = new QilParameter(QilNodeType.Parameter, defaultValue, name, xmlType); n.XmlType = _typeCheck.CheckParameter(n); TraceNode(n); return(n); }
public void Sort(QilNode?sortKeys) { if (sortKeys != null) { // If sorting is required, cache the input node-set to support last() within sort key expressions EnsureCache(); // The rest of the loop content must be compiled in the context of already sorted node-set _current = _f.For(_f.Sort(_current !, sortKeys)); } }
public QilNode EnsureNodeSet(QilNode n) { QilNode?result = TryEnsureNodeSet(n); if (result == null) { throw new XPathCompileException(SR.XPath_NodeSetExpected); } return(result); }
public QilNode?EndBuild(QilNode?result) { Debug.Assert(_inTheBuild, "StartBuild() wasn't called"); // All these variables will be positive for "false() and (. = position() + last())" // since QilPatternFactory eliminates the right operand of 'and' Debug.Assert(_predicateEnvironment.numFixupCurrent >= 0, "Context fixup error"); Debug.Assert(_predicateEnvironment.numFixupPosition >= 0, "Context fixup error"); Debug.Assert(_predicateEnvironment.numFixupLast >= 0, "Context fixup error"); _inTheBuild = false; return(result); }
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); }
public override QilNode this[int index] { get { if (index != 0) { throw new IndexOutOfRangeException(); } return(_binding !); } set { if (index != 0) { throw new IndexOutOfRangeException(); } _binding = value; } }
public QilNode Fixup(QilNode inExpr, QilIterator current, QilNode?last) { QilDepthChecker.Check(inExpr); _current = current; _last = last; Debug.Assert(current != null); _justCount = false; _environment = null; numCurrent = numPosition = numLast = 0; inExpr = VisitAssumeReference(inExpr); #if StopMaskOptimisation SetStopVisitMark(inExpr, /*stop*/ true); #endif return(inExpr); }
public TemplateMatch(Template template, QilLoop filter) { _template = template; _priority = double.IsNaN(template.Priority) ? XPathPatternBuilder.GetPriority(filter) : template.Priority; _iterator = filter.Variable; _condition = filter.Body; XPathPatternBuilder.CleanAnnotation(filter); NipOffTypeNameCheck(); Debug.Assert( _qname == null || _nodeKind == XmlNodeKindFlags.Element || _nodeKind == XmlNodeKindFlags.Attribute || _nodeKind == XmlNodeKindFlags.PI, "qname may be not null only for element, attribute, or PI patterns" ); }
private QilNode MatchPattern(QilIterator it, TemplateMatch match) { QilNode?cond = match.Condition; if (cond == null) { return(_f.True()); } else { // We have to clone, because the same pattern may be used // in many different xsl:apply-templates/imports functions cond = cond.DeepClone(_f.BaseFactory); return(_refReplacer.Replace(cond, match.Iterator, it)); } }
public void Append(QilNode?value) { Debug.Assert(_inUse, "Reset() wasn't called"); if (value != null) { Debug.Assert(value.XmlType !.TypeCode == XmlTypeCode.String); if (value.NodeType == QilNodeType.LiteralString) { _builder.Append((string)(QilLiteral)value); } else { FlushBuilder(); _concat !.Add(value); } } }
public virtual QilNode?EndBuild(QilNode?result) { Debug.Assert(_inTheBuild, "StartBuild() wasn't called"); if (result == null) { // Special door to clean builder state in exception handlers } // All these variables will be positive for "false() and (. = position() + last())" // since QilPatternFactory eliminates the right operand of 'and' Debug.Assert(_predicateEnvironment.numFixupCurrent >= 0, "Context fixup error"); Debug.Assert(_predicateEnvironment.numFixupPosition >= 0, "Context fixup error"); Debug.Assert(_predicateEnvironment.numFixupLast >= 0, "Context fixup error"); _inTheBuild = false; return(result); }
public override QilNode?EndBuild(QilNode?result) { _depth--; Debug.Assert(0 <= _depth && _depth <= 1, "this shouldn't happen"); if (result == null) { // special door to clean builder state in exception handlers return(base.EndBuild(result)); } if (_depth == 0) { Debug.Assert(base.numFixupLast == 0); Debug.Assert(base.numFixupPosition == 0); result = _convertor.ConvertReletive2Absolute(result, base.fixupCurrent); result = base.EndBuild(result); } return(result); }
public QilNode Operator(XPathOperator op, QilNode?left, QilNode?right) { Debug.Assert(op == XPathOperator.Union); Debug.Assert(left != null); Debug.Assert(right != null); // It is important to not create nested lists here Debug.Assert(right.NodeType == QilNodeType.Filter, "LocationPathPattern must be compiled into a filter"); if (left.NodeType == QilNodeType.Sequence) { ((QilList)left).Add(right); return(left); } else { Debug.Assert(left.NodeType == QilNodeType.Filter, "LocationPathPattern must be compiled into a filter"); return(_f.Sequence(left, right)); } }
/// <summary> /// Analyze the content argument of the ElementCtor. Try to eliminate as many runtime checks as possible, /// both for the ElementCtor and for content constructors. /// </summary> public override QilNode?Analyze(QilNode?ndElem, QilNode?ndContent) { Debug.Assert(ndElem !.NodeType == QilNodeType.ElementCtor); this.parentInfo = XmlILConstructInfo.Write(ndElem); // Start by assuming that these properties are false (they default to true, but analyzer might be able to // prove they are really false). this.parentInfo.MightHaveNamespacesAfterAttributes = false; this.parentInfo.MightHaveAttributes = false; this.parentInfo.MightHaveDuplicateAttributes = false; // The element's namespace might need to be declared this.parentInfo.MightHaveNamespaces = !this.parentInfo.IsNamespaceInScope; // Clear list of duplicate attributes _dupAttrs.Clear(); return(base.Analyze(ndElem, ndContent)); }
private QilNode UnionOperator(XPathOperator op, QilNode?left, QilNode right) { Debug.Assert(op == XPathOperator.Union); if (left == null) { return(_f.EnsureNodeSet(right)); } left = _f.EnsureNodeSet(left); right = _f.EnsureNodeSet(right); if (left.NodeType == QilNodeType.Sequence) { ((QilList)left).Add(right); return(left); } else { return(_f.Union(left, right)); } }
//----------------------------------------------- // QilVisitor overrides //----------------------------------------------- /// <summary> /// Visit all children of "parent", replacing each child with a copy of each child. /// </summary> protected override QilNode Visit(QilNode oldNode) { QilNode?newNode = null; if (oldNode == null) { return(null !); } // ShallowClone any nodes which have not yet been cloned if (oldNode is QilReference) { // Reference nodes may have been cloned previously and put into scope newNode = FindClonedReference(oldNode); } newNode ??= oldNode.ShallowClone(_fac); return(base.Visit(newNode)); }
public QilNode Parse(XPathScanner scanner, IPatternBuilder ptrnBuilder) { Debug.Assert(_scanner == null && _ptrnBuilder == null); Debug.Assert(scanner != null && ptrnBuilder != null); QilNode?result = null; ptrnBuilder.StartBuild(); try { _scanner = scanner; _ptrnBuilder = ptrnBuilder; result = this.ParsePattern(); _scanner.CheckToken(LexKind.Eof); } finally { result = ptrnBuilder.EndBuild(result); #if DEBUG _ptrnBuilder = null; _scanner = null; #endif } return(result !); }
/// <summary> /// Perform analysis on the specified constructor and its content. Return the ndContent that was passed in, /// or a replacement. /// </summary> public virtual QilNode?Analyze(QilNode?ndConstr, QilNode?ndContent) { if (ndConstr == null) { // Root expression is analyzed this.parentInfo = null; this.xstates = PossibleXmlStates.WithinSequence; this.withinElem = false; Debug.Assert(ndContent != null); ndContent = AnalyzeContent(ndContent); } else { this.parentInfo = XmlILConstructInfo.Write(ndConstr); if (ndConstr.NodeType == QilNodeType.Function) { // Results of function should be pushed to writer this.parentInfo.ConstructMethod = XmlILConstructMethod.Writer; // Start with PossibleXmlStates.None and then add additional possible starting states PossibleXmlStates xstates = PossibleXmlStates.None; foreach (XmlILConstructInfo infoCaller in this.parentInfo.CallersInfo) { if (xstates == PossibleXmlStates.None) { xstates = infoCaller.InitialStates; } else if (xstates != infoCaller.InitialStates) { xstates = PossibleXmlStates.Any; } // Function's results are pushed to Writer, so make sure that Invoke nodes' construct methods match infoCaller.PushToWriterFirst = true; } this.parentInfo.InitialStates = xstates; } else { // Build a standalone tree, with this constructor as its root if (ndConstr.NodeType != QilNodeType.Choice) { this.parentInfo.InitialStates = this.parentInfo.FinalStates = PossibleXmlStates.WithinSequence; } // Don't stream Rtf; fully cache the Rtf and copy it into any containing tree in order to simplify XmlILVisitor.VisitRtfCtor if (ndConstr.NodeType != QilNodeType.RtfCtor) { this.parentInfo.ConstructMethod = XmlILConstructMethod.WriterThenIterator; } } // Set withinElem = true if analyzing element content this.withinElem = (ndConstr.NodeType == QilNodeType.ElementCtor); switch (ndConstr.NodeType) { case QilNodeType.DocumentCtor: this.xstates = PossibleXmlStates.WithinContent; break; case QilNodeType.ElementCtor: this.xstates = PossibleXmlStates.EnumAttrs; break; case QilNodeType.AttributeCtor: this.xstates = PossibleXmlStates.WithinAttr; break; case QilNodeType.NamespaceDecl: Debug.Assert(ndContent == null); break; case QilNodeType.TextCtor: Debug.Assert(ndContent == null); break; case QilNodeType.RawTextCtor: Debug.Assert(ndContent == null); break; case QilNodeType.CommentCtor: this.xstates = PossibleXmlStates.WithinComment; break; case QilNodeType.PICtor: this.xstates = PossibleXmlStates.WithinPI; break; case QilNodeType.XsltCopy: this.xstates = PossibleXmlStates.Any; break; case QilNodeType.XsltCopyOf: Debug.Assert(ndContent == null); break; case QilNodeType.Function: this.xstates = this.parentInfo.InitialStates; break; case QilNodeType.RtfCtor: this.xstates = PossibleXmlStates.WithinContent; break; case QilNodeType.Choice: this.xstates = PossibleXmlStates.Any; break; default: Debug.Fail($"{ndConstr.NodeType} is not handled by XmlILStateAnalyzer."); break; } if (ndContent != null) { ndContent = AnalyzeContent(ndContent); } if (ndConstr.NodeType == QilNodeType.Choice) { AnalyzeChoice((ndConstr as QilChoice) !, this.parentInfo); } // Since Function will never be another node's content, set its final states here if (ndConstr.NodeType == QilNodeType.Function) { this.parentInfo.FinalStates = this.xstates; } } return(ndContent); }
public QilParameter Parameter(QilNode?defaultValue, QilName?name, XmlQueryType t) { return(_f.Parameter(defaultValue, name, t)); }
//----------------------------------------------- // Constructor //----------------------------------------------- /// <summary> /// Construct a parameter /// </summary> public QilParameter(QilNodeType nodeType, QilNode?defaultValue, QilNode?name, XmlQueryType xmlType) : base(nodeType, defaultValue) { _name = name; this.xmlType = xmlType; }
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; } }
public QilIterator(QilNodeType nodeType, QilNode?binding) : base(nodeType) { Binding = binding; }
/// <summary> /// If a cloned reference is in scope, replace "oldNode". Otherwise, return "oldNode". /// </summary> protected override QilNode VisitReference(QilNode oldNode) { QilNode?newNode = FindClonedReference(oldNode); return(base.VisitReference(newNode == null ? oldNode : newNode)); }
protected virtual QilNode?NoReplace(QilNode?node) { return(node); }