<xsl:stylesheet xmlns:src="http://www.sdml.info/srcML/src" xmlns:cpp="http://www.sdml.info/srcML/cpp" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:saxon="http://saxon.sf.net/" xmlns:xd="http://www.pnp-software.com/XSLTdoc" xmlns:util="http://www.pnp-software.com/util" xmlns:ax="http://control.ee.ethz.ch/XWeaver/AspectX" xmlns:xslt="http://xslt" version="2.0" exclude-result-prefixes="xsl">
  
  <xd:doc type="stylesheet">
    
<xd:short>AspectX Compiler</xd:short>
    
<xd:detail>This XSL stylesheet compiles a program written in 
    
<a href="../AspectX/LanguageGuide.html">AspectX</a> into an XSL stylesheet.
    The resulting stylesheet is able to add advice elements to
    
<a href="http://www.sdml.info/projects/srcml/">srcML</a> base
    code. See templates documentation (especially the root template) for a more detailed description.
</xd:detail>
    
<xd:cvsId>$Id: axc.xsl 138 2005-07-27 09:14:07Z ibirrer $</xd:cvsId>
    
<xd:author>ibirrer</xd:author>
    
<xd:copyright>2005, P&amp;P Software GmbH</xd:copyright>
  
</xd:doc>

  
  
<!-- The output is an XSLT Stylesheet in XML -->
  
<xsl:output method="xml" indent="no" />
  
  
<xsl:preserve-space elements="xsl:text" />
  
<xsl:strip-space elements="*" />
  
  
<!-- Inlcudes -->
  
<xsl:include href="util.xsl" />
  
  
<!--
    The result of the transformation with this stylesheet is again a stylesheet. Whenever
    an element in this stylesheet is used with the prefix 'xslt', it is copied to the
    resulting document as an xsl element.
  
-->
  
<xsl:namespace-alias stylesheet-prefix="xslt" result-prefix="xsl" />
  
  
<!--
          ==================================
           ResolveIncludes templates
          ==================================
         
-->
  
  <xd:doc>
    
<xd:short>Main Root template</xd:short>
    
<xd:detail>
      Resolves any includes and hands the resulting file to the templates with mode 
<code>compiler</code>.
      Resolving includes is done by templates with mode 
<code>resolveIncludes</code>.
    
</xd:detail>
  
</xd:doc>

  
<xsl:template match="/">
    
<!-- Resolve includes -->
    
<xsl:variable name="resolvedAspect">
      
<xsl:apply-templates select="." mode="resolveIncludes" />
    
</xsl:variable>
    
<xsl:apply-templates select="$resolvedAspect" mode="compiler" />
  
</xsl:template>
  
  
  <xd:doc>
    Default copy template to resolve Includes in aspects.
  
</xd:doc>

  
<xsl:template match="*" mode="resolveIncludes">
    
<xsl:copy>
      
<xsl:copy-of select="@*" />
      
<xsl:apply-templates mode="resolveIncludes" />
    
</xsl:copy>
  
</xsl:template>
  
  
  <xd:doc>
    Resolve includes. Replaces include elements by all contents (pointcuts, advices) of the aspect it refers to.
  
</xd:doc>

  
<xsl:template match="ax:include" mode="resolveIncludes">
    
<xsl:apply-templates select="document(@href)/ax:aspect/*" mode="resolveIncludes" />
  
</xsl:template>
  
  
  <xd:doc>
    Add apspect attribute to named pointcut elements and pointcutRef elements. If an aspect attribute already exists 
    it is not replaces.
  
</xd:doc>

  
<xsl:template match="ax:pointcut[@name] | ax:pointcutRef" mode="resolveIncludes">
    
<xsl:copy>
      
<xsl:copy-of select="@*" />
      
<xsl:if test="not(@aspect)">
        
<xsl:attribute name="aspect" select="/ax:aspect/@name" />
      
</xsl:if>
      
<xsl:apply-templates mode="resolveIncludes" />
    
