1
1
mirror of https://github.com/kanaka/mal.git synced 2024-10-26 14:22:25 +03:00

attempt to speed execution up

by booting up multiple instancees of saxon, waiting for a signal
This doesn't really help much, since most of our tests are very small
however, it does lower the overall boot time (assuming travis can do
real concurrency)
This commit is contained in:
AnotherTest 2020-02-29 18:00:00 +03:30
parent 73e80a3974
commit e4882d7d71
21 changed files with 5826 additions and 5610 deletions

View File

@ -5,6 +5,8 @@ import sys
import xml.etree.ElementTree as ET
from threading import Thread
from threading import Lock
from collections import deque
from multiprocessing import Process, Queue
fname = sys.argv[1]
args = sys.argv[2:]
@ -30,88 +32,142 @@ except:
finished = False
sem = Lock()
init_t = time.time() * 1000
def setup_request_file():
process_pool_count = 1 if len(args) > 0 else 4 # we don't need a process pool when running a single file
process_pool = None
class SaxonProcess:
def __init__(self, pid, xsl):
self.pid = pid
self.command = f'saxon -xsl:{xsl} -s:xslt_input.xml process_id={pid} > xslt_output-{pid}.xml 2> xsl_error-{pid}.xml'
self.process = None
self.interpreter = Thread(target=self.interpret).start()
self.reboot()
def reboot(self):
if self.process is not None and self.process.is_alive():
self.process.kill()
self.queue = Queue(1)
self.process = Process(target=self.boot)
self.process.start()
def interpret(self):
while not finished:
try:
with open(f'xsl_error-{self.pid}.xml', 'r') as f:
xtree = ET.fromstring(f.read().strip('\x00'))
# stdout.write(xtree.attrib['kind'])
req = xtree
if req is not None:
if req.attrib['kind'] == 'readline':
stdout.write(req.attrib['value'])
x = input()
with open('xsl_input-string', 'w') as fx:
fx.write(x)
# stdout.write(' = ' + x)
elif req.attrib['kind'] == 'display':
x = req.attrib['value']
# stdout.write(' = ' + x)
stdout.write(x + '\n')
elif req.attrib['kind'] == 'time':
x = time.time() * 1000 - init_t
# stdout.write(' = ' + str(int(x)))
with open('xsl_input-string', 'w') as fx:
fx.write(str(int(x)))
# stdout.write('\n')
elif req.attrib['kind'] == 'xpath-eval':
xpath = req.attrib['value']
with open('xsl-eval.xslt', 'w') as f:
f.write(f'<?xml version="1.0" encoding="UTF-8"?><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" xmlns:core="CORE" exclude-result-prefixes="env core xs xsl map fn"><xsl:output omit-xml-declaration="yes"/><xsl:template match="/"><xsl:sequence select="{xpath}" /></xsl:template></xsl:stylesheet>')
with open('xsl-null.xml', 'w') as f:
f.write(req.attrib['context'])
if os.system(f'saxon -xsl:xsl-eval.xslt -s:xsl-null.xml > xsl-eval_output.xml'):
x = ''
else:
with open('xsl-eval_output.xml', 'r') as f:
x = f.read()
with open('xsl_input-string', 'w') as fx:
fx.write(x)
# stdout.write('\n')
except Exception as e:
# if str(e) != 'no element found: line 1, column 0':
# f.seek(0)
# print(e, list(x for x in f.read()))
continue
with open(f'xsl_error-{self.pid}.xml', 'w') as f:
f.write('')
def boot(self):
self.queue.put(os.system(self.command))
def exit(self):
self.process.kill()
def execute(self, tree, on_complete):
tree.write(f'process-input-{self.pid}.xml')
with open(f'process-lock-{self.pid}', 'w') as f:
f.write('go')
self.process.join()
os.system(f"mv xsl_error-{self.pid}.xml xsl_error.xml")
os.system(f"mv xslt_output-{self.pid}.xml xslt_output.xml")
return on_complete(self.queue.get())
class SaxonProcessPool:
def __init__(self, procs: iter):
self.pool = deque(procs)
def acquire(self):
if len(self.pool) == 0:
raise Exception("Process Pool empty, magic?")
proc = self.pool.pop()
return proc
def release(self, proc):
proc.reboot()
self.pool.appendleft(proc)
def exit(self):
for proc in self.pool:
proc.exit()
def setup_request_file(step):
global process_pool
os.system('rm -rf xsl_input-string')
os.system('mkfifo xsl_input-string')
for i in range(process_pool_count):
os.system(f'rm -rf process-lock-{i}')
os.system(f'mkfifo process-lock-{i}')
process_pool = SaxonProcessPool(SaxonProcess(pid=i, xsl=step) for i in range(process_pool_count))
def serve_one_request():
with open('xsl_error.xml', 'r') as f:
try:
xtree = ET.fromstring(f.read().strip('\x00'))
# stdout.write(xtree.attrib['kind'])
req = xtree
if req is not None:
if req.attrib['kind'] == 'readline':
stdout.write(req.attrib['value'])
x = input()
with open('xsl_input-string', 'w') as fx:
fx.write(x)
# stdout.write(' = ' + x)
elif req.attrib['kind'] == 'display':
x = req.attrib['value']
# stdout.write(' = ' + x)
stdout.write(x + '\n')
elif req.attrib['kind'] == 'time':
x = time.time() * 1000 - init_t
# stdout.write(' = ' + str(int(x)))
with open('xsl_input-string', 'w') as fx:
fx.write(str(int(x)))
# stdout.write('\n')
elif req.attrib['kind'] == 'xpath-eval':
xpath = req.attrib['value']
with open('xsl-eval.xslt', 'w') as f:
f.write(f'<?xml version="1.0" encoding="UTF-8"?><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" xmlns:core="CORE" exclude-result-prefixes="env core xs xsl map fn"><xsl:output omit-xml-declaration="yes"/><xsl:template match="/"><xsl:sequence select="{xpath}" /></xsl:template></xsl:stylesheet>')
with open('xsl-null.xml', 'w') as f:
f.write(req.attrib['context'])
if os.system(f'saxon -xsl:xsl-eval.xslt -s:xsl-null.xml > xsl-eval_output.xml'):
x = ''
else:
with open('xsl-eval_output.xml', 'r') as f:
x = f.read()
with open('xsl_input-string', 'w') as fx:
fx.write(x)
# stdout.write('\n')
except Exception as e:
# if str(e) != 'no element found: line 1, column 0':
# f.seek(0)
# print(e, list(x for x in f.read()))
return
with open('xsl_error.xml', 'w') as f:
f.write('')
def serve_requests():
global finished
setup_request_file()
while not finished:
try:
serve_one_request()
except Exception as e:
# print(e)
pass
th = Thread(target=serve_requests)
th.start()
setup_request_file(fname)
def transform(do_print=True):
global tree
tree.write('xslt_input.xml')
if os.system(f'saxon -xsl:"{fname}" -s:xslt_input.xml -TP:perf.html > xslt_output.xml 2> xsl_error.xml'):
with open('xsl_error.xml', 'r') as f:
lines = f.readlines()
if len(lines):
print('Error:', [x for x in lines if x.strip() != ''][-1], end='')
return
else:
try:
def on_completion(exit_code):
if exit_code:
with open('xsl_error.xml', 'r') as f:
print(f.read(), end='')
except:
# nothing interesting happened
# HOW?
pass
lines = f.readlines()
if len(lines):
print('Error:', [x for x in lines if x.strip() != ''][-1], end='')
return False
else:
try:
with open('xsl_error.xml', 'r') as f:
print(f.read(), end='')
except:
pass
return True
proc = process_pool.acquire()
ok = proc.execute(tree, on_completion)
process_pool.release(proc)
if not ok:
return
tree = ET.parse('xslt_output.xml')
if do_print:
@ -155,4 +211,4 @@ else:
readline.write_history_file('.xslt_mal_history')
finished = True
th.join()
process_pool.exit()

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Step 0: REPL -->
<!-- input document must be in the following format -->
<!--
<mal>
<stdin>...stdin text...</stdin>
<stdout> ... ignored, omitted ... </stdout>
<state> ignored, preserved </state>
</mal>
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="mal" name="rep">
<mal>
<stdin/>
<!-- clear stdin -->
<xsl:copy-of select="state"/>
<!-- preserve state -->
<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:for-each>
</xsl:variable>
<stdout>
<xsl:for-each select="$_eval">
<xsl:call-template name="PRINT"/>
</xsl:for-each>
</stdout>
</mal>
</xsl:template>
<xsl:template name="PRINT">
<xsl:sequence select="."/>
</xsl:template>
<xsl:template name="EVAL">
<xsl:sequence select="."/>
</xsl:template>
<xsl:template name="READ">
<xsl:copy-of select="stdin/text()"/>
</xsl:template>
</xsl:stylesheet>

View File

@ -1,43 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Step 0: REPL -->
<!-- input document must be in the following format -->
<!--
<mal>
<stdin>...stdin text...</stdin>
<stdout> ... ignored, omitted ... </stdout>
<state> ignored, preserved </state>
</mal>
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="mal" name="rep">
<mal>
<stdin/>
<!-- clear stdin -->
<xsl:copy-of select="state"/>
<!-- preserve state -->
<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:for-each>
</xsl:variable>
<stdout>
<xsl:for-each select="$_eval">
<xsl:call-template name="PRINT"/>
</xsl:for-each>
</stdout>
</mal>
</xsl:template>
<xsl:template name="PRINT">
<xsl:sequence select="."/>
</xsl:template>
<xsl:template name="EVAL">
<xsl:sequence select="."/>
</xsl:template>
<xsl:template name="READ">
<xsl:copy-of select="stdin/text()"/>
</xsl:template>
</xsl:stylesheet>
<!-- A way to keep a process waiting until we signal it -->
<!-- In order to have a process pool that executes our queries faster -->
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="step0_repl.inc.xslt"></xsl:import>
<xsl:param name="process_id" required="yes"/>
<xsl:template match="/">
<xsl:variable name="uri" select="concat('process-input-', $process_id, '.xml')"></xsl:variable>
<xsl:variable name="_lock" select="unparsed-text(concat('process-lock-', $process_id))"></xsl:variable>
<!-- use _lock to trick the runtime -->
<xsl:variable name="ctx" select="doc(concat($uri, substring($_lock, 0, 0)))"/>
<xsl:for-each select="$ctx/mal">
<xsl:call-template name="rep"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Step 1: Read-Print -->
<!-- input document must be in the following format -->
<!--
<mal>
<stdin>...stdin text...</stdin>
<stdout> ... ignored, omitted ... </stdout>
<state> ignored, preserved </state>
</mal>
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
<xsl:import href="reader.xslt"/>
<xsl:import href="printer.xslt"/>
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="mal" name="rep">
<mal>
<stdin/>
<!-- clear stdin -->
<xsl:copy-of select="state"/>
<!-- preserve state -->
<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:for-each>
</xsl:variable>
<stdout>
<xsl:for-each select="$_eval">
<xsl:call-template name="PRINT"/>
</xsl:for-each>
</stdout>
</mal>
</xsl:template>
<xsl:template name="PRINT">
<xsl:variable name="context">
<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:variable>
<xsl:for-each select="$context">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
<xsl:template name="EVAL">
<xsl:copy-of select="."/>
</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:for-each select="$context">
<xsl:call-template name="malreader-read_str"/>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$form">
<xsl:if test="error">
<xsl:value-of select="error(QName('MAL', 'Error'), string(error))"/>
</xsl:if>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

