impl step6
[jackhill/mal.git] / xslt / env.xslt
1 <?xml version="1.0" encoding="UTF-8"?>
2 <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">
3 <!-- since I can not, for the life of me, figure out how to (de-)serialise maps from/to xml, we're gonna be storing the env as a json string -->
4
5 <xsl:function name="env:noReplEnv">
6 <xsl:param name="env"/>
7 <xsl:sequence select="map {'outer': $env('outer'), 'isReplEnv': false(), 'data': $env('data') }"/>
8 </xsl:function>
9
10 <xsl:function name="env:set">
11 <xsl:param name="env"/>
12 <xsl:param name="name"/>
13 <xsl:param name="value"/>
14 <xsl:sequence select="if ($env('isReplEnv')) then map { 'outer': $env('outer'), 'replEnv': env:set($env('replEnv'), $name, $value), 'isReplEnv': true(), 'data': $env('data') } else map { 'outer': $env('outer'), 'replEnv': $env('replEnv'), 'isReplEnv': false(), 'data': map:put($env('data'), $name, $value => serialize(map{})) }"/>
15 </xsl:function>
16
17 <xsl:function name="env:find">
18 <xsl:param name="env"/>
19 <xsl:param name="name"/>
20 <xsl:sequence select="if (empty($env)) then () else if (map:contains($env('data'), $name)) then $env else (env:find($env('outer'), $name), env:find($env('replEnv'), $name))[1]"/>
21 </xsl:function>
22
23 <xsl:function name="env:get">
24 <xsl:param name="env"/>
25 <xsl:param name="name"/>
26 <xsl:variable name="value" select="let $venv := env:find($env, $name) return if (empty($venv)) then () else $venv('data')($name)"></xsl:variable>
27 <xsl:choose>
28 <xsl:when test="empty($value)"><xsl:message terminate="yes">Symbol <xsl:value-of select="$name" /> not found</xsl:message></xsl:when>
29 <xsl:otherwise><xsl:sequence select="parse-xml($value)"/></xsl:otherwise>
30 </xsl:choose>
31 </xsl:function>
32
33 <xsl:function name="env:base" as="xs:string">
34 <xsl:variable name="plus"><malval kind="function" name="+"></malval></xsl:variable>
35 <xsl:variable name="minus"><malval kind="function" name="-"></malval></xsl:variable>
36 <xsl:variable name="mult"><malval kind="function" name="*"></malval></xsl:variable>
37 <xsl:variable name="div"><malval kind="function" name="/"></malval></xsl:variable>
38 <xsl:sequence select="env:serialise(env:set(env:set(env:set(env:set(map{'outer':(), 'data':map{}, 'isReplEnv': false()}, '+', $plus), '-', $minus), '*', $mult), '/', $div))"/>
39 </xsl:function>
40
41 <xsl:function name="env:swap-replEnv">
42 <xsl:param name="env"></xsl:param>
43 <xsl:param name="toRepl"></xsl:param>
44 <xsl:sequence select="if (not(empty($toRepl))) then map:put($env, 'replEnv', $toRepl) else $env"/>
45 </xsl:function>
46
47 <xsl:function name="env:replEnv">
48 <xsl:param name="env"/>
49 <xsl:sequence select="$env('replEnv')"/>
50 </xsl:function>
51
52 <xsl:function name="env:toReplEnv">
53 <xsl:param name="env"/>
54 <xsl:variable name='renv' select="map{'outer':(), 'data': map{}, 'replEnv': map{'data':env:dump($env), 'outer':(), 'isReplEnv': false()}, 'isReplEnv': true()}"/>
55 <xsl:sequence select="$renv"/>
56 </xsl:function>
57
58 <xsl:function name="env:empty">
59 <xsl:sequence select="map{'outer':(), 'data':map{}, 'isReplEnv': false()}"/>
60 </xsl:function>
61
62 <xsl:function name="env:serialise">
63 <xsl:param name="env"/>
64 <xsl:sequence select="serialize($env, map {'method': 'json'})"/>
65 </xsl:function>
66
67 <xsl:function name="env:close">
68 <xsl:param name="env"/>
69 <xsl:sequence select="map{'outer': env:noReplEnv($env), 'data': map{}, 'isReplEnv': false(), 'replEnv': $env('replEnv')}"/>
70 </xsl:function>
71
72 <xsl:function name="env:close-with-binds">
73 <xsl:param name="env"/>
74 <xsl:param name="binds" />
75 <xsl:param name="exprs" />
76
77 <xsl:variable name="new-env" select="map {'outer': env:noReplEnv($env), 'replEnv': $env('replEnv'), 'data': map{}, 'isReplEnv': false()}"/>
78 <xsl:sequence select="$new-env => env:bind-all($binds, $exprs)"/>
79 </xsl:function>
80
81 <xsl:function name="env:dump">
82 <xsl:param name="env"/>
83 <xsl:sequence select="if (not(empty($env))) then map:merge(($env('data'), env:dump($env('outer')))) else map{}"/>
84 </xsl:function>
85
86 <xsl:function name="env:merge">
87 <xsl:param name="env" />
88 <xsl:param name="second" />
89
90 <xsl:variable name="env-items" select="env:dump($env)"></xsl:variable>
91 <xsl:variable name="second-items" select="env:dump($second)"></xsl:variable>
92 <xsl:variable name="new-env" select="if (empty($env)) then $second else if (empty($second)) then $env else map {'outer': $env('outer'), 'data': map:merge(($env-items, $second-items)), 'isReplEnv': false(), 'replEnv': env:merge($second('replEnv'), $env('replEnv'))}"></xsl:variable>
93 <xsl:sequence select="$new-env"/>
94 </xsl:function>
95
96 <xsl:function name="env:hier">
97 <xsl:param name="env"/>
98 <xsl:param name="over"/>
99 <xsl:variable name="newEnv" select="env:merge($over, $env)"></xsl:variable>
100 <xsl:sequence select="map{'outer': env:noReplEnv($newEnv), 'data': map{}, 'isReplEnv': false(), 'replEnv': $newEnv('replEnv')}"/>
101 </xsl:function>
102
103 <xsl:function name="env:bind-all">
104 <xsl:param name="env"/>
105 <xsl:param name="binds"/>
106 <xsl:param name="exprs"/>
107 <xsl:choose>
108 <xsl:when test="exists($binds) and exists($exprs)">
109 <xsl:choose>
110 <xsl:when test="string(head($binds)) = '&#38;'">
111 <xsl:variable name="listExprs">
112 <malval kind="list">
113 <lvalue>
114 <xsl:sequence select="$exprs"/>
115 </lvalue>
116 </malval>
117 </xsl:variable>
118 <xsl:sequence select="$env => env:set(string($binds[2]), $listExprs)"/>
119 </xsl:when>
120 <xsl:otherwise>
121 <xsl:variable name="new-env" select="$env => env:set(string(head($binds)), head($exprs))"></xsl:variable>
122 <xsl:sequence select="$new-env => env:bind-all(tail($binds), tail($exprs))"/>
123 </xsl:otherwise>
124 </xsl:choose>
125 </xsl:when>
126 <xsl:when test="exists($binds)">
127 <xsl:choose>
128 <xsl:when test="string(head($binds)) = '&#38;'">
129 <xsl:variable name="listExprs">
130 <malval kind="list">
131 <lvalue>
132 </lvalue>
133 </malval>
134 </xsl:variable>
135 <xsl:sequence select="$env => env:set(string($binds[2]), $listExprs)"/>
136 </xsl:when>
137 <xsl:otherwise>
138 <xsl:variable name="Exprs">
139 <malval kind="nil">
140 </malval>
141 </xsl:variable>
142 <xsl:variable name="new-env" select="$env => env:set(string(head($binds)), $Exprs)"></xsl:variable>
143 <xsl:sequence select="$new-env => env:bind-all(tail($binds), $exprs)"/>
144 </xsl:otherwise>
145 </xsl:choose>
146 </xsl:when>
147 <xsl:otherwise>
148 <xsl:sequence select="$env"/>
149 </xsl:otherwise>
150 </xsl:choose>
151 </xsl:function>
152
153 <xsl:function name="env:deserialise">
154 <xsl:param name="env"/>
155 <xsl:sequence select="parse-json($env)"/>
156 </xsl:function>
157
158 </xsl:stylesheet>