</xsl:copy>
  
</xsl:template>
  
  
<!--
          ==================================
           Compiler templates
          ==================================
         
-->
  
  <xd:doc>
    
<xd:short>
      Builds the general structure of the locator stylesheet.
    
</xd:short>
    
<xd:detail>
    Procedure:
    
<ul>
      
<li>
        1. Find all anonymous pointcut and pointcutRef elements used for advices. 
        These are all pointcut and pointcutRef elements definded as a direct child 
        of an advice. Descendants of these are not inlcuded, neither are named pointcuts.
      
</li>
      
<li>2. Group the elements found by the type attribute. This means that a group consists of
      pointcut or pointcutRef elements which have the same value for the type attribute. Then iterate through the
      groups (Each group is processed once).
</li>
      
<ul>
        
<li>2.1 Build an unnamed template for each group. The match attribute value is set to the common type 
        attribute value of the group.
</li>
        
<li>2.2 Iterate through all distinct pointcutRef (a pointcutRef element is equal 
        with another if their ref attribute value is equal) elements and all pointcut elements 
        in the group.
</li>
        
<ul>
          
<li>2.2.1 Build an if statement for each group</li>
          
<li>2.2.2 Generate the XPath expression from the pointcut (Using the first pointcut in the group). 
          This uses templates with mode 
<code>pointcutXPath</code>. PoinctutRef elements are translated to 
          their corresponding pointcut element in a template with mode 
<code>pointcutXPath</code>.</li>
          
<li>2.2.3 Find all advices which use any of the pointcuts or pointcutRef's in the group and copy them. 
          (These are the advices which are direct parents of a pointcut or pointcutRef)
</li>
        
</ul>
      
</ul>
    
</ul>
    A pointcut type always directly refers to a specific srcML element. Therefore a template generated for a pointuct of type 
<code>src:class</code>
    is processed for each 
<code>src:class</code> element in the srcML base code. Because all <code>src:class</code> elements are processed 
    by this template the template logic needs to decide if an advice should be added to a specific 
<code>src:class</code> element. This is achieved
    by generating several 
<code>xsl:if</code> clauses inside the template. Each <code>xsl:if</code> tests if a pointcut matches the srcML element currently
    processed. Note that 
<code>xsl:choose</code>
    would not work for this purpose as it would only allow one pointcut to match one srcML element but of course there can be several pointcuts that match one 
    srcML element (=pointcut type). Generating the test attribute of the 
<code>xsl:if</code> clause is done by several templates with the mode pointcutXPath (See also 
    stylesheets in compilerRules/restrictions).
    
</xd:detail>
  
</xd:doc>

  
<xsl:template match="/" mode="compiler">
    
<xslt:stylesheet version="2.0">
      
<xslt:include href="util.xsl" />
      
      
<xslt:preserve-space elements="*" />

      
<!-- Add default copy template-->
      
<xslt:template match="*">
        
<xslt:copy>
          
<xslt:copy-of select="@*" />
          
<xslt:apply-templates />
        
</xslt:copy>
      
</xslt:template>

      
<!--
              (Step 1 & 2, see template documentation above)
      
-->
      
<xsl:for-each-group select="ax:aspect/ax:advice/ax:pointcut | ax:aspect/ax:advice/ax:pointcutRef" group-by="@type">
        
<xsl:comment><xsl:value-of select="@type" /></xsl:comment>
        
<!--
                (Step 2.1, see template documentation above)
        
-->
        
<xslt:template match="{@type}">
          
<!-- Add variable declarations (Dollar variables) -->
          
<xsl:variable name="srcMLElement">
            
<xsl:element name="{@type}" />
          
</xsl:variable>
          
<xsl:apply-templates select="$srcMLElement" mode="commonVariableDeclarations" />
          
<xsl:apply-templates select="$srcMLElement" mode="variableDeclarations" />
          
          
<xslt:copy>
            