View File

@ -1,70 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Step 1: Read-Print -->
<!-- input document must be in the following format -->
<!--
<mal>
<stdin>...stdin text...</stdin>
<stdout> ... ignored, omitted ... </stdout>
<state> ignored, preserved </state>
</mal>
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
<xsl:import href="reader.xslt"/>
<xsl:import href="printer.xslt"/>
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="mal" name="rep">
<mal>
<stdin/>
<!-- clear stdin -->
<xsl:copy-of select="state"/>
<!-- preserve state -->
<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:for-each>
</xsl:variable>
<stdout>
<xsl:for-each select="$_eval">
<xsl:call-template name="PRINT"/>
</xsl:for-each>
</stdout>
</mal>
</xsl:template>
<xsl:template name="PRINT">
<xsl:variable name="context">
<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:variable>
<xsl:for-each select="$context">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
<xsl:template name="EVAL">
<xsl:copy-of select="."/>
</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:for-each select="$context">
<xsl:call-template name="malreader-read_str"/>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$form">
<xsl:if test="error">
<xsl:value-of select="error(QName('MAL', 'Error'), string(error))"/>
</xsl:if>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
<!-- A way to keep a process waiting until we signal it -->
<!-- In order to have a process pool that executes our queries faster -->
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="step1_read_print.inc.xslt"></xsl:import>
<xsl:param name="process_id" required="yes"/>
<xsl:template match="/">
<xsl:variable name="uri" select="concat('process-input-', $process_id, '.xml')"></xsl:variable>
<xsl:variable name="_lock" select="unparsed-text(concat('process-lock-', $process_id))"></xsl:variable>
<!-- use _lock to trick the runtime -->
<xsl:variable name="ctx" select="doc(concat($uri, substring($_lock, 0, 0)))"/>
<xsl:for-each select="$ctx/mal">
<xsl:call-template name="rep"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,253 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Step 2: Eval -->
<!-- input document must be in the following format -->
<!--
<mal>
<stdin>...stdin text...</stdin>
<stdout> ... ignored, omitted ... </stdout>
<state> ignored, preserved </state>
</mal>
-->
<xsl:stylesheet 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" version="3.0" 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:template match="mal" name="rep">
<mal>
<xsl:variable name="env" as="map(*)">
<xsl:if test="not(state)">
<!-- we never update this -->
<xsl:map>
<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"/>
<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="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'">
<value>
<xsl:sequence select="fn:env_lookup($env, value/malval/@value)"/>
</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: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: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: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: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: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:for-each>
</lvalue>
</malval>
</value>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="."/>
</xsl:otherwise>
</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: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: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: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: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: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:variable name="context">
<str>
<xsl:copy-of select="stdin/text()"/>
</str>
</xsl:variable>
<xsl:variable name="form">
<xsl:for-each select="$context">
<xsl:call-template name="malreader-read_str"/>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$form">
<xsl:if test="error">
<xsl:value-of select="error(QName('MAL', 'Error'), string(error))"/>
</xsl:if>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
<xsl:function name="fn:env_lookup">
<xsl:param name="env"/>
<xsl:param name="name"/>
<xsl:variable name="value">
<xsl:sequence select="$env(string($name))"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$value != ''">
<malval kind="nfunction" name="{$name}">
<xsl:sequence select="$value"/>
</malval>
</xsl:when>
<xsl:otherwise>
<malval kind="nil"/>
</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>

View File

@ -1,253 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Step 2: Eval -->
<!-- input document must be in the following format -->
<!--
<mal>
<stdin>...stdin text...</stdin>
<stdout> ... ignored, omitted ... </stdout>
<state> ignored, preserved </state>
</mal>
-->
<xsl:stylesheet 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" version="3.0" 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:template match="mal" name="rep">
<mal>
<xsl:variable name="env" as="map(*)">
<xsl:if test="not(state)">
<!-- we never update this -->
<xsl:map>
<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"/>
<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="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'">
<value>
<xsl:sequence select="fn:env_lookup($env, value/malval/@value)"/>
</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: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: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: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: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: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:for-each>
</lvalue>
</malval>
</value>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="."/>
</xsl:otherwise>
</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: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: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: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: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: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:variable name="context">
<str>
<xsl:copy-of select="stdin/text()"/>
</str>
</xsl:variable>
<xsl:variable name="form">
<xsl:for-each select="$context">
<xsl:call-template name="malreader-read_str"/>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$form">
<xsl:if test="error">
<xsl:value-of select="error(QName('MAL', 'Error'), string(error))"/>
</xsl:if>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
<xsl:function name="fn:env_lookup">
<xsl:param name="env"/>
<xsl:param name="name"/>
<xsl:variable name="value">
<xsl:sequence select="$env(string($name))"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$value != ''">
<malval kind="nfunction" name="{$name}">
<xsl:sequence select="$value"/>
</malval>
</xsl:when>
<xsl:otherwise>
<malval kind="nil"/>
</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>
<!-- A way to keep a process waiting until we signal it -->
<!-- In order to have a process pool that executes our queries faster -->
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="step2_eval.inc.xslt"></xsl:import>
<xsl:param name="process_id" required="yes"/>
<xsl:template match="/">
<xsl:variable name="uri" select="concat('process-input-', $process_id, '.xml')"></xsl:variable>
<xsl:variable name="_lock" select="unparsed-text(concat('process-lock-', $process_id))"></xsl:variable>
<!-- use _lock to trick the runtime -->
<xsl:variable name="ctx" select="doc(concat($uri, substring($_lock, 0, 0)))"/>
<xsl:for-each select="$ctx/mal">
<xsl:call-template name="rep"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,369 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Step 3: Environment -->
<!-- input document must be in the following format -->
<!--
<mal>
<stdin>...stdin text...</stdin>
<stdout> ... ignored, omitted ... </stdout>
<state> contains env </state>
</mal>
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:env="ENV" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:map="http://www.w3.org/2005/xpath-functions/map" version="3.0" exclude-result-prefixes="fn xs map env">
<xsl:import href="reader.xslt"/>
<xsl:import href="printer.xslt"/>
<xsl:import href="env.xslt"/>
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="mal" name="rep">
<mal>
<xsl:variable name="env" as="map(*)">
<xsl:sequence select="env:deserialise((state/env/@data, env:base())[1])"/>
</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:for-each select="data">
<xsl:call-template name="PRINT"/>
</xsl:for-each>
</stdout>
<state>
<env data="{env/@data}"/>
</state>
</xsl:for-each>
</mal>
</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:with-param name="encode-env" select="false()"/>
</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:with-param name="encode-env" select="false()"/>
</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:with-param name="encode-env" select="false()"/>
</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>
<!-- vapply[fn, args] :: fn/value/text() -->
<xsl:template name="vapply">
<xsl:param name="func"/>
<xsl:param name="args"/>
<xsl:choose>
<xsl:when test="$func/malval/@kind = 'function'">
<xsl:choose>
<xsl:when test="$func/malval/@name = '+'">
<xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) + number($args/value/malval/lvalue/malval[2]/@value)"/>
<xsl:sequence select="fn:makeMALType($result, 'number')"/>
</xsl:when>
<xsl:when test="$func/malval/@name = '-'">
<xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) - number($args/value/malval/lvalue/malval[2]/@value)"/>
<xsl:sequence select="fn:makeMALType($result, 'number')"/>
</xsl:when>
<xsl:when test="$func/malval/@name = '*'">
<xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) * number($args/value/malval/lvalue/malval[2]/@value)"/>
<xsl:sequence select="fn:makeMALType($result, 'number')"/>
</xsl:when>
<xsl:when test="$func/malval/@name = '/'">
<xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) div number($args/value/malval/lvalue/malval[2]/@value)"/>
<xsl:sequence select="fn:makeMALType($result, 'number')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="error(QName('MAL', 'Error'), concat('Invalid function ', $func))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:template>
<xsl:template name="EVAL">
<xsl:param name="env"/>
<xsl:param name="encode-env" select="true()"/>
<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="."/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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:variable>
<xsl:variable name="value">
<xsl:for-each select="$xvalue">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:set($env, $name, $value/data/value/malval))}"/>
</xsl:if>
</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:variable>
<xsl:variable name="new_env" select="env:close($env)"/>
<xsl:iterate select="fn:group_consec(value/malval/lvalue/malval[2]/lvalue/malval)">
<xsl:param name="new_env" select="$env"/>
<xsl:on-completion>
<xsl:variable name="value">
<xsl:for-each select="$xvalue">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$new_env"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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:variable>
<xsl:variable name="value">
<xsl:for-each select="$xvalue">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$new_env"/>
<xsl:with-param name="encode-env" select="false()"/>
</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:next-iteration>
</xsl:iterate>
</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: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:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<data>
<xsl:sequence select="$data/value"/>
</data>
<xsl:if test="$encode-env">
<env data="{$data/env/@data}"/>
</xsl:if>
</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:for-each select="$context">
<xsl:call-template name="malreader-read_str"/>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$form">
<xsl:if test="error">
<xsl:value-of select="error(QName('MAL', 'Error'), string(error))"/>
</xsl:if>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
<xsl:function name="fn:makeMALType">
<xsl:param name="value"/>
<xsl:param name="kind"/>
<value>
<malval kind="{$kind}" value="{$value}"/>
</value>
</xsl:function>
<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(.)"/>
<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>

