<!-- 
     XSLT Loop Compiler,
     translates iteration (for and while) into recursion
     Version 1.0
     GPL (c) Oliver Becker, 2000-07-06
     obecker@informatik.hu-berlin.de
-->
<xslt:transform xmlns:loop="http://informatik.hu-berlin.de/loop" xmlns:axslt="http://www.w3.org/1999/XSL/Transform/Alias" xmlns:xslt="http://www.w3.org/1999/XSL/Transform" version="1.0" exclude-result-prefixes="loop">

<xslt:namespace-alias stylesheet-prefix="axslt" result-prefix="xslt" />

<xslt:output method="xml" indent="no" encoding="iso-8859-1" />


<xslt:template match="/">
   
<!-- first validate ... -->
   
<xslt:variable name="errors">
      
<xslt:apply-templates mode="validate-loops" />
   
</xslt:variable>
   
<xslt:if test="string-length($errors)!=0">
      
<xslt:message terminate="yes">
         
<xslt:value-of select="string-length($errors)" />
         
<xslt:text> error(s) detected</xslt:text>
      
</xslt:message>
   
</xslt:if>

   
<!-- ... then generate code -->
   
<xslt:comment>

   File generated by translating loops into recursive template calls.
   XSLT Loop Compiler, Version 1.0
   GPL (c) O. Becker

   
</xslt:comment>
   
<xslt:apply-templates />
</xslt:template>


<!-- ====================== Validation code ======================= -->

<xslt:template match="loop:for" mode="validate-loops">
   
<xslt:if test="not(@name!='')">
      
<xslt:message>
         
<xslt:text>Missing required attribute 'name' of '</xslt:text>
         
<xslt:value-of select="name()" /><xslt:text />
      
</xslt:message>
      
<xslt:text>.</xslt:text>
   
</xslt:if>
   
<xslt:if test="not(@from!='')">
      
<xslt:message>
         
<xslt:text>Missing required attribute 'from' of '</xslt:text>
         
<xslt:value-of select="name()" /><xslt:text />
      
</xslt:message>
      
<xslt:text>.</xslt:text>
   
</xslt:if>
   
<xslt:if test="not(@to!='')">
      
<xslt:message>
         
<xslt:text>Missing required attribute 'to' of '</xslt:text>
         
<xslt:value-of select="name()" /><xslt:text />
      
</xslt:message>
      
<xslt:text>.</xslt:text>
   
</xslt:if>
   
<xslt:for-each select="@*">
      
<xslt:if test="name()!='name' and name()!='from' and name()!='to' and name()!='step'">
         
<xslt:message>
            
<xslt:text>Unknown attribute '</xslt:text>
            
<xslt:value-of select="name()" />
            
<xslt:text>' of '</xslt:text>
            
<xslt:value-of select="name(..)" /><xslt:text />
         
</xslt:message>
         
<xslt:text>.</xslt:text>
      
</xslt:if>
   
</xslt:for-each>
   
<xslt:apply-templates mode="validate-loops" />
</xslt:template>

<xslt:template match="loop:while" mode="validate-loops">
   
<xslt:if test="not(@test!='')">
      
<xslt:message>
         
<xslt:text>Missing required attribute 'test' of '</xslt:text>
         
<xslt:value-of select="name()" /><xslt:text />
      
</xslt:message>
      
<xslt:text>.</xslt:text>
   
</xslt:if>
   
<xslt:for-each select="@*">
      
<xslt:if test="name()!='test'">
         
<xslt:message>
            
<xslt:text>Unknown attribute '</xslt:text>
            
<xslt:value-of select="name()" />
            
<xslt:text>' of '</xslt:text>
            
<xslt:value-of select="name(..)" /><xslt:text />
         
</xslt:message>
         
<xslt:text>.</xslt:text>
      
</xslt:if>
   
</xslt:for-each>
   
<xslt:for-each select="*|text()">
      
<xslt:if test="not(self::xslt:variable or self::loop:do or self::loop:last or self::loop:update or (self::text() and normalize-space(.)=''))">
         
<xslt:message>
            
<xslt:text>Forbidden </xslt:text>
            
<xslt:choose>
               
<xslt:when test="self::text()">
                  
<xslt:text>text '</xslt:text>
                  
<xslt:value-of select="normalize-space(.)" />
               
</xslt:when>
               
<xslt:otherwise>
                  
<xslt:text>element '</xslt:text>
                  
<xslt:value-of select="name()" />
               
</xslt:otherwise>
            
</xslt:choose>
            
<xslt:text>' - expected '</xslt:text>
            
<xslt:value-of select="substring-before(name(//xslt:*),':')" />
            
<xslt:text>:variable', '</xslt:text>
            
<xslt:value-of select="substring-before(name(..),':')" />
            