<xslt:copy-of select="@*" />
            
<!--
                    (Step 2.2, see template documentation above)
                    The generate-id function is used to express that all poinctcuts are different to each other, what
                    results in iterating through all pointcut elements.
            
-->
            
<xsl:for-each-group select="current-group()" group-by="concat(@ref, generate-id(self::ax:pointcut))">
              
<xsl:comment><xsl:value-of select="concat('  ', name(),' ', @type, ', ' , @ref )" /></xsl:comment>
              
<!--
                      (Step 2.2.1, see template documentation above)
              
-->
              
<xslt:if>
                
<xsl:attribute name="test">
                  
<!--
                          (Step 2.2.2, see template documentation above)
                  
-->
                        
<xsl:variable name="xpath">
                          
<xsl:apply-templates select="current-group()[1]" mode="pointcutXPath" />
                  
</xsl:variable>
                  
<!-- 
                    Replace empty XPath expressions by the true() statement. This
                    needs to be done because an if statement with an empty test attribute value
                    generates a XSLT syntax error.
                   
-->
                  
<xsl:choose>
                          
<xsl:when test="normalize-space($xpath) != ''">
                                  
<xsl:value-of select="$xpath" />
                          
</xsl:when>
                          
<xsl:otherwise>
                                  
<xsl:text>true()</xsl:text>
                          
</xsl:otherwise>
                  
</xsl:choose>
                
</xsl:attribute>
                
<!--
                  Copy the advices (There can be several advices referring to one pointcut)
                  Dollar variables used in codeModifiers are replaced by the apporpriate <xsl:value ... /> element.
                
-->
                
<!--
                  (Step 2.2.3, see template documentation above)
                
-->
                
<xsl:for-each select="current-group()">
                  
<xsl:comment><xsl:value-of select="concat('    ', name(parent::ax:advice),' ', parent::ax:advice/@type, ', ' , parent::ax:advice/@name )" /></xsl:comment>
                  
<ax:advice>
                          
<xsl:attribute name="line" select="'{saxon:line-number() - 1}'" />
                    
<xsl:copy-of select="parent::ax:advice/@*" />
                    
<xsl:apply-templates select="parent::ax:advice/node()" mode="replaceDollarVariables" />
                  
</ax:advice>
                
</xsl:for-each>
              
</xslt:if>
            
</xsl:for-each-group>
            
<xslt:apply-templates />
          
</xslt:copy>
        
</xslt:template>
      
</xsl:for-each-group>
    
</xslt:stylesheet>
  
</xsl:template>
  
 

  
<!--
          ==================================
           PointcutXPath templates
          ==================================
         
-->
         
         
  <xd:doc>
    element: ax:pointcut
    parent: none
    constraint: none or empty
  
</xd:doc>

  
<xsl:template match="ax:pointcut[not(parent::ax:restriction) and ( not(@constraint) or string-length(replace(@constraint, '^[ \t]+|[ \t]+$', '')) = 0 )]" mode="pointcutXPath">
    
<xsl:choose>
      
<xsl:when test="*[not(self::ax:description)]">
        
<!-- If pointcut contains subelements, evaluate them -->
        
<xsl:apply-templates mode="pointcutXPath" />
      
</xsl:when>
      
<xsl:otherwise>
        
<xsl:text>true()</xsl:text>
      
</xsl:otherwise>
    
</xsl:choose>
          
  
</xsl:template>
         
  
  <xd:doc>
    element: ax:pointcut
    parent: none
    constraint: yes (not empty)
  
</xd:doc>

  
<xsl:template match="ax:pointcut[not(parent::ax:restriction) and @constraint and string-length(replace(@constraint, '^[ \t]+|[ \t]+$', '')) != 0]" mode="pointcutXPath">
    
<!-- Add constraint -->
    
<xsl:value-of select="concat('(', @constraint, ')')" />
    
<!-- If there is a subelement, apply templates for it -->
    
<xsl:choose>
      