View File

@ -1,369 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Step 3: Environment -->
<!-- input document must be in the following format -->
<!--
<mal>
<stdin>...stdin text...</stdin>
<stdout> ... ignored, omitted ... </stdout>
<state> contains env </state>
</mal>
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:env="ENV" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:map="http://www.w3.org/2005/xpath-functions/map" version="3.0" exclude-result-prefixes="fn xs map env">
<xsl:import href="reader.xslt"/>
<xsl:import href="printer.xslt"/>
<xsl:import href="env.xslt"/>
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="mal" name="rep">
<mal>
<xsl:variable name="env" as="map(*)">
<xsl:sequence select="env:deserialise((state/env/@data, env:base())[1])"/>
</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:for-each select="data">
<xsl:call-template name="PRINT"/>
</xsl:for-each>
</stdout>
<state>
<env data="{env/@data}"/>
</state>
</xsl:for-each>
</mal>
</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:with-param name="encode-env" select="false()"/>
</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:with-param name="encode-env" select="false()"/>
</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:with-param name="encode-env" select="false()"/>
</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>
<!-- vapply[fn, args] :: fn/value/text() -->
<xsl:template name="vapply">
<xsl:param name="func"/>
<xsl:param name="args"/>
<xsl:choose>
<xsl:when test="$func/malval/@kind = 'function'">
<xsl:choose>
<xsl:when test="$func/malval/@name = '+'">
<xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) + number($args/value/malval/lvalue/malval[2]/@value)"/>
<xsl:sequence select="fn:makeMALType($result, 'number')"/>
</xsl:when>
<xsl:when test="$func/malval/@name = '-'">
<xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) - number($args/value/malval/lvalue/malval[2]/@value)"/>
<xsl:sequence select="fn:makeMALType($result, 'number')"/>
</xsl:when>
<xsl:when test="$func/malval/@name = '*'">
<xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) * number($args/value/malval/lvalue/malval[2]/@value)"/>
<xsl:sequence select="fn:makeMALType($result, 'number')"/>
</xsl:when>
<xsl:when test="$func/malval/@name = '/'">
<xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) div number($args/value/malval/lvalue/malval[2]/@value)"/>
<xsl:sequence select="fn:makeMALType($result, 'number')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="error(QName('MAL', 'Error'), concat('Invalid function ', $func))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise/>
</xsl:choose>
</xsl:template>
<xsl:template name="EVAL">
<xsl:param name="env"/>
<xsl:param name="encode-env" select="true()"/>
<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="."/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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:variable>
<xsl:variable name="value">
<xsl:for-each select="$xvalue">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:set($env, $name, $value/data/value/malval))}"/>
</xsl:if>
</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:variable>
<xsl:variable name="new_env" select="env:close($env)"/>
<xsl:iterate select="fn:group_consec(value/malval/lvalue/malval[2]/lvalue/malval)">
<xsl:param name="new_env" select="$env"/>
<xsl:on-completion>
<xsl:variable name="value">
<xsl:for-each select="$xvalue">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$new_env"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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:variable>
<xsl:variable name="value">
<xsl:for-each select="$xvalue">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$new_env"/>
<xsl:with-param name="encode-env" select="false()"/>
</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:next-iteration>
</xsl:iterate>
</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: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:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<data>
<xsl:sequence select="$data/value"/>
</data>
<xsl:if test="$encode-env">
<env data="{$data/env/@data}"/>
</xsl:if>
</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:for-each select="$context">
<xsl:call-template name="malreader-read_str"/>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$form">
<xsl:if test="error">
<xsl:value-of select="error(QName('MAL', 'Error'), string(error))"/>
</xsl:if>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
<xsl:function name="fn:makeMALType">
<xsl:param name="value"/>
<xsl:param name="kind"/>
<value>
<malval kind="{$kind}" value="{$value}"/>
</value>
</xsl:function>
<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(.)"/>
<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>
<!-- A way to keep a process waiting until we signal it -->
<!-- In order to have a process pool that executes our queries faster -->
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="step3_env.inc.xslt"></xsl:import>
<xsl:param name="process_id" required="yes"/>
<xsl:template match="/">
<xsl:variable name="uri" select="concat('process-input-', $process_id, '.xml')"></xsl:variable>
<xsl:variable name="_lock" select="unparsed-text(concat('process-lock-', $process_id))"></xsl:variable>
<!-- use _lock to trick the runtime -->
<xsl:variable name="ctx" select="doc(concat($uri, substring($_lock, 0, 0)))"/>
<xsl:for-each select="$ctx/mal">
<xsl:call-template name="rep"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,503 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Step 4: If Fn Do -->
<!-- input document must be in the following format -->
<!--
<mal>
<stdin>...stdin text...</stdin>
<stdout> ... ignored, omitted ... </stdout>
<state> contains env </state>
</mal>
-->
<xsl:stylesheet 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" version="3.0" 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="vstate">
<mal>
<state>
<env data="{env:serialise(env:empty() =&gt; env:bind-all(core:ns()/@name, core:ns()))}"/>
</state>
<stdin>(def! not (fn* (a) (if a false true)))</stdin>
</mal>
</xsl:variable>
<xsl:variable name="new-state">
<xsl:for-each select="$vstate/mal">
<xsl:call-template name="rep"/>
</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: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:for-each select="data">
<xsl:call-template name="PRINT"/>
</xsl:for-each>
</stdout>
<state>
<env data="{env/@data}"/>
</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:with-param name="encode-env" select="false()"/>
</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:with-param name="encode-env" select="false()"/>
</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:with-param name="encode-env" select="false()"/>
</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 =&gt; env:hier(env:deserialise($func/malval/env/@data)) =&gt; 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:variable>
<xsl:variable name="result">
<xsl:for-each select="$body">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$nenv"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$result/data/value"/>
</xsl:template>
<xsl:template name="EVAL">
<xsl:param name="env"/>
<xsl:param name="encode-env" select="true()"/>
<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="."/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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:variable>
<xsl:variable name="value">
<xsl:for-each select="$xvalue">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:set($env, $name, $value/data/value/malval))}"/>
</xsl:if>
</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:variable>
<xsl:variable name="new_env" select="env:close($env)"/>
<xsl:iterate select="fn:group_consec(value/malval/lvalue/malval[2]/lvalue/malval)">
<xsl:param name="new_env" select="$env"/>
<xsl:on-completion>
<xsl:variable name="value">
<xsl:for-each select="$xvalue">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$new_env"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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:variable>
<xsl:variable name="value">
<xsl:for-each select="$xvalue">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$new_env"/>
<xsl:with-param name="encode-env" select="$encode-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: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() &gt; 1]">
<xsl:param name="new_env" select="$env"/>
<xsl:param name="previous_res" select="()"/>
<xsl:on-completion>
<xsl:sequence select="$previous_res"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($new_env)}"/>
</xsl:if>
</xsl:on-completion>
<xsl:variable name="xvalue">
<value>
<xsl:sequence select="."/>
</value>
</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:with-param name="encode-env" select="true()"/>
</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: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:variable>
<xsl:for-each select="$context">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="false()"/>
</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:for-each>
</xsl:variable>
<xsl:variable name="pfalse">
<xsl:for-each select="value/malval/lvalue/malval[4]">
<value>
<xsl:sequence select="."/>
</value>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="xfalse">
<xsl:choose>
<xsl:when test="empty($pfalse/value)">
<value>
<malval kind="nil"/>
</value>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$pfalse/value"/>
</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:with-param name="encode-env" select="$encode-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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:sequence select="$res/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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)}"/>
<!-- capture current env -->
</malval>
</value>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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:for-each>
</xsl:variable>
<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:call-template name="core-apply">
<xsl:with-param name="func" select="$func"/>
<xsl:with-param name="args" select="$args"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<data>
<xsl:sequence select="$data/value"/>
</data>
<xsl:if test="$encode-env">
<env data="{$data/env/@data}"/>
</xsl:if>
</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:for-each select="$context">
<xsl:call-template name="malreader-read_str"/>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$form">
<xsl:if test="error">
<xsl:value-of select="error(QName('MAL', 'Error'), string(error))"/>
</xsl:if>
<xsl:copy-of 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(.)"/>
<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>

View File

