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:
parent
73e80a3974
commit
e4882d7d71
@ -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()
|
43
impls/xslt/step0_repl.inc.xslt
Normal file
43
impls/xslt/step0_repl.inc.xslt
Normal 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>
|
@ -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>
|
70
impls/xslt/step1_read_print.inc.xslt
Normal file
70
impls/xslt/step1_read_print.inc.xslt
Normal 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>
|
@ -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>
|
253
impls/xslt/step2_eval.inc.xslt
Normal file
253
impls/xslt/step2_eval.inc.xslt
Normal 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>
|
@ -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>
|
369
impls/xslt/step3_env.inc.xslt
Normal file
369
impls/xslt/step3_env.inc.xslt
Normal 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>
|
@ -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>
|
503
impls/xslt/step4_if_fn_do.inc.xslt
Normal file
503
impls/xslt/step4_if_fn_do.inc.xslt
Normal 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() => 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 => env:hier(env:deserialise($func/malval/env/@data)) => env:close-with-binds($func/malval/binds/malval/@value, $args/value/malval/lvalue/malval)"/>
|
||||
<xsl:variable name="body">
|
||||
<value>
|
||||
<xsl:sequence select="$func/malval/body/malval"/>
|
||||
</value>
|
||||
</xsl: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() > 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>
|
@ -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() => 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 => env:hier(env:deserialise($func/malval/env/@data)) => env:close-with-binds($func/malval/binds/malval/@value, $args/value/malval/lvalue/malval)"/>
|
||||
<xsl:variable name="body">
|
||||
<value>
|
||||
<xsl:sequence select="$func/malval/body/malval"/>
|
||||
</value>
|
||||
</xsl: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() > 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>
|
628
impls/xslt/step6_file.inc.xslt
Normal file
628
impls/xslt/step6_file.inc.xslt
Normal 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() => env:bind-all(core:ns()/@name, core:ns()) => env:set('*ARGV*', $argv) => 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 => env:hier(env:deserialise($func/malval/env/@data)) => env:close-with-binds($func/malval/binds/malval/@value, $args/value/malval/lvalue/malval)"/>
|
||||
<xsl:variable name="body">
|
||||
<value>
|
||||
<xsl:sequence select="$func/malval/body/malval"/>
|
||||
</value>
|
||||
<xsl:sequence select="atoms"/>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="result">
|
||||
<xsl:for-each select="$body">
|
||||
<xsl:call-template name="EVAL">
|
||||
<xsl:with-param name="env" select="$nenv"/>
|
||||
</xsl:call-template>
|
||||
</xsl:for-each>
|
||||
</xsl:variable>
|
||||
<xsl:sequence select="$result/data/value"/>
|
||||
<env data="{env:serialise(env:swap-replEnv($env, env:deserialise($result/env/@data) => env:replEnv()))}"/>
|
||||
<xsl:sequence select="$result/atoms"/>
|
||||
</xsl:template>
|
||||
<xsl:template name="EVAL">
|
||||
<xsl:param name="env"/>
|
||||
<xsl: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) => 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() > 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() > 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>
|
@ -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() => env:bind-all(core:ns()/@name, core:ns()) => env:set('*ARGV*', $argv) => 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 => env:hier(env:deserialise($func/malval/env/@data)) => env:close-with-binds($func/malval/binds/malval/@value, $args/value/malval/lvalue/malval)"/>
|
||||
<xsl:variable name="body">
|
||||
<value>
|
||||
<xsl:sequence select="$func/malval/body/malval"/>
|
||||
</value>
|
||||
<xsl:sequence select="atoms"/>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="result">
|
||||
<xsl:for-each select="$body">
|
||||
<xsl:call-template name="EVAL">
|
||||
<xsl:with-param name="env" select="$nenv"/>
|
||||
</xsl:call-template>
|
||||
</xsl:for-each>
|
||||
</xsl:variable>
|
||||
<xsl:sequence select="$result/data/value"/>
|
||||
<env data="{env:serialise(env:swap-replEnv($env, env:deserialise($result/env/@data) => env:replEnv()))}"/>
|
||||
<xsl:sequence select="$result/atoms"/>
|
||||
</xsl:template>
|
||||
<xsl:template name="EVAL">
|
||||
<xsl:param name="env"/>
|
||||
<xsl: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) => 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() > 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() > 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>
|
742
impls/xslt/step7_quote.inc.xslt
Normal file
742
impls/xslt/step7_quote.inc.xslt
Normal 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() => env:bind-all(core:ns()/@name, core:ns()) => env:set('*ARGV*', $argv) => 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 => env:hier(env:deserialise($func/malval/env/@data)) => env:close-with-binds($func/malval/binds/malval/@value, $args/value/malval/lvalue/malval)"/>
|
||||
<xsl:variable name="body">
|
||||
<value>
|
||||
<xsl:sequence select="$func/malval/body/malval"/>
|
||||
</value>
|
||||
<xsl:sequence select="atoms"/>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="result">
|
||||
<xsl:for-each select="$body">
|
||||
<xsl:call-template name="EVAL">
|
||||
<xsl:with-param name="env" select="$nenv"/>
|
||||
</xsl:call-template>
|
||||
</xsl:for-each>
|
||||
</xsl:variable>
|
||||
<xsl:sequence select="$result/data/value"/>
|
||||
<env data="{env:serialise(env:swap-replEnv($env, env:deserialise($result/env/@data) => env:replEnv()))}"/>
|
||||
<xsl:sequence select="$result/atoms"/>
|
||||
</xsl:template>
|
||||
<xsl:template name="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() > 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() > 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) => 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() > 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 => 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() > 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>
|
@ -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() => env:bind-all(core:ns()/@name, core:ns()) => env:set('*ARGV*', $argv) => 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 => env:hier(env:deserialise($func/malval/env/@data)) => env:close-with-binds($func/malval/binds/malval/@value, $args/value/malval/lvalue/malval)"/>
|
||||
<xsl:variable name="body">
|
||||
<value>
|
||||
<xsl:sequence select="$func/malval/body/malval"/>
|
||||
</value>
|
||||
<xsl:sequence select="atoms"/>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="result">
|
||||
<xsl:for-each select="$body">
|
||||
<xsl:call-template name="EVAL">
|
||||
<xsl:with-param name="env" select="$nenv"/>
|
||||
</xsl:call-template>
|
||||
</xsl:for-each>
|
||||
</xsl:variable>
|
||||
<xsl:sequence select="$result/data/value"/>
|
||||
<env data="{env:serialise(env:swap-replEnv($env, env:deserialise($result/env/@data) => env:replEnv()))}"/>
|
||||
<xsl:sequence select="$result/atoms"/>
|
||||
</xsl:template>
|
||||
<xsl:template name="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() > 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() > 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) => 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() > 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 => 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() > 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>
|
858
impls/xslt/step8_macros.inc.xslt
Normal file
858
impls/xslt/step8_macros.inc.xslt
Normal 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() => env:bind-all(core:ns()/@name, core:ns()) => env:set('*ARGV*', $argv) => 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* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (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 => env:hier(env:deserialise($func/malval/env/@data)) => env:close-with-binds($func/malval/binds/malval/@value, $args/value/malval/lvalue/malval)"/>
|
||||
<xsl:variable name="body">
|
||||
<value>
|
||||
<xsl:sequence select="$func/malval/body/malval"/>
|
||||
</value>
|
||||
<xsl:sequence select="atoms[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) => 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() > 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() > 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() > 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 => 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) => 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() > 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 => 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() > 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>
|
@ -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() => env:bind-all(core:ns()/@name, core:ns()) => env:set('*ARGV*', $argv) => 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* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (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 => env:hier(env:deserialise($func/malval/env/@data)) => env:close-with-binds($func/malval/binds/malval/@value, $args/value/malval/lvalue/malval)"/>
|
||||
<xsl:variable name="body">
|
||||
<value>
|
||||
<xsl:sequence select="$func/malval/body/malval"/>
|
||||
</value>
|
||||
<xsl:sequence select="atoms[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) => 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() > 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() > 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() > 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 => 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) => 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() > 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 => 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() > 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>
|
1028
impls/xslt/step9_try.inc.xslt
Normal file
1028
impls/xslt/step9_try.inc.xslt
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1050
impls/xslt/stepA_mal.inc.xslt
Normal file
1050
impls/xslt/stepA_mal.inc.xslt
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user