impl step2, remove interleaved calls in READ/EVAL/PRINT
[jackhill/mal.git] / xslt / step2_eval.xslt
index df8e70d..89ca396 100644 (file)
@@ -10,7 +10,7 @@
 -->
 <xsl:stylesheet
     version="3.0"
-    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema"  xmlns:map="http://www.w3.org/2005/xpath-functions/map">
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema"  xmlns:map="http://www.w3.org/2005/xpath-functions/map" exclude-result-prefixes="fn xs map">
     <xsl:import href="reader.xslt" />
     <xsl:import href="printer.xslt" />
     <xsl:output method='xml' encoding='utf-8' indent='yes'/>
         <xsl:variable name="env" as="map(*)">
           <xsl:if test="not(state)"> <!-- we never update this -->
             <xsl:map>
-              <xsl:map-entry key="'+'" select="'lvalue/malval[1]/@value + lvalue/malval[2]/@value'" />
-              <xsl:map-entry key="'-'" select="'lvalue/malval[1]/@value - lvalue/malval[2]/@value'" />
-              <xsl:map-entry key="'*'" select="'lvalue/malval[1]/@value * lvalue/malval[2]/@value'" />
-              <xsl:map-entry key="'/'" select="'lvalue/malval[1]/@value / lvalue/malval[2]/@value'" />
+              <xsl:map-entry key="'+'" select="'+'"/>
+              <xsl:map-entry key="'-'" select="'-'"/>
+              <xsl:map-entry key="'*'" select="'*'"/>
+              <xsl:map-entry key="'/'" select="'/'"/>
             </xsl:map>
           </xsl:if>
         </xsl:variable>
         <xsl:sequence select="stdin"/>
-        <stdout><xsl:call-template name="PRINT"><xsl:with-param name="env" select="$env"/></xsl:call-template></stdout> 
+        <xsl:variable name="_read">
+          <xsl:call-template name="READ" />
+        </xsl:variable>
+        <xsl:variable name="_eval">
+          <xsl:for-each select="$_read">
+            <xsl:call-template name="EVAL"><xsl:with-param name="env" select="$env"/></xsl:call-template>
+          </xsl:for-each>
+        </xsl:variable>
+        <stdout>
+          <xsl:for-each select="$_eval">
+            <xsl:call-template name="PRINT"><xsl:with-param name="env" select="$env"/></xsl:call-template>
+          </xsl:for-each>
+        </stdout>
       </mal>
     </xsl:template>
 
     <xsl:template name="PRINT">
       <xsl:param name="env" />
-      <xsl:variable name="context">
-        <xsl:variable name="ctx">
-          <xsl:call-template name="EVAL"><xsl:with-param name="env" select="$env"/></xsl:call-template>
-        </xsl:variable>
-        <xsl:for-each select="$ctx">
-          <xsl:variable name="str">
-            <xsl:call-template name="malprinter-pr_str"><xsl:with-param name="readably" select="true()"/></xsl:call-template>
-          </xsl:variable>
-          <xsl:value-of select="$str" />
-        </xsl:for-each>
+      <xsl:variable name="str">
+        <xsl:call-template name="malprinter-pr_str"><xsl:with-param name="readably" select="true()"/></xsl:call-template>
       </xsl:variable>
-      <xsl:for-each select="$context"><xsl:copy-of select="." /></xsl:for-each>
+      <xsl:value-of select="$str" />
     </xsl:template>
 
     <xsl:template name="eval_ast">
@@ -65,7 +69,7 @@
                   </xsl:variable>
                   <xsl:variable name="xctx">
                     <xsl:for-each select="$ctx">
-                      <xsl:call-template name="eval_ast"><xsl:with-param name="env" select="$env"/></xsl:call-template>
+                      <xsl:call-template name="EVAL"><xsl:with-param name="env" select="$env"/></xsl:call-template>
                     </xsl:for-each>
                   </xsl:variable>
                   <xsl:sequence select="$xctx/value/malval"/>
       </xsl:choose>
     </xsl:template>
 