<xslt:text>:do', '</xslt:text>
            
<xslt:value-of select="substring-before(name(..),':')" />
            
<xslt:text>:last' or '</xslt:text>
            
<xslt:value-of select="substring-before(name(..),':')" />
            
<xslt:text>:update'</xslt:text>
         
</xslt:message>
         
<xslt:text>.</xslt:text>
      
</xslt:if>
   
</xslt:for-each>
   
<xslt:if test="not(loop:update)">
      
<xslt:message>
         
<xslt:text />Warning: '<xslt:value-of select="name()" />
         
<xslt:text>' contains no '</xslt:text>
         
<xslt:value-of select="substring-before(name(..),':')" />
         
<xslt:text>:update' - infinite loop!</xslt:text>
      
</xslt:message>
   
</xslt:if>
   
<xslt:apply-templates mode="validate-loops" />
</xslt:template>

<xslt:template match="loop:while/xslt:variable" mode="validate-loops">
   
<xslt:choose>
      
<xslt:when test="preceding-sibling::loop:do">
         
<xslt:message>
            
<xslt:text />'<xslt:value-of select="name()" />
            
<xslt:text>' must not follow a preceding '</xslt:text>
            
<xslt:value-of select="substring-before(name(..),':')" />
            
<xslt:text>:do'</xslt:text>
         
</xslt:message>
         
<xslt:text>.</xslt:text>
      
</xslt:when>
      
<xslt:when test="preceding-sibling::loop:last">
         
<xslt:message>
            
<xslt:text />'<xslt:value-of select="name()" />
            
<xslt:text>' must not follow a preceding '</xslt:text>
            
<xslt:value-of select="substring-before(name(..),':')" />
            
<xslt:text>:last'</xslt:text>
         
</xslt:message>
         
<xslt:text>.</xslt:text>
      
</xslt:when>
      
<xslt:when test="preceding-sibling::loop:update">
         
<xslt:message>
            
<xslt:text />'<xslt:value-of select="name()" />
            
<xslt:text>' must not follow a preceding '</xslt:text>
            
<xslt:value-of select="substring-before(name(..),':')" />
            
<xslt:text>:update'</xslt:text>
         
</xslt:message>
         
<xslt:text>.</xslt:text>
      
</xslt:when>
   
</xslt:choose>
</xslt:template>

<xslt:template match="loop:do | loop:last" mode="validate-loops">
   
<xslt:if test="not(parent::loop:while)">
      
<xslt:message>
         
<xslt:text />'<xslt:value-of select="name()" />
         
<xslt:text>' must be an immediate child of '</xslt:text>
         
<xslt:value-of select="substring-before(name(),':')" />
         
<xslt:text>:while'</xslt:text>
      
</xslt:message>
      
<xslt:text>.</xslt:text>
   
</xslt:if>
   
<xslt:for-each select="@*">
      
<xslt:message>
         
<xslt:text>Unknown attribute '</xslt:text>
         
<xslt:value-of select="name()" />
         
<xslt:text>' of '</xslt:text>
         
<xslt:value-of select="name(..)" /><xslt:text />
      
</xslt:message>
      
<xslt:text>.</xslt:text>
   
</xslt:for-each>
   
<xslt:choose>
      
<xslt:when test="self::loop:do and preceding-sibling::loop:do">
         
<xslt:message>
            
<xslt:text />'<xslt:value-of select="name()" />
            
<xslt:text>' must not follow a preceding '</xslt:text>
            
<xslt:value-of select="substring-before(name(),':')" />
            
<xslt:text>:do'</xslt:text>
         
</xslt:message>
         
<xslt:text>.</xslt:text>
      
</xslt:when>
      
<xslt:when test="preceding-sibling::loop:last">
         
<xslt:message>
            
<xslt:text />'<xslt:value-of select="name()" />
            
<xslt:text>' must not follow a preceding '</xslt:text>
            
<xslt:value-of select="substring-before(name(),':')" />
            
<xslt:text>:last'</xslt:text>
         
</xslt:message>
         
<xslt:text>.</xslt:text>
      
</xslt:when>
      
<xslt:when test="preceding-sibling::loop:update">
         
<xslt:message>
            
<xslt:text />'<xslt:value-of select="name()" />
            
<xslt:text>' must not follow a preceding '</xslt:text>
            
<xslt:value-of select="substring-before(name(),':')" />
            
<xslt:text>:update'</xslt:text>
         
</xslt:message>
         
<xslt:text>.</xslt:text>
      
</xslt:when>
   
</xslt:choose>
   
<xslt:apply-templates mode="validate-loops" />
</xslt:template>

<xslt:template match="loop:update" mode="validate-loops">
   
<xslt:if test="not(parent::loop:for) and not(parent::loop:while)">
      
