Пример #1
0
        private QilNode InvokeApplyFunction(StylesheetLevel sheet, QilName mode, IList<XslNode> actualArgs)
        {
            // Here we create function that has one argument for each with-param in apply-templates
            // We have actualArgs -- list of xsl:with-param(name, value)
            // From it we create:
            // invokeArgs -- values to use with QilInvoke
            // formalArgs -- list of iterators to use with QilFunction
            // actualArgs -- modify it to hold iterators (formalArgs) instead of values to ise in invoke generator inside function budy

            XslFlags flags;
            {
                if (!sheet.ModeFlags.TryGetValue(mode, out flags))
                {
                    flags = 0;
                }
                flags |= XslFlags.Current; // Due to recursive nature of Apply(Templates/Imports) we will need current node any way
            }
            actualArgs = AddRemoveImplicitArgs(actualArgs, flags);

            QilList invokeArgs = _f.ActualParameterList();
            QilFunction applyFunction = null;

            // Look at the list of all functions that have been already built.  If a suitable one is found, reuse it.
            List<QilFunction> functionsForMode;
            if (!sheet.ApplyFunctions.TryGetValue(mode, out functionsForMode))
            {
                functionsForMode = sheet.ApplyFunctions[mode] = new List<QilFunction>();
            }

            foreach (QilFunction func in functionsForMode)
            {
                if (FillupInvokeArgs(func.Arguments, actualArgs, /*ref*/invokeArgs))
                {
                    applyFunction = func;
                    break;
                }
            }

            // If a suitable function has not been found, create it
            if (applyFunction == null)
            {
                invokeArgs.Clear();
                // We wasn't able to find suitable function. Let's build new:
                // 1. Function arguments
                QilList formalArgs = _f.FormalParameterList();
                for (int i = 0; i < actualArgs.Count; i++)
                {
                    Debug.Assert(actualArgs[i].NodeType == XslNodeType.WithParam, "All Sorts was removed in CompileSorts()");
                    VarPar withParam = (VarPar)actualArgs[i];

                    // Add actual arg to 'invokeArgs' array. No need to clone it since it must be
                    // a literal or a reference.
                    invokeArgs.Add(withParam.Value);

                    // Create correspondent formal arg
                    QilParameter formalArg = _f.Parameter(i == 0 ? T.NodeNotRtf : withParam.Value.XmlType);
                    formalArg.Name = CloneName(withParam.Name);
                    formalArgs.Add(formalArg);

                    // Change actual arg value to formalArg for reuse in calling built-in templates rules
                    withParam.Value = formalArg;
                }

                // 2. Function header
                applyFunction = _f.Function(formalArgs,
                    _f.Boolean((flags & XslFlags.SideEffects) != 0),
                    T.NodeNotRtfS
                );
                string attMode = (mode.LocalName.Length == 0) ? string.Empty : " mode=\"" + mode.QualifiedName + '"';
                applyFunction.DebugName = (sheet is RootLevel ? "<xsl:apply-templates" : "<xsl:apply-imports") + attMode + '>';
                functionsForMode.Add(applyFunction);
                _functions.Add(applyFunction);

                // 3. Function body
                Debug.Assert(actualArgs[0].Name == _nameCurrent, "Caller should always pass $current as a first argument to apply-* calls.");
                QilIterator current = (QilIterator)formalArgs[0];

                // 3.1 Built-in templates:
                // 3.1.1 loop over content of current element
                QilLoop loopOnContent;
                {
                    QilIterator iChild = _f.For(_f.Content(current));
                    QilNode filter = _f.Filter(iChild, _f.IsType(iChild, T.Content));
                    filter.XmlType = T.ContentS;    // not attribute

                    LoopFocus curLoopSaved = _curLoop;
                    _curLoop.SetFocus(_f.For(filter));

                    /* Prepare actual arguments */
                    // At XSLT 1.0, if a built-in template rule is invoked with parameters, the parameters are not
                    // passed on to any templates invoked by the built-in rule. At XSLT 2.0, these parameters are
                    // passed through the built-in template rule unchanged.

                    // we can't just modify current/position/last of actualArgs in XSLT 2.0 as we tried before, 
                    // becuase flags for apply-import amy now be different then flags for apply-templates, so 
                    // we may need to add some space for additional position/last arguments
                    QilNode body = InvokeApplyFunction(_compiler.Root, mode, /*actualArgs:*/null);
                    if (IsDebug)
                    {
                        body = _f.Sequence(InvokeOnCurrentNodeChanged(), body);
                    }
                    loopOnContent = _curLoop.ConstructLoop(body);
                    _curLoop = curLoopSaved;
                }

                // 3.1.2 switch on type of current node
                QilTernary builtinTemplates = _f.BaseFactory.Conditional(_f.IsType(current, _elementOrDocumentType),
                    loopOnContent,
                    _f.Conditional(_f.IsType(current, _textOrAttributeType),
                        _f.TextCtor(_f.XPathNodeValue(current)),
                        _f.Sequence()
                    )
                );

                // 3.2 Stylesheet templates
                _matcherBuilder.CollectPatterns(sheet, mode);
                applyFunction.Definition = _matcherBuilder.BuildMatcher(current, actualArgs, /*otherwise:*/builtinTemplates);
            }
            return _f.Invoke(applyFunction, invokeArgs);
        }
