The Labs \ Source Viewer \ SSCLI \ System.Xml.Xsl.Xslt \ InvokeGenerator

  1. //------------------------------------------------------------------------------
  2. // <copyright file="InvokeGenerator.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System.Collections.Generic;
  16. using System.Diagnostics;
  17. using System.Xml.Xsl.Qil;
  18. namespace System.Xml.Xsl.Xslt
  19. {
  20.     using T = XmlQueryTypeFactory;
  21.    
  22. /**
  23.     InvokeGenerator is one of the trikest peaces here.
  24.     ARGS:
  25.         QilFunction func      -- Functions which should be invoked. Arguments of this function (formalArgs) are Let nodes
  26.                                   anotated with names and default valies.
  27.                                   Problem 1 is that default values can contain references to previouse args of this function.
  28.                                   Problem 2 is that default values shouldn't contain fixup nodes.
  29.         ArrayList actualArgs  -- Array of QilNodes anotated with names. When name of formalArg match name actualArg last one
  30.                                   is used as invokeArg, otherwise formalArg's default value is cloned and used.
  31.     **/   
  32.    
  33.     internal class InvokeGenerator : QilCloneVisitor
  34.     {
  35.         private bool debug;
  36.         private Stack<QilIterator> iterStack;
  37.        
  38.         private QilList formalArgs;
  39.         private QilList invokeArgs;
  40.         private int curArg;
  41.         // this.Clone() depends on this value
  42.         private XsltQilFactory fac;
  43.        
  44.         public InvokeGenerator(XsltQilFactory f, bool debug) : base(f.BaseFactory)
  45.         {
  46.             this.debug = debug;
  47.             this.fac = f;
  48.             this.iterStack = new Stack<QilIterator>();
  49.         }
  50.        
  51.         public QilNode GenerateInvoke(QilFunction func, IList<XslNode> actualArgs)
  52.         {
  53.             iterStack.Clear();
  54.             formalArgs = func.Arguments;
  55.             invokeArgs = fac.ActualParameterList();
  56.            
  57.             // curArg is an instance variable used in Clone() method
  58.             for (curArg = 0; curArg < formalArgs.Count; curArg++) {
  59.                 // Find actual value for a given formal arg
  60.                 QilParameter formalArg = (QilParameter)formalArgs[curArg];
  61.                 QilNode invokeArg = FindActualArg(formalArg, actualArgs);
  62.                
  63.                 // If actual value was not specified, use the default value and copy its debug comment
  64.                 if (invokeArg == null) {
  65.                     if (debug) {
  66.                         if (formalArg.Name.NamespaceUri == XmlReservedNs.NsXslDebug) {
  67.                             Debug.Assert(formalArg.Name.LocalName == "namespaces", "Cur,Pos,Last don't have default values and should be always added to by caller in AddImplicitArgs()");
  68.                             Debug.Assert(formalArg.DefaultValue != null, "PrecompileProtoTemplatesHeaders() set it");
  69.                             invokeArg = Clone(formalArg.DefaultValue);
  70.                         }
  71.                         else {
  72.                             invokeArg = fac.DefaultValueMarker();
  73.                         }
  74.                     }
  75.                     else {
  76.                         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.");
  77.                         invokeArg = Clone(formalArg.DefaultValue);
  78.                     }
  79.                 }
  80.                
  81.                 XmlQueryType formalType = formalArg.XmlType;
  82.                 XmlQueryType invokeType = invokeArg.XmlType;
  83.                
  84.                 // Possible arg types: anyType, node-set, string, boolean, and number
  85.                 fac.CheckXsltType(formalArg);
  86.                 fac.CheckXsltType(invokeArg);
  87.                
  88.                 if (!invokeType.IsSubtypeOf(formalType)) {
  89.                     // This may occur only if inferred type of invokeArg is XslFlags.None
  90.                     Debug.Assert(invokeType == T.ItemS, "Actual argument type is not a subtype of formal argument type");
  91.                     invokeArg = fac.TypeAssert(invokeArg, formalType);
  92.                 }
  93.                
  94.                 invokeArgs.Add(invokeArg);
  95.             }
  96.            
  97.             // Create Invoke node and wrap it with previous parameter declarations
  98.             QilNode invoke = fac.Invoke(func, invokeArgs);
  99.             while (iterStack.Count != 0)
  100.                 invoke = fac.Loop(iterStack.Pop(), invoke);
  101.            
  102.             return invoke;
  103.         }
  104.        
  105.         private QilNode FindActualArg(QilParameter formalArg, IList<XslNode> actualArgs)
  106.         {
  107.             QilName argName = formalArg.Name;
  108.             Debug.Assert(argName != null);
  109.             foreach (XslNode actualArg in actualArgs) {
  110.                 if (actualArg.Name.Equals(argName)) {
  111.                     return ((VarPar)actualArg).Value;
  112.                 }
  113.             }
  114.             return null;
  115.         }
  116.        
  117.         // ------------------------------------ QilCloneVisitor -------------------------------------
  118.        
  119.         protected override QilNode VisitReference(QilNode n)
  120.         {
  121.             QilNode replacement = FindClonedReference(n);
  122.            
  123.             // If the reference is internal for the subtree being cloned, return it as is
  124.             if (replacement != null) {
  125.                 return replacement;
  126.             }
  127.            
  128.             // Replacement was not found, thus the reference is external for the subtree being cloned.
  129.             // The case when it refers to one of previous arguments (xsl:param can refer to previous
  130.             // xsl:param's) must be taken care of.
  131.             for (int prevArg = 0; prevArg < curArg; prevArg++) {
  132.                 Debug.Assert(formalArgs[prevArg] != null, "formalArg must be in the list");
  133.                 Debug.Assert(invokeArgs[prevArg] != null, "This arg should be compiled already");
  134.                
  135.                 // Is this a reference to prevArg?
  136.                 if (n == formalArgs[prevArg]) {
  137.                     // If prevArg is a literal, just clone it
  138.                     if (invokeArgs[prevArg] is QilLiteral) {
  139.                         return invokeArgs[prevArg].ShallowClone(fac.BaseFactory);
  140.                     }
  141.                    
  142.                     // If prevArg is not an iterator, cache it in an iterator, and return it
  143.                     if (!(invokeArgs[prevArg] is QilIterator)) {
  144.                         QilIterator var = fac.BaseFactory.Let(invokeArgs[prevArg]);
  145.                         iterStack.Push(var);
  146.                         invokeArgs[prevArg] = var;
  147.                     }
  148.                     Debug.Assert(invokeArgs[prevArg] is QilIterator);
  149.                     return invokeArgs[prevArg];
  150.                 }
  151.             }
  152.            
  153.             // This is a truly external reference, return it as is
  154.             return n;
  155.         }
  156.        
  157.         protected override QilNode VisitFunction(QilFunction n)
  158.         {
  159.             // No need to change function references
  160.             return n;
  161.         }
  162.     }
  163. }

Developer Fusion