Welcome to mirror list, hosted at ThFree Co, Russian Federation.

InvokeGenerator.cs « Xslt « Xsl « Xml « System « System.Data.SqlXml « referencesource « class « mcs - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 0f82b468ebc0678543c82c335c52693ef9f95857 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//------------------------------------------------------------------------------
// <copyright file="InvokeGenerator.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">[....]</owner>
//------------------------------------------------------------------------------

using System.Collections.Generic;
using System.Diagnostics;
using System.Xml.Xsl.Qil;

namespace System.Xml.Xsl.Xslt {
    using T = XmlQueryTypeFactory;

    /**
    InvokeGenerator is one of the trikest peaces here.
    ARGS:
         QilFunction func      -- Functions which should be invoked. Arguments of this function (formalArgs) are Let nodes
                                  anotated with names and default valies.
                                  Problem 1 is that default values can contain references to previouse args of this function.
                                  Problem 2 is that default values shouldn't contain fixup nodes.
         ArrayList actualArgs  -- Array of QilNodes anotated with names. When name of formalArg match name actualArg last one
                                  is used as invokeArg, otherwise formalArg's default value is cloned and used.
    **/

    internal class InvokeGenerator : QilCloneVisitor {
        private bool                debug;
        private Stack<QilIterator>  iterStack;

        private QilList             formalArgs;
        private QilList             invokeArgs;
        private int                 curArg;     // this.Clone() depends on this value

        private XsltQilFactory      fac;

        public InvokeGenerator(XsltQilFactory f, bool debug) : base(f.BaseFactory) {
            this.debug  = debug;
            this.fac    = f;
            this.iterStack = new Stack<QilIterator>();
        }

        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);
            }

            // Create Invoke node and wrap it with previous parameter declarations
            QilNode invoke = fac.Invoke(func, invokeArgs);
            while (iterStack.Count != 0)
                invoke = fac.Loop(iterStack.Pop(), invoke);

            return invoke;
        }

        private QilNode FindActualArg(QilParameter formalArg, IList<XslNode> actualArgs) {
            QilName argName = formalArg.Name;
            Debug.Assert(argName != null);
            foreach (XslNode actualArg in actualArgs) {
                if (actualArg.Name.Equals(argName)) {
                    return ((VarPar)actualArg).Value;
                }
            }
            return null;
        }

        // ------------------------------------ QilCloneVisitor -------------------------------------

        protected override QilNode VisitReference(QilNode n) {
            QilNode replacement = FindClonedReference(n);

            // If the reference is internal for the subtree being cloned, return it as is
            if (replacement != null) {
                return replacement;
            }

            // Replacement was not found, thus the reference is external for the subtree being cloned.
            // The case when it refers to one of previous arguments (xsl:param can refer to previous
            // xsl:param's) must be taken care of.
            for (int prevArg = 0; prevArg < curArg; prevArg++) {
                Debug.Assert(formalArgs[prevArg] != null, "formalArg must be in the list");
                Debug.Assert(invokeArgs[prevArg] != null, "This arg should be compiled already");

                // Is this a reference to prevArg?
                if (n == formalArgs[prevArg]) {
                    // If prevArg is a literal, just clone it
                    if (invokeArgs[prevArg] is QilLiteral) {
                        return invokeArgs[prevArg].ShallowClone(fac.BaseFactory);
                    }

                    // If prevArg is not an iterator, cache it in an iterator, and return it
                    if (!(invokeArgs[prevArg] is QilIterator)) {
                        QilIterator var = fac.BaseFactory.Let(invokeArgs[prevArg]);
                        iterStack.Push(var);
                        invokeArgs[prevArg] = var;
                    }
                    Debug.Assert(invokeArgs[prevArg] is QilIterator);
                    return invokeArgs[prevArg];
                }
            }

            // This is a truly external reference, return it as is
            return n;
        }

        protected override QilNode VisitFunction(QilFunction n) {
            // No need to change function references
            return n;
        }
    }
}