<xsl:when test="*[not(self::ax:description)]">
        
<!-- If pointcut contains subelements, evaluate them and add them to the constraint with the 'and' operator -->
        
<xsl:text> and (</xsl:text><xsl:apply-templates mode="pointcutXPath" /><xsl:text>)</xsl:text>
      
</xsl:when>
    
</xsl:choose>
  
</xsl:template>
  
  
  <xd:doc>Empty template to exclude description and text elements from the XPath creation for pointcuts.</xd:doc>

  
<xsl:template match="ax:description | text()" mode="pointcutXPath" />
  
  
  <xd:doc>
    element: ax:pointcut
    parent: yes
    constraint: none or empty
  
</xd:doc>

  
<xsl:template match="ax:pointcut[parent::ax:restriction and ( not(@constraint) or string-length(replace(@constraint, '^[ \t]+|[ \t]+$', '')) = 0 )]" mode="pointcutXPath">
          
<!-- Print the type of the pointcut -->
          
<xsl:value-of select="@type" />
          
<xsl:choose>
      
<xsl:when test="*[not(self::ax:description)]">
        
<!-- If pointcut contains subelements, evaluate them -->
        
<xsl:text>[</xsl:text><xsl:apply-templates mode="pointcutXPath" /><xsl:text>]</xsl:text>
      
</xsl:when>
    
</xsl:choose>
  
</xsl:template>
  
  
  <xd:doc>
    element: ax:pointcut
    parent: yes
    constraint: yes (not empty)
  
</xd:doc>

  
<xsl:template match="ax:pointcut[parent::ax:restriction and @constraint and string-length(replace(@constraint, '^[ \t]+|[ \t]+$', '')) != 0]" mode="pointcutXPath">
          
<!-- Print the type of the pointcut -->
          
<xsl:value-of select="@type" />
          
<xsl:text>[(</xsl:text><xsl:value-of select="@constraint" /><xsl:text>)</xsl:text>
          
<xsl:choose>
      
<xsl:when test="*[not(self::ax:description)]">
        
<!-- If pointcut contains subelements, evaluate them and add them to the constraint with the 'and' operator -->
        
<xsl:text> and (</xsl:text><xsl:apply-templates select="*[not(self::ax:description)]" mode="pointcutXPath" /><xsl:text>)</xsl:text>
      
</xsl:when>
    
</xsl:choose>
          
<xsl:text>]</xsl:text>
  
</xsl:template>
  
  
  
  <xd:doc>
    A reference to a pointcut is resolved to the corresponding 
    pointcut. This pointcut is then again applied to the templates 
    taking a pointcut to generate the XPath expression. 
    In this case the parent element is a restriction and therefore
    the type of the pointcut needs to be output.
  
</xd:doc>

  
<xsl:template match="ax:pointcutRef[parent::ax:restriction]" mode="pointcutXPath">
    
<xsl:variable name="aspectRef" select="@aspect" />
    
<xsl:variable name="pointcutRef" select="@ref" /> 
    
<xsl:variable name="pointcut" select="/ax:aspect/ax:pointcut[@name=$pointcutRef and @aspect = $aspectRef]" />
    
<xsl:if test="count($pointcut) &lt;=0">
      
<xsl:message terminate="yes">[ERROR] Cannot find pointcut with name <xsl:value-of select="@ref" /> in aspect <xsl:value-of select="@aspect" />.</xsl:message>
    
</xsl:if>
          
<xsl:value-of select="@type" />
          
<xsl:text>[</xsl:text><xsl:apply-templates select="$pointcut" mode="pointcutXPath" /><xsl:text>]</xsl:text>
  
</xsl:template>
  
  
  <xd:doc>
    A reference to a pointcut is resolved to the corresponding 
    pointcut. This pointcut is then again applied to the templates 
    taking a pointcut to generate the XPath expression.
  
</xd:doc>

  
<xsl:template match="ax:pointcutRef[not(parent::ax:restriction)]" mode="pointcutXPath">
    