<xslt:message>
         
<xslt:text />'<xslt:value-of select="name()" /> 
         
<xslt:text>' must be an immediate child of '</xslt:text>
         
<xslt:value-of select="substring-before(name(),':')" />
         
<xslt:text>:for' or '</xslt:text>
         
<xslt:value-of select="substring-before(name(),':')" />
         
<xslt:text>:while'</xslt:text>
      
</xslt:message>
      
<xslt:text>.</xslt:text>
   
</xslt:if>
   
<xslt:if test="not(@name!='')">
      
<xslt:message>
         
<xslt:text>Missing required attribute 'name' of '</xslt:text>
         
<xslt:value-of select="name()" />'<xslt:text />
      
</xslt:message>
      
<xslt:text>.</xslt:text>
   
</xslt:if>
   
<xslt:for-each select="@*">
      
<xslt:if test="name()!='name' and name()!='select'">
         
<xslt:message>
            
<xslt:text>Unknown attribute '</xslt:text>
            
<xslt:value-of select="name()" />
            
<xslt:text>' of '</xslt:text>
            
<xslt:value-of select="name(..)" /><xslt:text />
         
</xslt:message>
         
<xslt:text>.</xslt:text>
      
</xslt:if>
   
</xslt:for-each>
   
<xslt:if test="preceding-sibling::loop:update [@name=current()/@name]">
      
<xslt:message>
         
<xslt:text />'<xslt:value-of select="name()" />
         
<xslt:text>' for variable '</xslt:text>
         
<xslt:value-of select="@name" />
         
<xslt:text>' already defined</xslt:text>
      
</xslt:message>
      
<xslt:text>.</xslt:text>
   
</xslt:if>
   
<xslt:call-template name="var-wrapper">
      
<xslt:with-param name="action" select="'validate-update'" />
      
<xslt:with-param name="loop-node" select=".." />
   
</xslt:call-template>
   
<xslt:apply-templates mode="validate-loops" />
</xslt:template>

<xslt:template match="loop:*" mode="validate-loops">
   
<xslt:message>
      
<xslt:text />Unknown element '<xslt:value-of select="name()" />
      
<xslt:text>'</xslt:text>
   
</xslt:message>
   
<xslt:text>.</xslt:text>
   
<xslt:apply-templates mode="validate-loops" />
</xslt:template>

<xslt:template match="text()" mode="validate-loops" />

<!-- =================== End of validation ======================== -->



<!-- ================= General template rules ===================== -->

<xslt:template match="xslt:stylesheet | xslt:transform">
   
<xslt:copy>
      
<xslt:copy-of select="@*" />
      
<xslt:apply-templates />
      
<xslt:apply-templates mode="create-templates" />
   
</xslt:copy>
</xslt:template>

<xslt:template match="text()" mode="create-templates" />

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

<xslt:template match="comment()|processing-instruction()">
   
<xslt:copy />
</xslt:template>



<!-- ========================= for-loop =========================== -->

<xslt:template match="loop:for">
   
<xslt:variable name="step">
      
<xslt:choose>
         
<xslt:when test="not(@step)">1</xslt:when>
         
<xslt:otherwise>
            
<xslt:value-of select="@step" />
         
</xslt:otherwise>
      
</xslt:choose>
   
</xslt:variable>
   
<xslt:variable name="id" select="generate-id()" />
   
<axslt:call-template name="for-loop-{$id}">
      
<axslt:with-param name="{@name}" select="{@from}" />
      
<axslt:with-param name="to{$id}" select="{@to}" />
      
<axslt:with-param name="step{$id}" select="{$step}" />
      
<xslt:call-template name="var-wrapper">
         
<xslt:with-param name="action" select="'create-call-with-params'" />
      
</xslt:call-template>
   
</axslt:call-template>
</xslt:template>


<xslt:template match="loop:for" mode="create-templates">
   
<xslt:variable name="id" select="generate-id()" />

   
<axslt:template name="for-loop-{$id}">
      
<axslt:param name="{@name}" />
      
<axslt:param name="to{$id}" />
      
<axslt:param name="step{$id}" />
      
<xslt:call-template name="var-wrapper">
         
<xslt:with-param name="action" select="'create-loop-params'" />
      
</xslt:call-template>

      
<xslt:apply-templates />

      
<xslt:variable name="comp-op">
         
<xslt:choose>
            
<xslt:when test="@step &lt; 0">&gt;=</xslt:when>
            
<xslt:otherwise>&lt;=</xslt:otherwise>
         
</xslt:choose>
      
</xslt:variable>

      
<axslt:if test="${@name}+$step{$id} {$comp-op} $to{$id}">
         
<axslt:call-template name="for-loop-{$id}">
            