@ -1,503 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Step 4: If Fn Do -->
<!-- input document must be in the following format -->
<!--
<mal>
<stdin>...stdin text...</stdin>
<stdout> ... ignored, omitted ... </stdout>
<state> contains env </state>
</mal>
-->
<xsl:stylesheet 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" version="3.0" 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="vstate">
<mal>
<state>
<env data="{env:serialise(env:empty() =&gt; env:bind-all(core:ns()/@name, core:ns()))}"/>
</state>
<stdin>(def! not (fn* (a) (if a false true)))</stdin>
</mal>
</xsl:variable>
<xsl:variable name="new-state">
<xsl:for-each select="$vstate/mal">
<xsl:call-template name="rep"/>
</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: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:for-each select="data">
<xsl:call-template name="PRINT"/>
</xsl:for-each>
</stdout>
<state>
<env data="{env/@data}"/>
</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:with-param name="encode-env" select="false()"/>
</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:with-param name="encode-env" select="false()"/>
</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:with-param name="encode-env" select="false()"/>
</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 =&gt; env:hier(env:deserialise($func/malval/env/@data)) =&gt; 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:variable>
<xsl:variable name="result">
<xsl:for-each select="$body">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$nenv"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$result/data/value"/>
</xsl:template>
<xsl:template name="EVAL">
<xsl:param name="env"/>
<xsl:param name="encode-env" select="true()"/>
<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="."/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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:variable>
<xsl:variable name="value">
<xsl:for-each select="$xvalue">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:set($env, $name, $value/data/value/malval))}"/>
</xsl:if>
</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:variable>
<xsl:variable name="new_env" select="env:close($env)"/>
<xsl:iterate select="fn:group_consec(value/malval/lvalue/malval[2]/lvalue/malval)">
<xsl:param name="new_env" select="$env"/>
<xsl:on-completion>
<xsl:variable name="value">
<xsl:for-each select="$xvalue">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$new_env"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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:variable>
<xsl:variable name="value">
<xsl:for-each select="$xvalue">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$new_env"/>
<xsl:with-param name="encode-env" select="$encode-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: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() &gt; 1]">
<xsl:param name="new_env" select="$env"/>
<xsl:param name="previous_res" select="()"/>
<xsl:on-completion>
<xsl:sequence select="$previous_res"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($new_env)}"/>
</xsl:if>
</xsl:on-completion>
<xsl:variable name="xvalue">
<value>
<xsl:sequence select="."/>
</value>
</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:with-param name="encode-env" select="true()"/>
</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: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:variable>
<xsl:for-each select="$context">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="false()"/>
</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:for-each>
</xsl:variable>
<xsl:variable name="pfalse">
<xsl:for-each select="value/malval/lvalue/malval[4]">
<value>
<xsl:sequence select="."/>
</value>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="xfalse">
<xsl:choose>
<xsl:when test="empty($pfalse/value)">
<value>
<malval kind="nil"/>
</value>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$pfalse/value"/>
</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:with-param name="encode-env" select="$encode-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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:sequence select="$res/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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)}"/>
<!-- capture current env -->
</malval>
</value>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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:for-each>
</xsl:variable>
<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:call-template name="core-apply">
<xsl:with-param name="func" select="$func"/>
<xsl:with-param name="args" select="$args"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<data>
<xsl:sequence select="$data/value"/>
</data>
<xsl:if test="$encode-env">
<env data="{$data/env/@data}"/>
</xsl:if>
</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:for-each select="$context">
<xsl:call-template name="malreader-read_str"/>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$form">
<xsl:if test="error">
<xsl:value-of select="error(QName('MAL', 'Error'), string(error))"/>
</xsl:if>
<xsl:copy-of 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(.)"/>
<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>
<!-- A way to keep a process waiting until we signal it -->
<!-- In order to have a process pool that executes our queries faster -->
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="step4_if_fn_do.inc.xslt"></xsl:import>
<xsl:param name="process_id" required="yes"/>
<xsl:template match="/">
<xsl:variable name="uri" select="concat('process-input-', $process_id, '.xml')"></xsl:variable>
<xsl:variable name="_lock" select="unparsed-text(concat('process-lock-', $process_id))"></xsl:variable>
<!-- use _lock to trick the runtime -->
<xsl:variable name="ctx" select="doc(concat($uri, substring($_lock, 0, 0)))"/>
<xsl:for-each select="$ctx/mal">
<xsl:call-template name="rep"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,628 @@
<?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 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" version="3.0" 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() =&gt; env:bind-all(core:ns()/@name, core:ns()) =&gt; env:set('*ARGV*', $argv) =&gt; env:toReplEnv())}"/>
<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: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: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: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:param name="atoms"/>
<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' or value/malval/@kind = 'vector' or value/malval/@kind = 'hash'">
<xsl:variable name="myctx">
<xsl:iterate select="value/malval/lvalue/malval">
<xsl:param name="atoms" select="$atoms"/>
<xsl:param name="xctx" select="()"/>
<xsl:on-completion>
<xsl:sequence select="$xctx/value/malval"/>
<xsl:sequence select="$atoms"/>
</xsl:on-completion>
<xsl:variable name="ctx">
<value>
<xsl:sequence select="."/>
</value>
<xsl:sequence select="$atoms"/>
</xsl:variable>
<xsl:variable name="xctxy">
<xsl:for-each select="$ctx">
<xsl:variable name="val">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:variable>
<xsl:sequence select="$val/data/value"/>
<xsl:sequence select="$val/atoms"/>
</xsl:for-each>
</xsl:variable>
<xsl:next-iteration>
<xsl:with-param name="atoms" select="$xctxy/atoms"/>
<xsl:with-param name="xctx" select="$xctx, $xctxy"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:variable>
<value>
<malval kind="{value/malval/@kind}">
<lvalue>
<xsl:sequence select="$myctx/malval"/>
</lvalue>
</malval>
</value>
<xsl:sequence select="$myctx/atoms"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="."/>
<xsl:sequence select="$atoms"/>
</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 =&gt; env:hier(env:deserialise($func/malval/env/@data)) =&gt; 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) =&gt; env:replEnv()))}"/>
<xsl:sequence select="$result/atoms"/>
</xsl:template>
<xsl:template name="EVAL">
<xsl:param name="env"/>
<xsl:param name="encode-env" select="true()"/>
<xsl:variable name="atoms" select="atoms"/>
<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="."/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<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:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:set($env, $name, $value/data/value/malval))}"/>
</xsl:if>
<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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:swap-replEnv($env, env:deserialise($value/env/@data) =&gt; env:replEnv()))}"/>
</xsl:if>
<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:with-param name="encode-env" select="false()"/>
</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() &gt; 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"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($new_env)}"/>
</xsl:if>
<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:with-param name="encode-env" select="false()"/>
</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:with-param name="encode-env" select="$encode-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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:sequence select="$res/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<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>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$atoms"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="new_list">
<xsl:call-template name="eval_ast">
<xsl:with-param name="atoms" select="$atoms"/>
<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="$new_list/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 = 'eval'">
<!-- needs access to env -->
<xsl:variable name="venv" select="env:replEnv($env)"/>
<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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:swap-replEnv($env, env:deserialise($value/env/@data)))}"/>
</xsl:if>
<xsl:sequence select="$value/atoms"/>
</xsl:when>
<xsl:when test="$func/malval/@name = 'atom'">
<!-- needs access to atoms -->
<xsl:variable name="atom-ident" select="count($atoms/atom)"/>
<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 name="newv" select="$args/value/malval/lvalue/malval[2]"/>
<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 name="atom-value" select="$atoms/atom[@identity = $atom-ident]/malval"/>
<xsl:variable name="fn" select="$args/value/malval/lvalue/malval[2]"/>
<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() &gt; 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:with-param name="encode-env" select="$encode-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:if test="$encode-env">
<xsl:sequence select="$newv/env"/>
</xsl:if>
</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)">
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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="atoms" select="$atoms"/>
<xsl:with-param name="env" select="$env"/>
</xsl:call-template>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<!-- <xsl:sequence select="$atoms"/> -->
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<data>
<xsl:sequence select="$data/value"/>
</data>
<xsl:if test="$encode-env">
<env data="{$data/env/@data}"/>
</xsl:if>
<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:for-each>
</xsl:variable>
<xsl:for-each select="$form">
<xsl:if test="error">
<xsl:value-of select="error(QName('MAL', 'Error'), string(error))"/>
</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(.)"/>
<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>

View File