<xsl:variable name="aspectRef" select="@aspect" />
    
<xsl:variable name="pointcutRef" select="@ref" /> 
      
    
<xsl:variable name="pointcut" select="/ax:aspect/ax:pointcut[@name=$pointcutRef and @aspect = $aspectRef]" />
    
<xsl:if test="count($pointcut) &lt;=0">
      
<xsl:message terminate="yes">[ERROR] Cannot find pointcut with name <xsl:value-of select="@ref" /> in aspect <xsl:value-of select="@aspect" />.</xsl:message>
    
</xsl:if>
    
<xsl:apply-templates select="$pointcut" mode="pointcutXPath" />
  
</xsl:template>
  
  
  <xd:doc>
    Template rule for not
  
</xd:doc>

  
<xsl:template match="ax:not" mode="pointcutXPath">
    
<xsl:text>not( </xsl:text>
    
<xsl:variable name="xpath">
        
<xsl:apply-templates select="*" mode="pointcutXPath" />
      
</xsl:variable>
      
<xsl:choose>
        
<xsl:when test="normalize-space($xpath) != ''">
          
<xsl:text>(</xsl:text><xsl:value-of select="$xpath" /><xsl:text>)</xsl:text>
        
</xsl:when>
        
<xsl:otherwise>
          
<xsl:text>(true())</xsl:text>
        
</xsl:otherwise>
      
</xsl:choose>
    
<xsl:text> )</xsl:text>
  
</xsl:template>
  
  
  <xd:doc>
    Template rule for and
  
</xd:doc>

  
<xsl:template match="ax:and" mode="pointcutXPath">
    
<xsl:for-each select="*">
            
<xsl:if test="position() &gt; 1">
        
<xsl:text> and </xsl:text>
      
</xsl:if>
            
<xsl:variable name="xpath">
        
<xsl:apply-templates select="." mode="pointcutXPath" />
      
</xsl:variable>
      
<xsl:choose>
        
<xsl:when test="normalize-space($xpath) != ''">
          
<xsl:text>(</xsl:text><xsl:value-of select="$xpath" /><xsl:text>)</xsl:text>
        
</xsl:when>
        
<xsl:otherwise>
          
<xsl:text>(true())</xsl:text>
        
</xsl:otherwise>
      
</xsl:choose>
    
</xsl:for-each> 
  
</xsl:template>
  
  
  <xd:doc>
    Template rule for or
  
</xd:doc>

  
<xsl:template match="ax:or" mode="pointcutXPath">
    
<xsl:for-each select="*">
            
<xsl:if test="position() &gt; 1">
        
<xsl:text> or </xsl:text>
      
</xsl:if>
            
<xsl:variable name="xpath">
        
<xsl:apply-templates select="." mode="pointcutXPath" />
      
</xsl:variable>
      
<xsl:choose>
        
<xsl:when test="normalize-space($xpath) != ''">
          
<xsl:text>(</xsl:text><xsl:value-of select="$xpath" /><xsl:text>)</xsl:text>
        
</xsl:when>
        
<xsl:otherwise>
          
<xsl:text>(true())</xsl:text>
        
</xsl:otherwise>
      
</xsl:choose>
    
</xsl:for-each> 
  
</xsl:template>
  
  
  <xd:doc>
    If an unsupported element is encountered, the program aborts and outputs an errror message. 
  
</xd:doc>

  
<xsl:template match="*" mode="pointcutXPath">
    
<xsl:choose>
      
<xsl:when test="self::ax:restriction">
        
<xsl:message terminate="yes">ERROR: Restriction elements of type '<xsl:value-of select="@type" />' are not supported. ( File: <xsl:value-of select="base-uri(.)" /> )</xsl:message>
      
</xsl:when>
      
<xsl:otherwise>
        
<xsl:message terminate="yes">ERROR: '<xsl:value-of select="name(.)" />' elements are not supported. ( File: <xsl:value-of select="base-uri(.)" /> ) </xsl:message>
      