<axslt:with-param name="{@name}" select="${@name} + $step{$id}" />
            
<axslt:with-param name="to{$id}" select="$to{$id}" />
            
<axslt:with-param name="step{$id}" select="$step{$id}" />
            
<xslt:call-template name="var-wrapper">
               
<xslt:with-param name="action" select="'create-loop-with-params'" />
            
</xslt:call-template>
         
</axslt:call-template>
      
</axslt:if>
   
</axslt:template>

   
<xslt:apply-templates mode="create-templates" />
</xslt:template>

<!-- ============================================================== -->



<!-- ====================== while-loop ============================ -->

<xslt:template match="loop:while">
   
<axslt:call-template name="while-loop-{generate-id()}">
      
<xslt:call-template name="var-wrapper">
         
<xslt:with-param name="action" select="'create-call-with-params'" />
      
</xslt:call-template>
   
</axslt:call-template>
</xslt:template>


<xslt:template match="loop:while" mode="create-templates">
   
<xslt:variable name="id" select="generate-id()" />

   
<axslt:template name="while-loop-{$id}">
      
<xslt:call-template name="var-wrapper">
         
<xslt:with-param name="action" select="'create-loop-params'" />
      
</xslt:call-template>

      
<xslt:copy-of select="xslt:variable" />
      
<axslt:choose>
         
<axslt:when test="{@test}">
            
<xslt:apply-templates select="loop:do" />
            
<axslt:call-template name="while-loop-{$id}">
               
<xslt:call-template name="var-wrapper">
                  
<xslt:with-param name="action" select="'create-loop-with-params'" />
               
</xslt:call-template>
            
</axslt:call-template>
         
</axslt:when>
         
<xslt:if test="loop:last">
            
<axslt:otherwise>
               
<xslt:apply-templates select="loop:last" />
            
</axslt:otherwise>
         
</xslt:if>
      
</axslt:choose>
   
</axslt:template>
   
   
<xslt:apply-templates mode="create-templates" />
</xslt:template>


<xslt:template match="loop:do | loop:last">
   
<xslt:apply-templates />
</xslt:template>


<xslt:template match="loop:update" />

<!-- ============================================================== -->



<!-- =================== variable wrapper ========================= -->
<!-- separated because the expression for $vars was a little bit 
     difficult to determine 
-->

<xslt:template name="var-wrapper">
   
<xslt:param name="action" />
   
<xslt:param name="loop-node" select="." />
   
<xslt:variable name="vars" select="$loop-node/ancestor-or-self::*/preceding-sibling::xslt:variable [ancestor::xslt:template] | $loop-node/ancestor-or-self::*/preceding-sibling::xslt:param [ancestor::xslt:template] | $loop-node/ancestor::loop:for" />
   
<xslt:choose>
      
<xslt:when test="$action='create-call-with-params'">
         
<xslt:for-each select="$vars">
            
<axslt:with-param name="{@name}" select="${@name}" />
         
</xslt:for-each>
      
</xslt:when>
      
<xslt:when test="$action='create-loop-params'">
         
<xslt:for-each select="$vars">
            
<axslt:param name="{@name}" />
         
</xslt:for-each>
      
</xslt:when>
      
<xslt:when test="$action='create-loop-with-params'">
         
<xslt:for-each select="$vars"> 
            
<xslt:variable name="update" select="$loop-node/loop:update [@name=current()/@name]" />
            
<xslt:choose>
               
<xslt:when test="$update">
                  
<axslt:with-param name="{@name}">
                     
<xslt:if test="$update/@select">
                       
<xslt:attribute name="select">
                          
<xslt:value-of select="$update/@select" />
                       
</xslt:attribute>
                     
</xslt:if>
                     
<xslt:apply-templates select="$update" mode="process-update" />
                  
</axslt:with-param>
               
</xslt:when>
               
<xslt:otherwise>
                  
<axslt:with-param name="{@name}" select="${@name}" />
               
</xslt:otherwise>
            
</xslt:choose>
         
</xslt:for-each>
      
</xslt:when>

      
<!-- the following is validation code -->
      
<xslt:when test="$action='validate-update'">
         
<xslt:if test="@name and not($vars[@name=current()/@name])">
            
<xslt:message>
               
<xslt:text>Cannot update variable '</xslt:text>
               
<xslt:value-of select="@name" />
               
<xslt:text>' - not locally visible at parent node '</xslt:text>
               
<xslt:value-of select="name(..)" /><xslt:text />
            
</xslt:message>
            
<xslt:text>.</xslt:text>
         
</xslt:if>
      
</xslt:when>

   
</xslt:choose>
</xslt:template>


<xslt:template match="loop:update" mode="process-update">
   
<xslt:apply-templates />
</xslt:template>


</xslt:transform>