@ -1,628 +1,16 @@
<?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 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" version="3.0" 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() =&gt; env:bind-all(core:ns()/@name, core:ns()) =&gt; env:set('*ARGV*', $argv) =&gt; env:toReplEnv())}"/>
<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: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: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: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:param name="atoms"/>
<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' or value/malval/@kind = 'vector' or value/malval/@kind = 'hash'">
<xsl:variable name="myctx">
<xsl:iterate select="value/malval/lvalue/malval">
<xsl:param name="atoms" select="$atoms"/>
<xsl:param name="xctx" select="()"/>
<xsl:on-completion>
<xsl:sequence select="$xctx/value/malval"/>
<xsl:sequence select="$atoms"/>
</xsl:on-completion>
<xsl:variable name="ctx">
<value>
<xsl:sequence select="."/>
</value>
<xsl:sequence select="$atoms"/>
</xsl:variable>
<xsl:variable name="xctxy">
<xsl:for-each select="$ctx">
<xsl:variable name="val">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:variable>
<xsl:sequence select="$val/data/value"/>
<xsl:sequence select="$val/atoms"/>
</xsl:for-each>
</xsl:variable>
<xsl:next-iteration>
<xsl:with-param name="atoms" select="$xctxy/atoms"/>
<xsl:with-param name="xctx" select="$xctx, $xctxy"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:variable>
<value>
<malval kind="{value/malval/@kind}">
<lvalue>
<xsl:sequence select="$myctx/malval"/>
</lvalue>
</malval>
</value>
<xsl:sequence select="$myctx/atoms"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="."/>
<xsl:sequence select="$atoms"/>
</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 =&gt; env:hier(env:deserialise($func/malval/env/@data)) =&gt; 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) =&gt; env:replEnv()))}"/>
<xsl:sequence select="$result/atoms"/>
</xsl:template>
<xsl:template name="EVAL">
<xsl:param name="env"/>
<xsl:param name="encode-env" select="true()"/>
<xsl:variable name="atoms" select="atoms"/>
<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="."/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<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:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:set($env, $name, $value/data/value/malval))}"/>
</xsl:if>
<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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:swap-replEnv($env, env:deserialise($value/env/@data) =&gt; env:replEnv()))}"/>
</xsl:if>
<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:with-param name="encode-env" select="false()"/>
</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() &gt; 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"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($new_env)}"/>
</xsl:if>
<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:with-param name="encode-env" select="false()"/>
</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:with-param name="encode-env" select="$encode-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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:sequence select="$res/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<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>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$atoms"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="new_list">
<xsl:call-template name="eval_ast">
<xsl:with-param name="atoms" select="$atoms"/>
<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="$new_list/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 = 'eval'">
<!-- needs access to env -->
<xsl:variable name="venv" select="env:replEnv($env)"/>
<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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:swap-replEnv($env, env:deserialise($value/env/@data)))}"/>
</xsl:if>
<xsl:sequence select="$value/atoms"/>
</xsl:when>
<xsl:when test="$func/malval/@name = 'atom'">
<!-- needs access to atoms -->
<xsl:variable name="atom-ident" select="count($atoms/atom)"/>
<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 name="newv" select="$args/value/malval/lvalue/malval[2]"/>
<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 name="atom-value" select="$atoms/atom[@identity = $atom-ident]/malval"/>
<xsl:variable name="fn" select="$args/value/malval/lvalue/malval[2]"/>
<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() &gt; 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:with-param name="encode-env" select="$encode-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:if test="$encode-env">
<xsl:sequence select="$newv/env"/>
</xsl:if>
</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)">
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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="atoms" select="$atoms"/>
<xsl:with-param name="env" select="$env"/>
</xsl:call-template>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<!-- <xsl:sequence select="$atoms"/> -->
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<data>
<xsl:sequence select="$data/value"/>
</data>
<xsl:if test="$encode-env">
<env data="{$data/env/@data}"/>
</xsl:if>
<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:for-each>
</xsl:variable>
<xsl:for-each select="$form">
<xsl:if test="error">
<xsl:value-of select="error(QName('MAL', 'Error'), string(error))"/>
</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(.)"/>
<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>
<!-- A way to keep a process waiting until we signal it -->
<!-- In order to have a process pool that executes our queries faster -->
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="step6_file.inc.xslt"></xsl:import>
<xsl:param name="process_id" required="yes"/>
<xsl:template match="/">
<xsl:variable name="uri" select="concat('process-input-', $process_id, '.xml')"></xsl:variable>
<xsl:variable name="_lock" select="unparsed-text(concat('process-lock-', $process_id))"></xsl:variable>
<!-- use _lock to trick the runtime -->
<xsl:variable name="ctx" select="doc(concat($uri, substring($_lock, 0, 0)))"/>
<xsl:for-each select="$ctx/mal">
<xsl:call-template name="rep"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,742 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Step 7: Quoting -->
<!-- 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 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" version="3.0" 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() =&gt; env:bind-all(core:ns()/@name, core:ns()) =&gt; env:set('*ARGV*', $argv) =&gt; env:toReplEnv())}"/>
<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: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: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: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:param name="atoms"/>
<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' or value/malval/@kind = 'vector' or value/malval/@kind = 'hash'">
<xsl:variable name="myctx">
<xsl:iterate select="value/malval/lvalue/malval">
<xsl:param name="atoms" select="$atoms"/>
<xsl:param name="xctx" select="()"/>
<xsl:on-completion>
<xsl:sequence select="$xctx/value/malval"/>
<xsl:sequence select="$atoms"/>
</xsl:on-completion>
<xsl:variable name="ctx">
<value>
<xsl:sequence select="."/>
</value>
<xsl:sequence select="$atoms"/>
</xsl:variable>
<xsl:variable name="xctxy">
<xsl:for-each select="$ctx">
<xsl:variable name="val">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:variable>
<xsl:sequence select="$val/data/value"/>
<xsl:sequence select="$val/atoms"/>
</xsl:for-each>
</xsl:variable>
<xsl:next-iteration>
<xsl:with-param name="atoms" select="$xctxy/atoms"/>
<xsl:with-param name="xctx" select="$xctx, $xctxy"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:variable>
<value>
<malval kind="{value/malval/@kind}">
<lvalue>
<xsl:sequence select="$myctx/malval"/>
</lvalue>
</malval>
</value>
<xsl:sequence select="$myctx/atoms"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="."/>
<xsl:sequence select="$atoms"/>
</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 =&gt; env:hier(env:deserialise($func/malval/env/@data)) =&gt; 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) =&gt; env:replEnv()))}"/>
<xsl:sequence select="$result/atoms"/>
</xsl:template>
<xsl:template name="quasiquote">
<xsl:param name="ast"/>
<xsl:variable name="result">
<xsl:choose>
<xsl:when test="fn:is-pair($ast)">
<xsl:choose>
<xsl:when test="let $fst := $ast/lvalue/malval[1] return $fst/@kind = 'symbol' and $fst/@value = 'unquote'">
<xsl:sequence select="$ast/lvalue/malval[2]"/>
</xsl:when>
<xsl:when test="let $fst := $ast/lvalue/malval[1] return fn:is-pair($fst) and (let $fstfst := $fst/lvalue/malval[1] return $fstfst/@kind = 'symbol' and $fstfst/@value = 'splice-unquote')">
<malval kind="list">
<lvalue>
<malval kind="symbol" value="concat"/>
<xsl:sequence select="$ast/lvalue/malval[1]/lvalue/malval[2]"/>
<xsl:variable name="rest" select="$ast/lvalue/malval[position() &gt; 1]"/>
<xsl:variable name="rest-">
<malval kind="list">
<lvalue>
<xsl:sequence select="$rest"/>
</lvalue>
</malval>
</xsl:variable>
<xsl:call-template name="quasiquote">
<xsl:with-param name="ast" select="$rest-"/>
</xsl:call-template>
</lvalue>
</malval>
</xsl:when>
<xsl:otherwise>
<malval kind="list">
<lvalue>
<malval kind="symbol" value="cons"/>
<xsl:variable name="first" select="$ast/lvalue/malval[1]"/>
<xsl:variable name="rest" select="$ast/lvalue/malval[position() &gt; 1]"/>
<xsl:variable name="rest-">
<malval kind="list">
<lvalue>
<xsl:sequence select="$rest"/>
</lvalue>
</malval>
</xsl:variable>
<xsl:call-template name="quasiquote">
<xsl:with-param name="ast" select="$first"/>
</xsl:call-template>
<xsl:call-template name="quasiquote">
<xsl:with-param name="ast" select="$rest-/malval"/>
</xsl:call-template>
</lvalue>
</malval>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<malval kind="list">
<lvalue>
<malval kind="symbol" value="quote"/>
<xsl:sequence select="$ast"/>
</lvalue>
</malval>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:sequence select="$result"/>
</xsl:template>
<xsl:template name="EVAL">
<xsl:param name="env"/>
<xsl:param name="encode-env" select="true()"/>
<xsl:variable name="atoms" select="atoms"/>
<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="."/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<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:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:set($env, $name, $value/data/value/malval))}"/>
</xsl:if>
<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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:swap-replEnv($env, env:deserialise($value/env/@data) =&gt; env:replEnv()))}"/>
</xsl:if>
<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:with-param name="encode-env" select="false()"/>
</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() &gt; 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"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($new_env)}"/>
</xsl:if>
<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:with-param name="encode-env" select="false()"/>
</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:with-param name="encode-env" select="$encode-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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:sequence select="$res/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<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>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$atoms"/>
</xsl:when>
<xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'quote'">
<value>
<xsl:sequence select="value/malval/lvalue/malval[2]"/>
</value>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$atoms"/>
</xsl:when>
<xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'quasiquote'">
<xsl:variable name="exp">
<value>
<xsl:call-template name="quasiquote">
<xsl:with-param name="ast" select="value/malval/lvalue/malval[2]"/>
</xsl:call-template>
</value>
<xsl:sequence select="$atoms"/>
</xsl:variable>
<xsl:variable name="res">
<xsl:for-each select="$exp">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$res/data/value"/>
<xsl:if test="$encode-env">
<xsl:sequence select="$res/env"/>
</xsl:if>
<xsl:sequence select="$res/atoms"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="new_list">
<xsl:call-template name="eval_ast">
<xsl:with-param name="atoms" select="$atoms"/>
<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="$new_list/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 name="value">
<malval kind="string" value="{$env =&gt; serialize(map{'method':'json'})}"/>
</xsl:variable>
<value>
<xsl:sequence select="$value"/>
</value>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<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 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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:swap-replEnv($env, env:deserialise($value/env/@data)))}"/>
</xsl:if>
<xsl:sequence select="$value/atoms"/>
</xsl:when>
<xsl:when test="$func/malval/@name = 'atom'">
<!-- needs access to atoms -->
<xsl:variable name="atom-ident" select="count($atoms/atom)"/>
<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 name="newv" select="$args/value/malval/lvalue/malval[2]"/>
<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 name="atom-value" select="$atoms/atom[@identity = $atom-ident]/malval"/>
<xsl:variable name="fn" select="$args/value/malval/lvalue/malval[2]"/>
<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() &gt; 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:with-param name="encode-env" select="$encode-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:if test="$encode-env">
<xsl:sequence select="$newv/env"/>
</xsl:if>
</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)">
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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="atoms" select="$atoms"/>
<xsl:with-param name="env" select="$env"/>
</xsl:call-template>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<!-- <xsl:sequence select="$atoms"/> -->
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<data>
<xsl:sequence select="$data/value"/>
</data>
<xsl:if test="$encode-env">
<env data="{$data/env/@data}"/>
</xsl:if>
<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:for-each>
</xsl:variable>
<xsl:for-each select="$form">
<xsl:if test="error">
<xsl:value-of select="error(QName('MAL', 'Error'), string(error))"/>
</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(.)"/>
<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:function name="fn:is-pair">
<xsl:param name="list"/>
<xsl:sequence select="($list/@kind = 'list' or $list/@kind = 'vector') and count($list/lvalue/malval) != 0"/>
</xsl:function>
</xsl:stylesheet>

View File