Пример #2
0
        private QilGenerator(bool debug)
        {
            _scope = new CompilerScopeManager<QilIterator>();
            _outputScope = new OutputScopeManager();
            _prefixesInUse = new HybridDictionary();
            _f = new XsltQilFactory(new QilFactory(), debug);
            _xpathBuilder = new XPathBuilder((IXPathEnvironment)this);
            _xpathParser = new XPathParser<QilNode>();
            _ptrnBuilder = new XPathPatternBuilder((IXPathEnvironment)this);
            _ptrnParser = new XPathPatternParser();
            _refReplacer = new ReferenceReplacer(_f.BaseFactory);
            _invkGen = new InvokeGenerator(_f, debug);
            _matcherBuilder = new MatcherBuilder(_f, _refReplacer, _invkGen);
            _singlFocus = new SingletonFocus(_f);
            _funcFocus = new FunctionFocus();
            _curLoop = new LoopFocus(_f);
            _strConcat = new QilStrConcatenator(_f);
            _varHelper = new VariableHelper(_f);

            _elementOrDocumentType = T.DocumentOrElement;
            _textOrAttributeType = T.NodeChoice(XmlNodeKindFlags.Text | XmlNodeKindFlags.Attribute);

            _nameCurrent = _f.QName("current", XmlReservedNs.NsXslDebug);
            _namePosition = _f.QName("position", XmlReservedNs.NsXslDebug);
            _nameLast = _f.QName("last", XmlReservedNs.NsXslDebug);
            _nameNamespaces = _f.QName("namespaces", XmlReservedNs.NsXslDebug);
            _nameInit = _f.QName("init", XmlReservedNs.NsXslDebug);

            _formatterCnt = 0;
        }
