<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:env="ENV">
<!-- since I can not, for the life of me, figure out how to (de-)serialise maps from/to xml, we're gonna be storing the env as a json string -->
+ <xsl:function name="env:noReplEnv">
+ <xsl:param name="env"/>
+ <xsl:sequence select="map {'outer': $env('outer'), 'isReplEnv': false(), 'data': $env('data') }"/>
+ </xsl:function>
+
<xsl:function name="env:set">
<xsl:param name="env"/>
<xsl:param name="name"/>
<xsl:param name="value"/>
- <xsl:sequence select="map { 'outer': $env('outer'), 'data': map:put(map:merge($env('data')), $name, $value => serialize(map{})) }"/>
+ <xsl:sequence select="if ($env('isReplEnv')) then map { 'outer': $env('outer'), 'replEnv': env:set($env('replEnv'), $name, $value), 'isReplEnv': true(), 'data': $env('data') } else map { 'outer': $env('outer'), 'replEnv': $env('replEnv'), 'isReplEnv': false(), 'data': map:put($env('data'), $name, $value => serialize(map{})) }"/>
</xsl:function>
<xsl:function name="env:find">
<xsl:param name="env"/>
<xsl:param name="name"/>
- <xsl:sequence select="if (empty($env)) then () else if (map:contains($env('data'), $name)) then $env else env:find($env('outer'), $name)"/>
+ <xsl:sequence select="if (empty($env)) then () else if (map:contains($env('data'), $name)) then $env else (env:find($env('outer'), $name), env:find($env('replEnv'), $name))[1]"/>
</xsl:function>
<xsl:function name="env:get">
<xsl:variable name="minus"><malval kind="function" name="-"></malval></xsl:variable>
<xsl:variable name="mult"><malval kind="function" name="*"></malval></xsl:variable>
<xsl:variable name="div"><malval kind="function" name="/"></malval></xsl:variable>
- <xsl:sequence select="env:serialise(env:set(env:set(env:set(env:set(map{'outer':(), 'data':map{}}, '+', $plus), '-', $minus), '*', $mult), '/', $div))"/>
+ <xsl:sequence select="env:serialise(env:set(env:set(env:set(env:set(map{'outer':(), 'data':map{}, 'isReplEnv': false()}, '+', $plus), '-', $minus), '*', $mult), '/', $div))"/>
+ </xsl:function>
+
+ <xsl:function name="env:swap-replEnv">
+ <xsl:param name="env"></xsl:param>
+ <xsl:param name="toRepl"></xsl:param>
+ <xsl:sequence select="if (not(empty($toRepl))) then map:put($env, 'replEnv', $toRepl) else $env"/>
+ </xsl:function>
+
+ <xsl:function name="env:replEnv">
+ <xsl:param name="env"/>
+ <xsl:sequence select="$env('replEnv')"/>
+ </xsl:function>
+
+ <xsl:function name="env:toReplEnv">
+ <xsl:param name="env"/>
+ <xsl:variable name='renv' select="map{'outer':(), 'data': map{}, 'replEnv': map{'data':env:dump($env), 'outer':(), 'isReplEnv': false()}, 'isReplEnv': true()}"/>
+ <xsl:sequence select="$renv"/>
</xsl:function>
<xsl:function name="env:empty">
- <xsl:sequence select="map{'outer':(), 'data':map{}}"/>
+ <xsl:sequence select="map{'outer':(), 'data':map{}, 'isReplEnv': false()}"/>
</xsl:function>
<xsl:function name="env:serialise">
<xsl:function name="env:close">
<xsl:param name="env"/>
- <xsl:sequence select="map {'outer': $env, 'data': map{}}"/>
+ <xsl:sequence select="map{'outer': env:noReplEnv($env), 'data': map{}, 'isReplEnv': false(), 'replEnv': $env('replEnv')}"/>
</xsl:function>
<xsl:function name="env:close-with-binds">
<xsl:param name="binds" />
<xsl:param name="exprs" />
- <xsl:variable name="new-env" select="map {'outer': $env, 'data': map{}}"/>
+ <xsl:variable name="new-env" select="map {'outer': env:noReplEnv($env), 'replEnv': $env('replEnv'), 'data': map{}, 'isReplEnv': false()}"/>
<xsl:sequence select="$new-env => env:bind-all($binds, $exprs)"/>
</xsl:function>
<xsl:variable name="env-items" select="env:dump($env)"></xsl:variable>
<xsl:variable name="second-items" select="env:dump($second)"></xsl:variable>
- <xsl:variable name="new-env" select="map {'outer': (), 'data': map:merge(($env-items, $second-items))}"></xsl:variable>
+ <xsl:variable name="new-env" select="if (empty($env)) then $second else if (empty($second)) then $env else map {'outer': $env('outer'), 'data': map:merge(($env-items, $second-items)), 'isReplEnv': false(), 'replEnv': env:merge($second('replEnv'), $env('replEnv'))}"></xsl:variable>
<xsl:sequence select="$new-env"/>
</xsl:function>
<xsl:function name="env:hier">
<xsl:param name="env"/>
<xsl:param name="over"/>
- <xsl:sequence select="map{'outer': env:merge($over, $env), 'data': map{}}"/>
+ <xsl:variable name="newEnv" select="env:merge($over, $env)"></xsl:variable>
+ <xsl:sequence select="map{'outer': env:noReplEnv($newEnv), 'data': map{}, 'isReplEnv': false(), 'replEnv': $newEnv('replEnv')}"/>
</xsl:function>
<xsl:function name="env:bind-all">
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Step 6: File -->
+<!-- input document must be in the following format -->
+<!--
+<mal>
+ <stdin>...stdin text...</stdin>
+ <stdout> ... ignored, omitted ... </stdout>
+ <state> contains env and atoms </state>
+</mal>
+-->
+<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:env="ENV" xmlns:core="CORE" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:map="http://www.w3.org/2005/xpath-functions/map" exclude-result-prefixes="fn xs map env core">
+ <xsl:import href="reader.xslt" />
+ <xsl:import href="printer.xslt" />
+ <xsl:import href="env.xslt" />
+ <xsl:import href="core.xslt" />
+
+ <xsl:output method='xml' encoding='utf-8' indent='yes'/>
+ <xsl:template match="mal" name="rep">
+ <xsl:choose>
+ <xsl:when test="string(state/env/@data) = ''">
+ <xsl:variable name="argv">
+ <malval kind="list">
+ <lvalue>
+ <xsl:for-each select="argv/arg/text()">
+ <malval kind="string" value="{.}" />
+ </xsl:for-each>
+ </lvalue>
+ </malval>
+ </xsl:variable>
+ <xsl:variable name="vstate">
+ <mal>
+ <state>
+ <env data="{env:serialise(env:empty() => env:bind-all(core:ns()/@name, core:ns()) => env:set('*ARGV*', $argv) => env:toReplEnv())}"></env>
+ <atoms />
+ </state>
+ <stdin>(do (def! not (fn* (a) (if a false true))) (def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) "\nnil)"))))))</stdin>
+ </mal>
+ </xsl:variable>
+ <xsl:variable name="new-state">
+ <xsl:for-each select="$vstate/mal">
+ <xsl:call-template name="rep"></xsl:call-template>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:variable name="state-v">
+ <xsl:sequence select="$new-state/mal/state"/>
+ <xsl:sequence select="stdin"/>
+ </xsl:variable>
+ <xsl:for-each select="$state-v">
+ <xsl:call-template name="rep"></xsl:call-template>
+ </xsl:for-each>
+ </xsl:when>
+ <xsl:otherwise>
+ <mal>
+ <xsl:variable name="env" as="map(*)">
+ <xsl:sequence select="env:deserialise(state/env/@data)"/>
+ </xsl:variable>
+ <xsl:sequence select="stdin"/>
+ <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>
+ <xsl:for-each select="$_eval">
+ <stdout>
+ <xsl:variable name="data">
+ <xsl:sequence select="data/value"/>
+ <xsl:sequence select="atoms"/>
+ </xsl:variable>
+ <xsl:for-each select="$data">
+ <xsl:call-template name="PRINT"></xsl:call-template>
+ </xsl:for-each>
+ </stdout>
+ <state>
+ <env data="{env/@data}"/>
+ <xsl:sequence select="atoms"/>
+ </state>
+ </xsl:for-each>
+ </mal>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="PRINT">
+ <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:template>
+
+ <xsl:template name="eval_ast">
+ <xsl:param name="env" />
+ <xsl:choose>
+ <xsl:when test="value/malval/@kind = 'symbol'">
+ <xsl:variable name="val">
+ <xsl:sequence select="env:get($env, value/malval/@value)" />
+ </xsl:variable>
+ <value>
+ <xsl:sequence select="$val"/>
+ </value>
+ </xsl:when>
+ <xsl:when test="value/malval/@kind = 'list'">
+ <value>
+ <malval kind="list">
+ <lvalue>
+ <xsl:for-each select="value/malval/lvalue/malval">
+ <xsl:variable name="ctx">
+ <value>
+ <xsl:sequence select="."/>
+ </value>
+ </xsl:variable>
+ <xsl:variable name="xctx">
+ <xsl:for-each select="$ctx">
+ <xsl:variable name="val">
+ <xsl:call-template name="EVAL"><xsl:with-param name="env" select="$env"/></xsl:call-template>
+ </xsl:variable>
+ <xsl:sequence select="$val/data/value"/>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:sequence select="$xctx/value/malval"/>
+ </xsl:for-each>
+ </lvalue>
+ </malval>
+ </value>
+ </xsl:when>
+ <xsl:when test="value/malval/@kind = 'vector'">
+ <value>
+ <malval kind="vector">
+ <lvalue>
+ <xsl:for-each select="value/malval/lvalue/malval">
+ <xsl:variable name="ctx">
+ <value>
+ <xsl:sequence select="."/>
+ </value>
+ </xsl:variable>
+ <xsl:variable name="xctx">
+ <xsl:for-each select="$ctx">
+ <xsl:variable name="val">
+ <xsl:call-template name="EVAL"><xsl:with-param name="env" select="$env"/></xsl:call-template>
+ </xsl:variable>
+ <xsl:sequence select="$val/data/value"/>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:sequence select="$xctx/value/malval"/>
+ </xsl:for-each>
+ </lvalue>
+ </malval>
+ </value>
+ </xsl:when>
+ <xsl:when test="value/malval/@kind = 'hash'">
+ <value>
+ <malval kind="hash">
+ <lvalue>
+ <xsl:for-each select="value/malval/lvalue/malval">
+ <xsl:variable name="ctx">
+ <value>
+ <xsl:sequence select="."/>
+ </value>
+ </xsl:variable>
+ <xsl:variable name="xctx">
+ <xsl:for-each select="$ctx">
+ <xsl:variable name="val">
+ <xsl:call-template name="EVAL"><xsl:with-param name="env" select="$env"/></xsl:call-template>
+ </xsl:variable>
+ <xsl:sequence select="$val/data/value"/>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:sequence select="$xctx/value/malval"/>
+ </xsl:for-each>
+ </lvalue>
+ </malval>
+ </value>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:sequence select="." />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- uapply[env, fn, args] -->
+ <xsl:template name="uapply">
+ <xsl:param name="func" />
+ <xsl:param name="args" />
+ <xsl:param name="env" />
+
+ <xsl:variable name="nenv" select="$env => env:hier(env:deserialise($func/malval/env/@data)) => env:close-with-binds($func/malval/binds/malval/@value, $args/value/malval/lvalue/malval)" />
+ <xsl:variable name="body">
+ <value>
+ <xsl:sequence select="$func/malval/body/malval"/>
+ </value>
+ <xsl:sequence select="atoms"/>
+ </xsl:variable>
+ <xsl:variable name="result">
+ <xsl:for-each select="$body">
+ <xsl:call-template name="EVAL"><xsl:with-param name="env" select="$nenv"/></xsl:call-template>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:sequence select="$result/data/value"/>
+ <env data="{env:serialise(env:swap-replEnv($env, env:deserialise($result/env/@data) => env:replEnv()))}" />
+ <xsl:sequence select="$result/atoms"/>
+ </xsl:template>
+
+ <xsl:template name="EVAL">
+ <xsl:param name="env" />
+ <xsl:variable name="atoms" select="atoms"></xsl:variable>
+ <xsl:variable name="data">
+ <xsl:choose>
+ <xsl:when test="value/malval/@kind = 'list'">
+ <xsl:choose>
+ <xsl:when test="count(value/malval/lvalue/malval) = 0">
+ <xsl:sequence select="."/>
+ <env data="{env:serialise($env)}" />
+ <xsl:sequence select="$atoms"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:choose>
+ <xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'def!'">
+ <xsl:variable name="name">
+ <xsl:value-of select="value/malval/lvalue/malval[2]/@value"/>
+ </xsl:variable>
+ <xsl:variable name="xvalue">
+ <value>
+ <xsl:sequence select="value/malval/lvalue/malval[3]"/>
+ </value>
+ <xsl:sequence select="$atoms"/>
+ </xsl:variable>
+ <xsl:variable name="value">
+ <xsl:for-each select="$xvalue">
+ <xsl:call-template name="EVAL"><xsl:with-param name="env" select="$env"/></xsl:call-template>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:sequence select="$value/data/value"/>
+ <env data="{env:serialise(env:set($env, $name, $value/data/value/malval))}"/>
+ <xsl:sequence select="$value/atoms"/>
+ </xsl:when>
+ <xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'let*'">
+ <xsl:variable name="xvalue">
+ <value>
+ <xsl:sequence select="value/malval/lvalue/malval[3]"/>
+ </value>
+ <xsl:sequence select="$atoms"/>
+ </xsl:variable>
+
+ <xsl:iterate select="fn:group_consec(value/malval/lvalue/malval[2]/lvalue/malval)">
+ <xsl:param name="new_env" select="env:close($env)"/>
+ <xsl:param name="new_atoms" select="$atoms"/>
+
+ <xsl:on-completion>
+ <xsl:variable name="xvalue">
+ <xsl:sequence select="$xvalue/value"/>
+ <xsl:sequence select="$new_atoms"/>
+ </xsl:variable>
+ <xsl:variable name="value">
+ <xsl:for-each select="$xvalue">
+ <xsl:call-template name="EVAL"><xsl:with-param name="env" select="$new_env"/></xsl:call-template>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:sequence select="$value/data/value"></xsl:sequence>
+ <env data="{env:serialise(env:swap-replEnv($env, env:deserialise($value/env/@data) => env:replEnv()))}" />
+
+ <xsl:sequence select="$value/atoms"/>
+ </xsl:on-completion>
+
+ <xsl:variable name="name">
+ <xsl:value-of select="node()[name() = 'first']/malval/@value"/>
+ </xsl:variable>
+
+ <xsl:variable name="xvalue">
+ <value>
+ <xsl:sequence select="node()[name() = 'second']/malval"/>
+ </value>
+ <xsl:sequence select="$new_atoms"/>
+ </xsl:variable>
+
+ <xsl:variable name="value">
+ <xsl:for-each select="$xvalue">
+ <xsl:call-template name="EVAL"><xsl:with-param name="env" select="$new_env"/></xsl:call-template>
+ </xsl:for-each>
+ </xsl:variable>
+
+ <xsl:next-iteration>
+ <xsl:with-param name="new_env" select="env:set($new_env, $name, $value/data/value/malval)"/>
+ <xsl:with-param name="new_atoms" select="$value/atoms"/>
+ </xsl:next-iteration>
+ </xsl:iterate>
+ </xsl:when>
+ <xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'do'">
+ <xsl:iterate select="value/malval/lvalue/malval[position() > 1]">
+ <xsl:param name="new_env" select="$env"/>
+ <xsl:param name="atoms" select="$atoms"/>
+ <xsl:param name="previous_res" select="()"/>
+ <xsl:on-completion>
+ <xsl:sequence select="$previous_res"/>
+ <env data="{env:serialise($new_env)}" />
+ <xsl:sequence select="$atoms"/>
+ </xsl:on-completion>
+ <xsl:variable name="xvalue">
+ <value>
+ <xsl:sequence select="."/>
+ </value>
+ <xsl:sequence select="$atoms"/>
+ </xsl:variable>
+ <xsl:variable name="value">
+ <xsl:for-each select="$xvalue">
+ <xsl:call-template name="EVAL"><xsl:with-param name="env" select="$new_env"/></xsl:call-template>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:next-iteration>
+ <xsl:with-param name="new_env" select="env:deserialise($value/env/@data)"/>
+ <xsl:with-param name="previous_res" select="$value/data/value"/>
+ <xsl:with-param name="atoms" select="$value/atoms"/>
+ </xsl:next-iteration>
+ </xsl:iterate>
+ </xsl:when>
+ <xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'if'">
+ <xsl:variable name="cond">
+ <xsl:for-each select="value/malval/lvalue/malval[2]">
+ <xsl:variable name="context">
+ <value>
+ <xsl:sequence select="."/>
+ </value>
+ <xsl:sequence select="$atoms"/>
+ </xsl:variable>
+ <xsl:for-each select="$context">
+ <xsl:call-template name="EVAL"><xsl:with-param name="env" select="$env"/></xsl:call-template>
+ </xsl:for-each>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:variable name="ptrue">
+ <xsl:for-each select="value/malval/lvalue/malval[3]">
+ <value>
+ <xsl:sequence select="."/>
+ </value>
+ <xsl:sequence select="$cond/atoms"/>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:variable name="pfalse">
+ <xsl:for-each select="value/malval/lvalue/malval[4]">
+ <value>
+ <xsl:sequence select="."/>
+ </value>
+ <xsl:sequence select="$cond/atoms"/>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:variable name="xfalse">
+ <xsl:choose>
+ <xsl:when test="empty($pfalse/value)">
+ <value>
+ <malval kind='nil' />
+ </value>
+ <xsl:sequence select="$cond/atoms"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:sequence select="$pfalse/value"/>
+ <xsl:sequence select="$pfalse/atoms"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="res">
+ <xsl:choose>
+ <xsl:when test="let $kind := $cond/data/value/malval/@kind return $kind = 'nil' or $kind = 'false'">
+ <xsl:for-each select="$xfalse">
+ <xsl:call-template name="EVAL"><xsl:with-param name="env" select="$env"/></xsl:call-template>
+ </xsl:for-each>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:for-each select="$ptrue">
+ <xsl:call-template name="EVAL"><xsl:with-param name="env" select="$env"/></xsl:call-template>
+ </xsl:for-each>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:sequence select="$res/data/value"/>
+ <env data="{env:serialise($env)}" />
+ <xsl:sequence select="$res/atoms"/>
+ </xsl:when>
+ <xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'fn*'">
+ <value>
+ <malval kind="userfunction">
+ <binds>
+ <xsl:sequence select="value/malval/lvalue/malval[2]/lvalue/malval" />
+ </binds>
+ <body>
+ <xsl:sequence select="value/malval/lvalue/malval[3]"/>
+ </body>
+ <env data="{env:serialise(env:noReplEnv($env))}"/> <!-- capture current env -->
+ </malval>
+ </value>
+ <env data="{env:serialise($env)}" />
+ <xsl:sequence select="$atoms"/>
+ </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/malval[1]"/>
+ </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:sequence select="$atoms"/>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:variable name="resultv">
+ <xsl:choose>
+ <xsl:when test="$func/malval/@kind = 'userfunction'">
+ <xsl:call-template name="uapply"><xsl:with-param name="env" select="$env"/><xsl:with-param name="func" select="$func"/><xsl:with-param name="args" select="$args"/></xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:choose>
+ <xsl:when test="$func/malval/@name = 'env??'"> <!-- needs access to env -->
+ <xsl:variable name="nev" select="env:dump($env)"></xsl:variable>
+ <xsl:variable name="value">
+ <malval kind="string" value="{$env => serialize(map{'method':'json'})}"/>
+ </xsl:variable>
+ <value>
+ <xsl:sequence select="$value"/>
+ </value>
+ <env data="{env:serialise($env)}"/>
+ <xsl:sequence select="$value/atoms"/>
+ </xsl:when>
+ <xsl:when test="$func/malval/@name = 'eval'"> <!-- needs access to env -->
+ <xsl:variable name="venv" select="env:replEnv($env)"></xsl:variable>
+ <xsl:variable name="form">
+ <value>
+ <xsl:sequence select="$args/value/malval/lvalue/malval[1]"/>
+ </value>
+ <xsl:sequence select="$atoms"/>
+ </xsl:variable>
+ <xsl:variable name="value">
+ <xsl:for-each select="$form">
+ <xsl:call-template name="EVAL"><xsl:with-param name="env" select="$venv"/></xsl:call-template>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:sequence select="$value/data/value"/>
+ <env data="{env:serialise(env:swap-replEnv($env, env:deserialise($value/env/@data)))}"/>
+ <xsl:sequence select="$value/atoms"/>
+ </xsl:when>
+ <xsl:when test="$func/malval/@name = 'atom'"> <!-- needs access to atoms -->
+ <xsl:variable name="atom-ident" select="current-dateTime()"></xsl:variable>
+ <value>
+ <malval kind="atom" value="{$atom-ident}"/>
+ </value>
+ <atoms>
+ <xsl:for-each select="$atoms/atom">
+ <xsl:sequence select="."/>
+ </xsl:for-each>
+ <atom identity="{$atom-ident}">
+ <xsl:sequence select="$args/value/malval/lvalue/malval[1]"/>
+ </atom>
+ </atoms>
+ </xsl:when>
+ <xsl:when test="$func/malval/@name = 'deref'"> <!-- needs access to atoms -->
+ <value>
+ <xsl:sequence select="$atoms/atom[@identity = $args/value/malval/lvalue/malval[1]/@value]/malval"/>
+ </value>
+ <xsl:sequence select="$atoms"/>
+ </xsl:when>
+ <xsl:when test="$func/malval/@name = 'reset!'"> <!-- needs access to atoms -->
+ <xsl:variable name="atom-ident" select="$args/value/malval/lvalue/malval[1]/@value"></xsl:variable>
+ <xsl:variable name="newv" select="$args/value/malval/lvalue/malval[2]"></xsl:variable>
+ <value>
+ <xsl:sequence select="$newv"/>
+ </value>
+ <atoms>
+ <xsl:for-each select="$atoms/atom[@identity != $atom-ident]">
+ <xsl:sequence select="."/>
+ </xsl:for-each>
+ <atom identity="{$atom-ident}">
+ <xsl:sequence select="$newv"/>
+ </atom>
+ </atoms>
+ </xsl:when>
+ <xsl:when test="$func/malval/@name = 'swap!'"> <!-- needs access to atoms -->
+ <xsl:variable name="atom-ident" select="$args/value/malval/lvalue/malval[1]/@value"></xsl:variable>
+ <xsl:variable name="atom-value" select="$atoms/atom[@identity = $atom-ident]/malval"></xsl:variable>
+ <xsl:variable name="fn" select="$args/value/malval/lvalue/malval[2]"></xsl:variable>
+ <xsl:variable name="newlist">
+ <value>
+ <malval kind="list">
+ <lvalue>
+ <xsl:sequence select="$fn"/>
+ <xsl:sequence select="$atom-value"/>
+ <xsl:sequence select="$args/value/malval/lvalue/malval[position() > 2]"/>
+ </lvalue>
+ </malval>
+ </value>
+ <xsl:sequence select="$atoms"/>
+ </xsl:variable>
+ <xsl:variable name="newv">
+ <xsl:for-each select="$newlist">
+ <xsl:call-template name="EVAL"><xsl:with-param name="env" select="$env"/></xsl:call-template>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:sequence select="$newv/data/value"/>
+ <atoms>
+ <xsl:for-each select="$newv/atoms/atom[@identity != $atom-ident]">
+ <xsl:sequence select="."/>
+ </xsl:for-each>
+ <atom identity="{$atom-ident}">
+ <xsl:sequence select="$newv/data/value/malval"/>
+ </atom>
+ </atoms>
+ <xsl:sequence select="$newv/env"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="core-apply"><xsl:with-param name="func" select="$func"/><xsl:with-param name="args" select="$args"/></xsl:call-template>
+ <xsl:sequence select="$atoms"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:for-each select="$resultv">
+ <xsl:choose>
+ <xsl:when test="empty(env)">
+ <env data="{env:serialise($env)}" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:sequence select="env"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:sequence select="atoms"/>
+ <xsl:sequence select="value"/>
+ </xsl:for-each>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="eval_ast"><xsl:with-param name="env" select="$env"/></xsl:call-template>
+ <env data="{env:serialise($env)}" />
+ <xsl:sequence select="$atoms"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <data><xsl:sequence select="$data/value"/></data>
+ <env data="{$data/env/@data}" />
+ <xsl:sequence select="$data/atoms"/>
+ </xsl:template>
+
+ <xsl:template name="READ">
+ <xsl:variable name="context">
+ <str>
+ <xsl:copy-of select="stdin/text()" />
+ </str>
+ </xsl:variable>
+ <xsl:variable name="form">
+ <xsl:sequence select="state/atoms"/>
+ <xsl:for-each select="$context">
+ <xsl:call-template name="malreader-read_str"></xsl:call-template>
+ </xsl:for-each>
+ </xsl:variable>
+ <xsl:for-each select="$form">
+ <xsl:if test="error">
+ <xsl:message terminate="yes">
+ <xsl:value-of select="error" />
+ </xsl:message>
+ </xsl:if>
+ <xsl:sequence select="." />
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:function name="fn:group_consec">
+ <xsl:param name="nodes" />
+ <xsl:variable name="groups">
+ <xsl:for-each-group select="$nodes" group-by="position() mod 2">
+ <xsl:choose>
+ <xsl:when test="position() = 1">
+ <first>
+ <xsl:sequence select="current-group()"/>
+ </first>
+ </xsl:when>
+ <xsl:otherwise>
+ <second>
+ <xsl:sequence select="current-group()"/>
+ </second>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each-group>
+ </xsl:variable>
+ <xsl:iterate select="1 to count($groups/first/*)">
+ <element>
+ <xsl:variable name="idx" select="number(.)"></xsl:variable>
+ <first><xsl:sequence select="$groups/first/node()[position() = $idx]"/></first>
+ <second><xsl:sequence select="$groups/second/node()[position() = $idx]"/></second>
+ </element>
+ </xsl:iterate>
+ </xsl:function>
+</xsl:stylesheet>