@ -1,742 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Step 7: Quoting -->
<!-- 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 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" version="3.0" 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() =&gt; env:bind-all(core:ns()/@name, core:ns()) =&gt; env:set('*ARGV*', $argv) =&gt; env:toReplEnv())}"/>
<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: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: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: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:param name="atoms"/>
<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' or value/malval/@kind = 'vector' or value/malval/@kind = 'hash'">
<xsl:variable name="myctx">
<xsl:iterate select="value/malval/lvalue/malval">
<xsl:param name="atoms" select="$atoms"/>
<xsl:param name="xctx" select="()"/>
<xsl:on-completion>
<xsl:sequence select="$xctx/value/malval"/>
<xsl:sequence select="$atoms"/>
</xsl:on-completion>
<xsl:variable name="ctx">
<value>
<xsl:sequence select="."/>
</value>
<xsl:sequence select="$atoms"/>
</xsl:variable>
<xsl:variable name="xctxy">
<xsl:for-each select="$ctx">
<xsl:variable name="val">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:variable>
<xsl:sequence select="$val/data/value"/>
<xsl:sequence select="$val/atoms"/>
</xsl:for-each>
</xsl:variable>
<xsl:next-iteration>
<xsl:with-param name="atoms" select="$xctxy/atoms"/>
<xsl:with-param name="xctx" select="$xctx, $xctxy"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:variable>
<value>
<malval kind="{value/malval/@kind}">
<lvalue>
<xsl:sequence select="$myctx/malval"/>
</lvalue>
</malval>
</value>
<xsl:sequence select="$myctx/atoms"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="."/>
<xsl:sequence select="$atoms"/>
</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 =&gt; env:hier(env:deserialise($func/malval/env/@data)) =&gt; 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) =&gt; env:replEnv()))}"/>
<xsl:sequence select="$result/atoms"/>
</xsl:template>
<xsl:template name="quasiquote">
<xsl:param name="ast"/>
<xsl:variable name="result">
<xsl:choose>
<xsl:when test="fn:is-pair($ast)">
<xsl:choose>
<xsl:when test="let $fst := $ast/lvalue/malval[1] return $fst/@kind = 'symbol' and $fst/@value = 'unquote'">
<xsl:sequence select="$ast/lvalue/malval[2]"/>
</xsl:when>
<xsl:when test="let $fst := $ast/lvalue/malval[1] return fn:is-pair($fst) and (let $fstfst := $fst/lvalue/malval[1] return $fstfst/@kind = 'symbol' and $fstfst/@value = 'splice-unquote')">
<malval kind="list">
<lvalue>
<malval kind="symbol" value="concat"/>
<xsl:sequence select="$ast/lvalue/malval[1]/lvalue/malval[2]"/>
<xsl:variable name="rest" select="$ast/lvalue/malval[position() &gt; 1]"/>
<xsl:variable name="rest-">
<malval kind="list">
<lvalue>
<xsl:sequence select="$rest"/>
</lvalue>
</malval>
</xsl:variable>
<xsl:call-template name="quasiquote">
<xsl:with-param name="ast" select="$rest-"/>
</xsl:call-template>
</lvalue>
</malval>
</xsl:when>
<xsl:otherwise>
<malval kind="list">
<lvalue>
<malval kind="symbol" value="cons"/>
<xsl:variable name="first" select="$ast/lvalue/malval[1]"/>
<xsl:variable name="rest" select="$ast/lvalue/malval[position() &gt; 1]"/>
<xsl:variable name="rest-">
<malval kind="list">
<lvalue>
<xsl:sequence select="$rest"/>
</lvalue>
</malval>
</xsl:variable>
<xsl:call-template name="quasiquote">
<xsl:with-param name="ast" select="$first"/>
</xsl:call-template>
<xsl:call-template name="quasiquote">
<xsl:with-param name="ast" select="$rest-/malval"/>
</xsl:call-template>
</lvalue>
</malval>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<malval kind="list">
<lvalue>
<malval kind="symbol" value="quote"/>
<xsl:sequence select="$ast"/>
</lvalue>
</malval>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:sequence select="$result"/>
</xsl:template>
<xsl:template name="EVAL">
<xsl:param name="env"/>
<xsl:param name="encode-env" select="true()"/>
<xsl:variable name="atoms" select="atoms"/>
<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="."/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<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:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:set($env, $name, $value/data/value/malval))}"/>
</xsl:if>
<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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:swap-replEnv($env, env:deserialise($value/env/@data) =&gt; env:replEnv()))}"/>
</xsl:if>
<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:with-param name="encode-env" select="false()"/>
</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() &gt; 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"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($new_env)}"/>
</xsl:if>
<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:with-param name="encode-env" select="false()"/>
</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:with-param name="encode-env" select="$encode-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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:sequence select="$res/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<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>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$atoms"/>
</xsl:when>
<xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'quote'">
<value>
<xsl:sequence select="value/malval/lvalue/malval[2]"/>
</value>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$atoms"/>
</xsl:when>
<xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'quasiquote'">
<xsl:variable name="exp">
<value>
<xsl:call-template name="quasiquote">
<xsl:with-param name="ast" select="value/malval/lvalue/malval[2]"/>
</xsl:call-template>
</value>
<xsl:sequence select="$atoms"/>
</xsl:variable>
<xsl:variable name="res">
<xsl:for-each select="$exp">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$res/data/value"/>
<xsl:if test="$encode-env">
<xsl:sequence select="$res/env"/>
</xsl:if>
<xsl:sequence select="$res/atoms"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="new_list">
<xsl:call-template name="eval_ast">
<xsl:with-param name="atoms" select="$atoms"/>
<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="$new_list/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 name="value">
<malval kind="string" value="{$env =&gt; serialize(map{'method':'json'})}"/>
</xsl:variable>
<value>
<xsl:sequence select="$value"/>
</value>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<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 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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:swap-replEnv($env, env:deserialise($value/env/@data)))}"/>
</xsl:if>
<xsl:sequence select="$value/atoms"/>
</xsl:when>
<xsl:when test="$func/malval/@name = 'atom'">
<!-- needs access to atoms -->
<xsl:variable name="atom-ident" select="count($atoms/atom)"/>
<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 name="newv" select="$args/value/malval/lvalue/malval[2]"/>
<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 name="atom-value" select="$atoms/atom[@identity = $atom-ident]/malval"/>
<xsl:variable name="fn" select="$args/value/malval/lvalue/malval[2]"/>
<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() &gt; 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:with-param name="encode-env" select="$encode-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:if test="$encode-env">
<xsl:sequence select="$newv/env"/>
</xsl:if>
</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)">
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</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="atoms" select="$atoms"/>
<xsl:with-param name="env" select="$env"/>
</xsl:call-template>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<!-- <xsl:sequence select="$atoms"/> -->
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<data>
<xsl:sequence select="$data/value"/>
</data>
<xsl:if test="$encode-env">
<env data="{$data/env/@data}"/>
</xsl:if>
<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:for-each>
</xsl:variable>
<xsl:for-each select="$form">
<xsl:if test="error">
<xsl:value-of select="error(QName('MAL', 'Error'), string(error))"/>
</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(.)"/>
<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:function name="fn:is-pair">
<xsl:param name="list"/>
<xsl:sequence select="($list/@kind = 'list' or $list/@kind = 'vector') and count($list/lvalue/malval) != 0"/>
</xsl:function>
</xsl:stylesheet>
<!-- A way to keep a process waiting until we signal it -->
<!-- In order to have a process pool that executes our queries faster -->
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="step7_quote.inc.xslt"></xsl:import>
<xsl:param name="process_id" required="yes"/>
<xsl:template match="/">
<xsl:variable name="uri" select="concat('process-input-', $process_id, '.xml')"></xsl:variable>
<xsl:variable name="_lock" select="unparsed-text(concat('process-lock-', $process_id))"></xsl:variable>
<!-- use _lock to trick the runtime -->
<xsl:variable name="ctx" select="doc(concat($uri, substring($_lock, 0, 0)))"/>
<xsl:for-each select="$ctx/mal">
<xsl:call-template name="rep"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,858 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Step 8: Macros -->
<!-- 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 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" version="3.0" 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() =&gt; env:bind-all(core:ns()/@name, core:ns()) =&gt; env:set('*ARGV*', $argv) =&gt; env:toReplEnv())}"/>
<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)"))))) (defmacro! cond (fn* (&amp; xs) (if (&gt; (count xs) 0) (list 'if (first xs) (if (&gt; (count xs) 1) (nth xs 1) (throw "odd number of forms to cond")) (cons 'cond (rest (rest xs))))))))</stdin>
</mal>
</xsl:variable>
<xsl:variable name="new-state">
<xsl:for-each select="$vstate/mal">
<xsl:call-template name="rep"/>
</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: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[1]"/>
</xsl:variable>
<xsl:for-each select="$data">
<xsl:call-template name="PRINT"/>
</xsl:for-each>
</stdout>
<state>
<env data="{env/@data}"/>
<xsl:sequence select="atoms[1]"/>
</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:param name="atoms"/>
<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' or value/malval/@kind = 'vector' or value/malval/@kind = 'hash'">
<xsl:variable name="myctx">
<xsl:iterate select="value/malval/lvalue/malval">
<xsl:param name="atoms" select="$atoms"/>
<xsl:param name="xctx" select="()"/>
<xsl:on-completion>
<xsl:sequence select="$xctx/value/malval"/>
<xsl:sequence select="$atoms"/>
</xsl:on-completion>
<xsl:variable name="ctx">
<value>
<xsl:sequence select="."/>
</value>
<xsl:sequence select="$atoms"/>
</xsl:variable>
<xsl:variable name="xctxy">
<xsl:for-each select="$ctx">
<xsl:variable name="val">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:variable>
<xsl:sequence select="$val/data/value"/>
<xsl:sequence select="$val/atoms"/>
</xsl:for-each>
</xsl:variable>
<xsl:next-iteration>
<xsl:with-param name="atoms" select="$xctxy/atoms"/>
<xsl:with-param name="xctx" select="$xctx, $xctxy"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:variable>
<value>
<malval kind="{value/malval/@kind}">
<lvalue>
<xsl:sequence select="$myctx/malval"/>
</lvalue>
</malval>
</value>
<xsl:sequence select="$myctx/atoms"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="."/>
<xsl:sequence select="$atoms"/>
</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 =&gt; env:hier(env:deserialise($func/malval/env/@data)) =&gt; 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[1]"/>
</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) =&gt; env:replEnv()))}"/>
<xsl:sequence select="$result/atoms[1]"/>
</xsl:template>
<xsl:template name="quasiquote">
<xsl:param name="ast"/>
<xsl:variable name="result">
<xsl:choose>
<xsl:when test="fn:is-pair($ast)">
<xsl:choose>
<xsl:when test="let $fst := $ast/lvalue/malval[1] return $fst/@kind = 'symbol' and $fst/@value = 'unquote'">
<xsl:sequence select="$ast/lvalue/malval[2]"/>
</xsl:when>
<xsl:when test="let $fst := $ast/lvalue/malval[1] return fn:is-pair($fst) and (let $fstfst := $fst/lvalue/malval[1] return $fstfst/@kind = 'symbol' and $fstfst/@value = 'splice-unquote')">
<malval kind="list">
<lvalue>
<malval kind="symbol" value="concat"/>
<xsl:sequence select="$ast/lvalue/malval[1]/lvalue/malval[2]"/>
<xsl:variable name="rest" select="$ast/lvalue/malval[position() &gt; 1]"/>
<xsl:variable name="rest-">
<malval kind="list">
<lvalue>
<xsl:sequence select="$rest"/>
</lvalue>
</malval>
</xsl:variable>
<xsl:call-template name="quasiquote">
<xsl:with-param name="ast" select="$rest-"/>
</xsl:call-template>
</lvalue>
</malval>
</xsl:when>
<xsl:otherwise>
<malval kind="list">
<lvalue>
<malval kind="symbol" value="cons"/>
<xsl:variable name="first" select="$ast/lvalue/malval[1]"/>
<xsl:variable name="rest" select="$ast/lvalue/malval[position() &gt; 1]"/>
<xsl:variable name="rest-">
<malval kind="list">
<lvalue>
<xsl:sequence select="$rest"/>
</lvalue>
</malval>
</xsl:variable>
<xsl:call-template name="quasiquote">
<xsl:with-param name="ast" select="$first"/>
</xsl:call-template>
<xsl:call-template name="quasiquote">
<xsl:with-param name="ast" select="$rest-/malval"/>
</xsl:call-template>
</lvalue>
</malval>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<malval kind="list">
<lvalue>
<malval kind="symbol" value="quote"/>
<xsl:sequence select="$ast"/>
</lvalue>
</malval>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:sequence select="$result"/>
</xsl:template>
<xsl:template name="macroexpand">
<xsl:param name="ast"/>
<xsl:param name="env"/>
<xsl:param name="encode-env"/>
<xsl:choose>
<xsl:when test="fn:is-macro-call($ast, $env)">
<xsl:variable name="fn" select="env:get($env, $ast/lvalue/malval[1]/@value)"/>
<xsl:variable name="args">
<value>
<malval kind="list">
<lvalue>
<xsl:sequence select="$ast/lvalue/malval[position() &gt; 1]"/>
</lvalue>
</malval>
</value>
</xsl:variable>
<xsl:variable name="new">
<xsl:call-template name="uapply">
<xsl:with-param name="func" select="$fn"/>
<xsl:with-param name="args" select="$args"/>
<xsl:with-param name="env" select="$env"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="macroexpand">
<xsl:with-param name="ast" select="$new/value/malval"/>
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<value>
<xsl:sequence select="$ast"/>
</value>
<xsl:sequence select="atoms[1]"/>
<xsl:if test="$encode-env">
<env data="{$env =&gt; env:serialise()}"/>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="EVAL">
<xsl:param name="env"/>
<xsl:param name="encode-env" select="true()"/>
<xsl:variable name="atoms" select="atoms[1]"/>
<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="."/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$atoms"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="mexp">
<xsl:call-template name="macroexpand">
<xsl:with-param name="ast" select="value/malval"/>
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:variable>
<xsl:for-each select="$mexp">
<xsl:choose>
<xsl:when test="value/malval/@kind != 'list'">
<xsl:variable name="ctx">
<xsl:sequence select="value"/>
</xsl:variable>
<xsl:for-each select="$ctx">
<xsl:call-template name="eval_ast">
<xsl:with-param name="atoms" select="$atoms"/>
<xsl:with-param name="env" select="$env"/>
</xsl:call-template>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<!-- <xsl:sequence select="$atoms"/> -->
</xsl:for-each>
</xsl:when>
<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:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:set($env, $name, $value/data/value/malval))}"/>
</xsl:if>
<xsl:sequence select="$value/atoms[1]"/>
</xsl:when>
<xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'defmacro!'">
<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:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="resv">
<value>
<malval kind="{$value/data/value/malval/@kind}" value="{$value/data/value/malval/@value}">
<xsl:sequence select="$value/data/value/malval/*[name() != 'is_macro']"/>
<is_macro>true</is_macro>
</malval>
</value>
</xsl:variable>
<xsl:sequence select="$resv"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:set($env, $name, $resv/value/malval))}"/>
</xsl:if>
<xsl:sequence select="$resv/atoms[1]"/>
</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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:swap-replEnv($env, env:deserialise($value/env/@data) =&gt; env:replEnv()))}"/>
</xsl:if>
<xsl:sequence select="$value/atoms[1]"/>
</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:with-param name="encode-env" select="false()"/>
</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[1]"/>
</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() &gt; 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"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($new_env)}"/>
</xsl:if>
<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[1]"/>
</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:with-param name="encode-env" select="false()"/>
</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[1]"/>
</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[1]"/>
</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[1]"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$pfalse/value"/>
<xsl:sequence select="$pfalse/atoms[1]"/>
</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:with-param name="encode-env" select="$encode-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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:sequence select="$res/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$res/atoms[1]"/>
</xsl:when>
<xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'fn*'">
<value>
<malval kind="userfunction">
<is_macro>false</is_macro>
<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>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$atoms"/>
</xsl:when>
<xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'quote'">
<value>
<xsl:sequence select="value/malval/lvalue/malval[2]"/>
</value>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$atoms"/>
</xsl:when>
<xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'quasiquote'">
<xsl:variable name="exp">
<value>
<xsl:call-template name="quasiquote">
<xsl:with-param name="ast" select="value/malval/lvalue/malval[2]"/>
</xsl:call-template>
</value>
<xsl:sequence select="$atoms"/>
</xsl:variable>
<xsl:variable name="res">
<xsl:for-each select="$exp">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$res/data/value"/>
<xsl:if test="$encode-env">
<xsl:sequence select="$res/env"/>
</xsl:if>
<xsl:sequence select="$res/atoms[1]"/>
</xsl:when>
<xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'macroexpand'">
<xsl:variable name="exp">
<xsl:call-template name="macroexpand">
<xsl:with-param name="ast" select="value/malval/lvalue/malval[2]"/>
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
<xsl:sequence select="$atoms"/>
</xsl:variable>
<xsl:sequence select="$exp/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$atoms"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="new_list">
<xsl:call-template name="eval_ast">
<xsl:with-param name="atoms" select="$atoms"/>
<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="$new_list/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 name="value">
<malval kind="string" value="{$env =&gt; serialize(map{'method':'json'})}"/>
</xsl:variable>
<value>
<xsl:sequence select="$value"/>
</value>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$value/atoms[1]"/>
</xsl:when>
<xsl:when test="$func/malval/@name = 'eval'">
<!-- needs access to env -->
<xsl:variable name="venv" select="env:replEnv($env)"/>
<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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:swap-replEnv($env, env:deserialise($value/env/@data)))}"/>
</xsl:if>
<xsl:sequence select="$value/atoms[1]"/>
</xsl:when>
<xsl:when test="$func/malval/@name = 'atom'">
<!-- needs access to atoms -->
<xsl:variable name="atom-ident" select="count($atoms/atom)"/>
<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 name="newv" select="$args/value/malval/lvalue/malval[2]"/>
<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 name="atom-value" select="$atoms/atom[@identity = $atom-ident]/malval"/>
<xsl:variable name="fn" select="$args/value/malval/lvalue/malval[2]"/>
<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() &gt; 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:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$newv/data/value"/>
<atoms>
<xsl:for-each select="$newv/atoms[1]/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)">
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="env"/>
</xsl:otherwise>
</xsl:choose>
<xsl:sequence select="atoms[1]"/>
<xsl:sequence select="value"/>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="eval_ast">
<xsl:with-param name="atoms" select="$atoms"/>
<xsl:with-param name="env" select="$env"/>
</xsl:call-template>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<!-- <xsl:sequence select="$atoms"/> -->
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<data>
<xsl:sequence select="$data/value"/>
</data>
<xsl:if test="$encode-env">
<env data="{$data/env/@data}"/>
</xsl:if>
<xsl:sequence select="$data/atoms[1]"/>
</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[1]"/>
<xsl:for-each select="$context">
<xsl:call-template name="malreader-read_str"/>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$form">
<xsl:if test="error">
<xsl:value-of select="error(QName('MAL', 'Error'), string(error))"/>
</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(.)"/>
<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:function name="fn:is-pair">
<xsl:param name="list"/>
<xsl:sequence select="($list/@kind = 'list' or $list/@kind = 'vector') and count($list/lvalue/malval) != 0"/>
</xsl:function>
<xsl:function name="fn:is-macro-call">
<xsl:param name="ast"/>
<xsl:param name="env"/>
<xsl:variable name="res" select="$ast/@kind = 'list' and $ast/lvalue/malval[1]/@kind = 'symbol' and (let $fn := env:get-noerror($env, $ast/lvalue/malval[1]/@value) return not(empty($fn)) and $fn/malval/is_macro/text() = 'true')"/>
<xsl:sequence select="$res"/>
</xsl:function>
</xsl:stylesheet>