Пример #3
0
        private void CompileSort(Sort sort, QilList keyList, ref LoopFocus parentLoop)
        {
            Debug.Assert(sort.NodeType == XslNodeType.Sort);
            QilNode select, select2, lang, order, caseOrder;
            bool fwdCompat;

            EnterScope(sort);
            fwdCompat = sort.ForwardsCompatible;

            select = CompileXPathExpression(sort.Select);

            if (sort.Lang != null || sort.DataType != null || sort.Order != null || sort.CaseOrder != null)
            {
                // Calculate these attributes in the context of the parent loop
                LoopFocus curLoopSaved = _curLoop;
                _curLoop = parentLoop;

                lang = CompileLangAttribute(sort.Lang, fwdCompat);

                CompileDataTypeAttribute(sort.DataType, fwdCompat, ref select, out select2);

                order = CompileOrderAttribute(
                    /*attName:  */  "order",
                    /*attValue: */  sort.Order,
                    /*value0:   */  "ascending",
                    /*value1:   */  "descending",
                    /*fwdCompat:*/  fwdCompat
                );

                caseOrder = CompileOrderAttribute(
                    /*attName:  */  "case-order",
                    /*attValue: */  sort.CaseOrder,
                    /*value0:   */  "lower-first",
                    /*value1:   */  "upper-first",
                    /*fwdCompat:*/  fwdCompat
                );

                // Restore loop context
                _curLoop = curLoopSaved;
            }
            else
            {
                select = _f.ConvertToString(select);
                select2 = lang = order = caseOrder = null;
            }

            _strConcat.Reset();
            _strConcat.Append(XmlReservedNs.NsCollationBase);
            _strConcat.Append('/');
            _strConcat.Append(lang);

            char separator = '?';
            if (order != null)
            {
                _strConcat.Append(separator);
                _strConcat.Append("descendingOrder=");
                _strConcat.Append(order);
                separator = '&';
            }
            if (caseOrder != null)
            {
                _strConcat.Append(separator);
                _strConcat.Append("upperFirst=");
                _strConcat.Append(caseOrder);
                separator = '&';
            }

            QilNode collation = _strConcat.ToQil();

            QilSortKey result = _f.SortKey(select, collation);
            // Line information is not copied
            keyList.Add(result);

            if (select2 != null)
            {
                result = _f.SortKey(select2, collation.DeepClone(_f.BaseFactory));
                // Line information is not copied
                keyList.Add(result);
            }

            ExitScope();
        }
Пример #4
0
        // REVIEW: Can we handle both sort's and with-param's in the document order?
        // CompileSorts() creates helper variables in varHelper
        private QilNode CompileSorts(IList<XslNode> content, ref LoopFocus parentLoop)
        {
            QilList keyList = _f.BaseFactory.SortKeyList();

            int i = 0;

            while (i < content.Count)
            {
                Sort sort = content[i] as Sort;
                if (sort != null)
                {
                    CompileSort(sort, keyList, ref parentLoop);
                    content.RemoveAt(i);
                }
                else
                {
                    i++;
                }
            }

            if (keyList.Count == 0)
                return null;

            return keyList;
        }
Пример #5
0
        private QilNode CompileApplyTemplates(XslNodeEx node)
        {
            QilNode result;
            IList<XslNode> content = node.Content;

            // Calculate select expression
            int varScope = _varHelper.StartVariables();

            QilIterator select = _f.Let(CompileNodeSetExpression(node.Select));
            _varHelper.AddVariable(select);

            // Compile with-param's, they must be calculated outside the loop and
            // if they are neither constant nor reference we need to cache them in Let's
            for (int i = 0; i < content.Count; i++)
            {
                VarPar withParam = content[i] as VarPar;
                if (withParam != null)
                {
                    Debug.Assert(withParam.NodeType == XslNodeType.WithParam);
                    CompileWithParam(withParam);
                    QilNode val = withParam.Value;
                    if (IsDebug || !(val is QilIterator || val is QilLiteral))
                    {
                        QilIterator let = _f.Let(val);
                        let.DebugName = _f.QName("with-param " + withParam.Name.QualifiedName, XmlReservedNs.NsXslDebug).ToString();
                        _varHelper.AddVariable(let);
                        withParam.Value = let;
                    }
                }
            }

            // Push new loop frame on the stack
            LoopFocus curLoopSaved = _curLoop;
            QilIterator it = _f.For(select);
            _curLoop.SetFocus(it);

            // Compile sort keys and body
            _curLoop.Sort(CompileSorts(content, ref curLoopSaved));

            result = GenerateApply(_compiler.Root, node);

            result = WrapLoopBody(node.ElemNameLi, result, node.EndTagLi);
            result = AddCurrentPositionLast(result);
            result = _curLoop.ConstructLoop(result);

            // Pop loop frame
            _curLoop = curLoopSaved;

            result = _varHelper.FinishVariables(result, varScope);
            return result;
        }