+    <!-- vapply[fn, args] :: fn/value/text() -->
+    <xsl:template name="vapply">
+      <xsl:param name="func" />
+      <xsl:param name="args" />
+      <xsl:choose>
+        <xsl:when test="$func = '+'">
+          <xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) + number($args/value/malval/lvalue/malval[2]/@value)"></xsl:variable>
+          <xsl:sequence select="fn:makeMALType($result, 'number')"/>
+        </xsl:when>
+        <xsl:when test="$func = '-'">
+          <xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) - number($args/value/malval/lvalue/malval[2]/@value)"></xsl:variable>
+          <xsl:sequence select="fn:makeMALType($result, 'number')"/>
+        </xsl:when>
+        <xsl:when test="$func = '*'">
+          <xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) * number($args/value/malval/lvalue/malval[2]/@value)"></xsl:variable>
+          <xsl:sequence select="fn:makeMALType($result, 'number')"/>
+        </xsl:when>
+        <xsl:when test="$func = '/'">
+          <xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) div number($args/value/malval/lvalue/malval[2]/@value)"></xsl:variable>
+          <xsl:sequence select="fn:makeMALType($result, 'number')"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <error>Invalid function <xsl:sequence select="$func"/> </error>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:template>
+
     <xsl:template name="EVAL">
       <xsl:param name="env" />
-      <xsl:variable name="context">
-        <xsl:call-template name="READ" />
-      </xsl:variable>
-      <xsl:for-each select="$context">
-        <xsl:choose>
-          <xsl:when test="value/malval/@kind = 'list'">
-            <xsl:choose>
-              <xsl:when test="count(value/malval/lvalue/malval) = 0">
-                <xsl:sequence select="."/>
-              </xsl:when>
-              <xsl:otherwise>
-                <!-- <xsl:variable name="new_list"> -->
-                  <xsl:call-template name="eval_ast"><xsl:with-param name="env" select="$env"/></xsl:call-template>
-                <!-- </xsl:variable>
-                <xsl:sequence select="$new_list"/> -->
-              </xsl:otherwise>
-            </xsl:choose>
-          </xsl:when>
-          <xsl:otherwise>
-            <xsl:sequence select="."/>
-          </xsl:otherwise>
-        </xsl:choose>
-      </xsl:for-each>
+      <xsl:choose>
+        <xsl:when test="value/malval/@kind = 'list'">
+          <xsl:choose>
+            <xsl:when test="count(value/malval/lvalue/malval) = 0">
+              <xsl:sequence select="."/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:variable name="new_list">
+                <xsl:call-template name="eval_ast"><xsl:with-param name="env" select="$env"/></xsl:call-template>
+              </xsl:variable>
+              <xsl:variable name="func">
+                <xsl:for-each select="$new_list">
+                  <xsl:sequence select="value/malval/lvalue[1]/malval/text()"/>
+                </xsl:for-each>
+              </xsl:variable>
+              <xsl:variable name="args">
+                <xsl:for-each select="$new_list">
+                  <value>
+                    <malval kind="list">
+                      <lvalue>
+                        <xsl:for-each select="value/malval/lvalue/node()[position() != 1]">
+                          <xsl:sequence select="."/>
+                        </xsl:for-each>
+                      </lvalue>
+                    </malval>
+                  </value>
+                </xsl:for-each>
+              </xsl:variable>
+              <xsl:call-template name="vapply"><xsl:with-param name="func" select="$func"/><xsl:with-param name="args" select="$args"/></xsl:call-template>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:call-template name="eval_ast"><xsl:with-param name="env" select="$env"/></xsl:call-template>
+        </xsl:otherwise>
+      </xsl:choose>
     </xsl:template>
 
     <xsl:template name="READ">
         </xsl:otherwise>
       </xsl:choose>
     </xsl:function>
+
+    <xsl:function name="fn:makeMALType">
+      <xsl:param name="value" />
+      <xsl:param name="kind" />
+      <value>
+        <malval kind="{$kind}" value="{$value}"/>
+      </value>
+    </xsl:function>
 </xsl:stylesheet>