</xsl:otherwise>
    
</xsl:choose>
  
</xsl:template>  
  
  
  
  
<!--
          =====================================
           replaceDollarVariables templates
          =====================================
         
-->
  
  
  <xd:doc>
    Removing xsl elements. children of xsl elements are processed further.
  
</xd:doc>

  
<xsl:template match="ax:xsl" mode="replaceDollarVariables">
    
<ax:text>
            
<xsl:copy-of select="child::node()" />
    
</ax:text>
  
</xsl:template>
  
  
  <xd:doc>
    Removing description elements completely
  
</xd:doc>

  
<xsl:template match="ax:description" mode="replaceDollarVariables">
    
  
</xsl:template>
  
  
  <xd:doc>
    
<xd:short> Replaces variables used in codeModifiers (format: ${VariableName})with the &lt;xsl:value-of .../&gt; equivalent. </xd:short>
    
<xd:detail>This template uses regular expression of XSLT 2.0. Using <code>&lt;![[CDATA[</code> 
    sections makes it possible to generate new xsl elements.
    If a dollarVariable is written in the form ${   var}, the space between the opening curly brace and the 
    closing curly brace is added to variable as indentation. This is especially useful for the dollar variables
    $functionBody in an 'around' advice. 
    
</xd:detail>
  
</xd:doc>

  
<xsl:template match="ax:text/text()" mode="replaceDollarVariables">
    
<xsl:variable name="string" select="." />
    
<xsl:variable name="startCData"><xsl:text disable-output-escaping="yes">&lt;xsl:text&gt;&lt;![CDATA[</xsl:text></xsl:variable>
    
<xsl:variable name="endCData"><xsl:text disable-output-escaping="yes">]]&gt;&lt;/xsl:text&gt;</xsl:text></xsl:variable>
    
<xsl:variable name="regexp" select="'\$\{(\s*)([^$^\{^\}^\s]*)\}'" />
    
<xsl:variable name="replacedString">
            
<xsl:analyze-string select="$string" regex="{$regexp}">
                    
<xsl:matching-substring>
                            
<xsl:variable name="str1" select="regex-group(1)" />
                
<xsl:variable name="str2" select="regex-group(2)" />
                       
<xsl:value-of select="$endCData" />
                                        
<xsl:text>&lt;xsl:value-of select="util:indentText( $</xsl:text>
                                        
<xsl:value-of select="$str2" />
                            
<xsl:text> , '</xsl:text>
                            
<xsl:value-of select="replace( $str1, ' ', '&amp;#x9;' )" />
                            
<xsl:text>' )"/&gt;</xsl:text>
                            
<xsl:value-of select="$startCData" />
                    
</xsl:matching-substring>
                    
<xsl:non-matching-substring>
                            
<xsl:value-of select="." />
                    
</xsl:non-matching-substring>
            
</xsl:analyze-string>
    
</xsl:variable>
    
<xsl:value-of disable-output-escaping="yes" select="$startCData" />
    
<xsl:value-of disable-output-escaping="yes" select="$replacedString" />
    
<xsl:value-of disable-output-escaping="yes" select="$endCData" />
  
</xsl:template>
  
  <xd:doc>
    Standard template for replacing dollar variables.
  
</xd:doc>

  
<xsl:template match="*" mode="replaceDollarVariables">
    
<xsl:copy>
      
<xsl:copy-of select="@*" />
      
<xsl:apply-templates mode="replaceDollarVariables" />
    
</xsl:copy>
  
</xsl:template>
  
  
  <xd:doc>
    Do not do anything, as there are maybe no variable declaration for a particular srcML element.
  
</xd:doc>

  
<xsl:template match="node()" mode="variableDeclarations">
    
<!-- Do not do anything, as there are maybe no variable decalration for a particular srcML element -->
  
</xsl:template>
</xsl:stylesheet>






































v