Пример #6
0
        private QilNode CompileForEach(XslNodeEx node)
        {
            QilNode result;
            IList<XslNode> content = node.Content;

            // Push new loop frame on the stack
            LoopFocus curLoopSaved = _curLoop;
            QilIterator it = _f.For(CompileNodeSetExpression(node.Select));
            _curLoop.SetFocus(it);

            // Compile sort keys and body
            int varScope = _varHelper.StartVariables();
            _curLoop.Sort(CompileSorts(content, ref curLoopSaved));
            result = CompileInstructions(content);
            result = WrapLoopBody(node.ElemNameLi, result, node.EndTagLi);
            result = AddCurrentPositionLast(result);
            result = _curLoop.ConstructLoop(result);
            result = _varHelper.FinishVariables(result, varScope);

            // Pop loop frame
            _curLoop = curLoopSaved;
            return result;
        }
        private QilNode InvokeApplyFunction(Stylesheet sheet, QilName mode, IList<XslNode> actualArgs) {
            // Here we create function that has one argument for each with-param in apply-templates
            // We have actualArgs -- list of xsl:with-param(name, value)
            // From it we create:
            // invokeArgs -- values to use with QilInvoke
            // formalArgs -- list of iterators to use with QilFunction
            // actualArgs -- modify it to hold iterators (formalArgs) instead of values to ise in invoke generator inside function budy

            // Special treatment for current/position/last
            XslFlags flags;
            if (! compiler.ModeFlags.TryGetValue(mode, out flags)) {
                flags = 0;
            }
            if (IsDebug) {
                flags = XslFlags.FullFocus;
            }

            flags |= XslFlags.Current; // Due to recursive nature of Apply(Templates/Imports) we will need current node any way
            Debug.Assert(actualArgs[0].Name == nameCurrent, "Caller should always pass $current as a first argument to apply-* calls.");

            QilList     invokeArgs = f.ActualParameterList();
            QilFunction applyFunction = null;

            // Look at the list of all functions that have been already built.  If a suitable one is found, reuse it.
            Dictionary<QilName, List<QilFunction>> funcTable = (
                sheet == null ? compiler.ApplyTemplatesFunctions : sheet.ApplyImportsFunctions
            );

            List<QilFunction> functionsForMode;
            if (!funcTable.TryGetValue(mode, out functionsForMode)) {
                functionsForMode = funcTable[mode] = new List<QilFunction>();
            }

            foreach (QilFunction func in functionsForMode) {
                if (FillupInvokeArgs(func.Arguments, actualArgs, /*ref*/invokeArgs)) {
                    applyFunction = func;
                    break;
                }
            }

            // If a suitable function has not been found, create it
            if (applyFunction == null) {
                invokeArgs.Clear();
                // We wasn't able to find suitable function. Let's build new:
                // 1. Function arguments
                QilList formalArgs = f.FormalParameterList();
                for (int i = 0; i < actualArgs.Count; i++) {
                    Debug.Assert(actualArgs[i].NodeType == XslNodeType.WithParam, "All Sorts was removed in CompileSorts()");
                    VarPar withParam = (VarPar)actualArgs[i] ;

                    // Add actual arg to 'invokeArgs' array. No need to clone it since it must be
                    // a literal or a reference.
                    invokeArgs.Add(withParam.Value);

                    // Create correspondent formal arg
                    QilParameter formalArg = f.Parameter(i == 0 ? T.NodeNotRtf : withParam.Value.XmlType);
                    formalArg.Name = CloneName(withParam.Name);
                    formalArgs.Add(formalArg);

                    // Change actual arg value to formalArg for reuse in calling built-in templates rules
                    withParam.Value = formalArg;
                }

                // 2. Function header
                applyFunction = f.Function(formalArgs, f.False(), T.NodeNotRtfS);
                string attMode = (mode.LocalName.Length == 0) ? string.Empty : " mode=\"" + mode.QualifiedName + '"';
                applyFunction.DebugName = (sheet == null ? "<xsl:apply-templates" : "<xsl:apply-imports") + attMode + '>';
                functionsForMode.Add(applyFunction);
                this.functions.Add(applyFunction);

                // 3. Function body
                QilIterator current = (QilIterator)formalArgs[0];

                // 3.1 Built-in templates
                QilTernary builtinTemplates = f.BaseFactory.Conditional(f.IsType(current, elementOrDocumentType),
                    // This will be fixed up later
                    f.BaseFactory.Nop(f.BaseFactory.Unknown(T.NodeNotRtfS)),
                    f.Conditional(f.IsType(current, textOrAttributeType),
                        f.TextCtor(f.XPathNodeValue(current)),
                        f.Sequence()
                    )
                );

                // 3.2 Stylesheet templates
                matcherBuilder.CollectPatterns(sheet ?? compiler.PrincipalStylesheet, mode, /*applyImports:*/sheet != null);
                applyFunction.Definition = matcherBuilder.BuildMatcher(current, actualArgs, /*otherwise:*/builtinTemplates);

                // 3.3 Fix up the loop in built-in templates
                QilLoop loopOnContent; {
                    QilIterator iChild = f.For(f.Content(current));
                    QilNode filter = f.Filter(iChild, f.IsType(iChild, T.Content));
                    filter.XmlType = T.ContentS;    // not attribute

                    LoopFocus curLoopSaved = curLoop;
                    curLoop.SetFocus(f.For(filter));
                    if ((flags & XslFlags.Last) != 0) {
                        // Mark that we need last argument
                        curLoop.GetLast();
                    }

                    /* Prepare actual arguments */ {
                        // At XSLT 1.0, if a built-in template rule is invoked with parameters, the parameters are not
                        // passed on to any templates invoked by the built-in rule. At XSLT 2.0, these parameters are
                        // passed through the built-in template rule unchanged.
                        const bool Xslt10Rules = true;
                        if (Xslt10Rules) {
                            List<XslNode> newActualArgs = new List<XslNode>(3);
                            int argNum = 0;
                            if ((flags & XslFlags.Current ) != 0) { newActualArgs.Add(actualArgs[argNum ++]); }
                            if ((flags & XslFlags.Position) != 0) { newActualArgs.Add(actualArgs[argNum ++]); }
                            if ((flags & XslFlags.Last    ) != 0) { newActualArgs.Add(actualArgs[argNum ++]); }
                            actualArgs = newActualArgs;
                        }

                        // Fix values of current, position, and last
                        {
                            int argNum = 0;
                            if ((flags & XslFlags.Current ) != 0) { ((VarPar)actualArgs[argNum ++]).Value = GetCurrentNode    (); }
                            if ((flags & XslFlags.Position) != 0) { ((VarPar)actualArgs[argNum ++]).Value = GetCurrentPosition(); }
                            if ((flags & XslFlags.Last    ) != 0) { ((VarPar)actualArgs[argNum ++]).Value = GetLastPosition   (); }
                        }
                    }
                    loopOnContent = curLoop.ConstructLoop(InvokeApplyFunction(/*sheet:*/null, mode, actualArgs));
                    curLoop = curLoopSaved;
                }

                Debug.Assert(builtinTemplates.Center.NodeType == QilNodeType.Nop);
                ((QilUnary)builtinTemplates.Center).Child = loopOnContent;
            }
            return f.Invoke(applyFunction, invokeArgs);
        }