View File

@ -1,858 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Step 8: Macros -->
<!-- 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 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" version="3.0" 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() =&gt; env:bind-all(core:ns()/@name, core:ns()) =&gt; env:set('*ARGV*', $argv) =&gt; env:toReplEnv())}"/>
<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)"))))) (defmacro! cond (fn* (&amp; xs) (if (&gt; (count xs) 0) (list 'if (first xs) (if (&gt; (count xs) 1) (nth xs 1) (throw "odd number of forms to cond")) (cons 'cond (rest (rest xs))))))))</stdin>
</mal>
</xsl:variable>
<xsl:variable name="new-state">
<xsl:for-each select="$vstate/mal">
<xsl:call-template name="rep"/>
</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: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[1]"/>
</xsl:variable>
<xsl:for-each select="$data">
<xsl:call-template name="PRINT"/>
</xsl:for-each>
</stdout>
<state>
<env data="{env/@data}"/>
<xsl:sequence select="atoms[1]"/>
</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:param name="atoms"/>
<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' or value/malval/@kind = 'vector' or value/malval/@kind = 'hash'">
<xsl:variable name="myctx">
<xsl:iterate select="value/malval/lvalue/malval">
<xsl:param name="atoms" select="$atoms"/>
<xsl:param name="xctx" select="()"/>
<xsl:on-completion>
<xsl:sequence select="$xctx/value/malval"/>
<xsl:sequence select="$atoms"/>
</xsl:on-completion>
<xsl:variable name="ctx">
<value>
<xsl:sequence select="."/>
</value>
<xsl:sequence select="$atoms"/>
</xsl:variable>
<xsl:variable name="xctxy">
<xsl:for-each select="$ctx">
<xsl:variable name="val">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:variable>
<xsl:sequence select="$val/data/value"/>
<xsl:sequence select="$val/atoms"/>
</xsl:for-each>
</xsl:variable>
<xsl:next-iteration>
<xsl:with-param name="atoms" select="$xctxy/atoms"/>
<xsl:with-param name="xctx" select="$xctx, $xctxy"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:variable>
<value>
<malval kind="{value/malval/@kind}">
<lvalue>
<xsl:sequence select="$myctx/malval"/>
</lvalue>
</malval>
</value>
<xsl:sequence select="$myctx/atoms"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="."/>
<xsl:sequence select="$atoms"/>
</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 =&gt; env:hier(env:deserialise($func/malval/env/@data)) =&gt; 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[1]"/>
</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) =&gt; env:replEnv()))}"/>
<xsl:sequence select="$result/atoms[1]"/>
</xsl:template>
<xsl:template name="quasiquote">
<xsl:param name="ast"/>
<xsl:variable name="result">
<xsl:choose>
<xsl:when test="fn:is-pair($ast)">
<xsl:choose>
<xsl:when test="let $fst := $ast/lvalue/malval[1] return $fst/@kind = 'symbol' and $fst/@value = 'unquote'">
<xsl:sequence select="$ast/lvalue/malval[2]"/>
</xsl:when>
<xsl:when test="let $fst := $ast/lvalue/malval[1] return fn:is-pair($fst) and (let $fstfst := $fst/lvalue/malval[1] return $fstfst/@kind = 'symbol' and $fstfst/@value = 'splice-unquote')">
<malval kind="list">
<lvalue>
<malval kind="symbol" value="concat"/>
<xsl:sequence select="$ast/lvalue/malval[1]/lvalue/malval[2]"/>
<xsl:variable name="rest" select="$ast/lvalue/malval[position() &gt; 1]"/>
<xsl:variable name="rest-">
<malval kind="list">
<lvalue>
<xsl:sequence select="$rest"/>
</lvalue>
</malval>
</xsl:variable>
<xsl:call-template name="quasiquote">
<xsl:with-param name="ast" select="$rest-"/>
</xsl:call-template>
</lvalue>
</malval>
</xsl:when>
<xsl:otherwise>
<malval kind="list">
<lvalue>
<malval kind="symbol" value="cons"/>
<xsl:variable name="first" select="$ast/lvalue/malval[1]"/>
<xsl:variable name="rest" select="$ast/lvalue/malval[position() &gt; 1]"/>
<xsl:variable name="rest-">
<malval kind="list">
<lvalue>
<xsl:sequence select="$rest"/>
</lvalue>
</malval>
</xsl:variable>
<xsl:call-template name="quasiquote">
<xsl:with-param name="ast" select="$first"/>
</xsl:call-template>
<xsl:call-template name="quasiquote">
<xsl:with-param name="ast" select="$rest-/malval"/>
</xsl:call-template>
</lvalue>
</malval>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<malval kind="list">
<lvalue>
<malval kind="symbol" value="quote"/>
<xsl:sequence select="$ast"/>
</lvalue>
</malval>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:sequence select="$result"/>
</xsl:template>
<xsl:template name="macroexpand">
<xsl:param name="ast"/>
<xsl:param name="env"/>
<xsl:param name="encode-env"/>
<xsl:choose>
<xsl:when test="fn:is-macro-call($ast, $env)">
<xsl:variable name="fn" select="env:get($env, $ast/lvalue/malval[1]/@value)"/>
<xsl:variable name="args">
<value>
<malval kind="list">
<lvalue>
<xsl:sequence select="$ast/lvalue/malval[position() &gt; 1]"/>
</lvalue>
</malval>
</value>
</xsl:variable>
<xsl:variable name="new">
<xsl:call-template name="uapply">
<xsl:with-param name="func" select="$fn"/>
<xsl:with-param name="args" select="$args"/>
<xsl:with-param name="env" select="$env"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="macroexpand">
<xsl:with-param name="ast" select="$new/value/malval"/>
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<value>
<xsl:sequence select="$ast"/>
</value>
<xsl:sequence select="atoms[1]"/>
<xsl:if test="$encode-env">
<env data="{$env =&gt; env:serialise()}"/>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="EVAL">
<xsl:param name="env"/>
<xsl:param name="encode-env" select="true()"/>
<xsl:variable name="atoms" select="atoms[1]"/>
<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="."/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$atoms"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="mexp">
<xsl:call-template name="macroexpand">
<xsl:with-param name="ast" select="value/malval"/>
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:variable>
<xsl:for-each select="$mexp">
<xsl:choose>
<xsl:when test="value/malval/@kind != 'list'">
<xsl:variable name="ctx">
<xsl:sequence select="value"/>
</xsl:variable>
<xsl:for-each select="$ctx">
<xsl:call-template name="eval_ast">
<xsl:with-param name="atoms" select="$atoms"/>
<xsl:with-param name="env" select="$env"/>
</xsl:call-template>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<!-- <xsl:sequence select="$atoms"/> -->
</xsl:for-each>
</xsl:when>
<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:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:set($env, $name, $value/data/value/malval))}"/>
</xsl:if>
<xsl:sequence select="$value/atoms[1]"/>
</xsl:when>
<xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'defmacro!'">
<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:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="resv">
<value>
<malval kind="{$value/data/value/malval/@kind}" value="{$value/data/value/malval/@value}">
<xsl:sequence select="$value/data/value/malval/*[name() != 'is_macro']"/>
<is_macro>true</is_macro>
</malval>
</value>
</xsl:variable>
<xsl:sequence select="$resv"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:set($env, $name, $resv/value/malval))}"/>
</xsl:if>
<xsl:sequence select="$resv/atoms[1]"/>
</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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:swap-replEnv($env, env:deserialise($value/env/@data) =&gt; env:replEnv()))}"/>
</xsl:if>
<xsl:sequence select="$value/atoms[1]"/>
</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:with-param name="encode-env" select="false()"/>
</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[1]"/>
</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() &gt; 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"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($new_env)}"/>
</xsl:if>
<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[1]"/>
</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:with-param name="encode-env" select="false()"/>
</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[1]"/>
</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[1]"/>
</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[1]"/>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$pfalse/value"/>
<xsl:sequence select="$pfalse/atoms[1]"/>
</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:with-param name="encode-env" select="$encode-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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:sequence select="$res/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$res/atoms[1]"/>
</xsl:when>
<xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'fn*'">
<value>
<malval kind="userfunction">
<is_macro>false</is_macro>
<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>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$atoms"/>
</xsl:when>
<xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'quote'">
<value>
<xsl:sequence select="value/malval/lvalue/malval[2]"/>
</value>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$atoms"/>
</xsl:when>
<xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'quasiquote'">
<xsl:variable name="exp">
<value>
<xsl:call-template name="quasiquote">
<xsl:with-param name="ast" select="value/malval/lvalue/malval[2]"/>
</xsl:call-template>
</value>
<xsl:sequence select="$atoms"/>
</xsl:variable>
<xsl:variable name="res">
<xsl:for-each select="$exp">
<xsl:call-template name="EVAL">
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$res/data/value"/>
<xsl:if test="$encode-env">
<xsl:sequence select="$res/env"/>
</xsl:if>
<xsl:sequence select="$res/atoms[1]"/>
</xsl:when>
<xsl:when test="let $fn := value/malval/lvalue/malval[1] return $fn/@kind = 'symbol' and $fn/@value = 'macroexpand'">
<xsl:variable name="exp">
<xsl:call-template name="macroexpand">
<xsl:with-param name="ast" select="value/malval/lvalue/malval[2]"/>
<xsl:with-param name="env" select="$env"/>
<xsl:with-param name="encode-env" select="false()"/>
</xsl:call-template>
<xsl:sequence select="$atoms"/>
</xsl:variable>
<xsl:sequence select="$exp/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$atoms"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="new_list">
<xsl:call-template name="eval_ast">
<xsl:with-param name="atoms" select="$atoms"/>
<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="$new_list/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 name="value">
<malval kind="string" value="{$env =&gt; serialize(map{'method':'json'})}"/>
</xsl:variable>
<value>
<xsl:sequence select="$value"/>
</value>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<xsl:sequence select="$value/atoms[1]"/>
</xsl:when>
<xsl:when test="$func/malval/@name = 'eval'">
<!-- needs access to env -->
<xsl:variable name="venv" select="env:replEnv($env)"/>
<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:with-param name="encode-env" select="$encode-env"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$value/data/value"/>
<xsl:if test="$encode-env">
<env data="{env:serialise(env:swap-replEnv($env, env:deserialise($value/env/@data)))}"/>
</xsl:if>
<xsl:sequence select="$value/atoms[1]"/>
</xsl:when>
<xsl:when test="$func/malval/@name = 'atom'">
<!-- needs access to atoms -->
<xsl:variable name="atom-ident" select="count($atoms/atom)"/>
<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 name="newv" select="$args/value/malval/lvalue/malval[2]"/>
<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 name="atom-value" select="$atoms/atom[@identity = $atom-ident]/malval"/>
<xsl:variable name="fn" select="$args/value/malval/lvalue/malval[2]"/>
<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() &gt; 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:with-param name="encode-env" select="false()"/>
</xsl:call-template>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="$newv/data/value"/>
<atoms>
<xsl:for-each select="$newv/atoms[1]/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)">
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="env"/>
</xsl:otherwise>
</xsl:choose>
<xsl:sequence select="atoms[1]"/>
<xsl:sequence select="value"/>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="eval_ast">
<xsl:with-param name="atoms" select="$atoms"/>
<xsl:with-param name="env" select="$env"/>
</xsl:call-template>
<xsl:if test="$encode-env">
<env data="{env:serialise($env)}"/>
</xsl:if>
<!-- <xsl:sequence select="$atoms"/> -->
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<data>
<xsl:sequence select="$data/value"/>
</data>
<xsl:if test="$encode-env">
<env data="{$data/env/@data}"/>
</xsl:if>
<xsl:sequence select="$data/atoms[1]"/>
</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[1]"/>
<xsl:for-each select="$context">
<xsl:call-template name="malreader-read_str"/>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="$form">
<xsl:if test="error">
<xsl:value-of select="error(QName('MAL', 'Error'), string(error))"/>
</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(.)"/>
<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:function name="fn:is-pair">
<xsl:param name="list"/>
<xsl:sequence select="($list/@kind = 'list' or $list/@kind = 'vector') and count($list/lvalue/malval) != 0"/>
</xsl:function>
<xsl:function name="fn:is-macro-call">
<xsl:param name="ast"/>
<xsl:param name="env"/>
<xsl:variable name="res" select="$ast/@kind = 'list' and $ast/lvalue/malval[1]/@kind = 'symbol' and (let $fn := env:get-noerror($env, $ast/lvalue/malval[1]/@value) return not(empty($fn)) and $fn/malval/is_macro/text() = 'true')"/>
<xsl:sequence select="$res"/>
</xsl:function>
</xsl:stylesheet>
<!-- A way to keep a process waiting until we signal it -->
<!-- In order to have a process pool that executes our queries faster -->
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="step8_macros.inc.xslt"></xsl:import>
<xsl:param name="process_id" required="yes"/>
<xsl:template match="/">
<xsl:variable name="uri" select="concat('process-input-', $process_id, '.xml')"></xsl:variable>
<xsl:variable name="_lock" select="unparsed-text(concat('process-lock-', $process_id))"></xsl:variable>
<!-- use _lock to trick the runtime -->
<xsl:variable name="ctx" select="doc(concat($uri, substring($_lock, 0, 0)))"/>
<xsl:for-each select="$ctx/mal">
<xsl:call-template name="rep"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff