Commit | Line | Data |
---|---|---|
e4882d7d A |
1 | <?xml version="1.0" encoding="UTF-8"?> |
2 | <!-- Step 3: Environment --> | |
3 | <!-- input document must be in the following format --> | |
4 | <!-- | |
5 | <mal> | |
6 | <stdin>...stdin text...</stdin> | |
7 | <stdout> ... ignored, omitted ... </stdout> | |
8 | <state> contains env </state> | |
9 | </mal> | |
10 | --> | |
11 | <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"> | |
12 | <xsl:import href="reader.xslt"/> | |
13 | <xsl:import href="printer.xslt"/> | |
14 | <xsl:import href="env.xslt"/> | |
15 | <xsl:output method="xml" encoding="utf-8" indent="yes"/> | |
16 | <xsl:template match="mal" name="rep"> | |
fd99084c | 17 | <xsl:param name="display" select="false()" /> |
e4882d7d A |
18 | <mal> |
19 | <xsl:variable name="env" as="map(*)"> | |
20 | <xsl:sequence select="env:deserialise((state/env/@data, env:base())[1])"/> | |
21 | </xsl:variable> | |
22 | <xsl:sequence select="stdin"/> | |
23 | <xsl:variable name="_read"> | |
24 | <xsl:call-template name="READ"/> | |
25 | </xsl:variable> | |
26 | <xsl:variable name="_eval"> | |
27 | <xsl:for-each select="$_read"> | |
28 | <xsl:call-template name="EVAL"> | |
29 | <xsl:with-param name="env" select="$env"/> | |
30 | </xsl:call-template> | |
31 | </xsl:for-each> | |
32 | </xsl:variable> | |
33 | <xsl:for-each select="$_eval"> | |
fd99084c | 34 | <xsl:variable name="_print"> |
e4882d7d A |
35 | <xsl:for-each select="data"> |
36 | <xsl:call-template name="PRINT"/> | |
37 | </xsl:for-each> | |
fd99084c A |
38 | </xsl:variable> |
39 | <xsl:message> | |
40 | <request kind="display" value="{$_print}"/> | |
41 | </xsl:message> | |
e4882d7d A |
42 | <state> |
43 | <env data="{env/@data}"/> | |
44 | </state> | |
45 | </xsl:for-each> | |
46 | </mal> | |
47 | </xsl:template> | |
48 | <xsl:template name="PRINT"> | |
49 | <xsl:variable name="str"> | |
50 | <xsl:call-template name="malprinter-pr_str"> | |
51 | <xsl:with-param name="readably" select="true()"/> | |
52 | </xsl:call-template> | |
53 | </xsl:variable> | |
54 | <xsl:value-of select="$str"/> | |
55 | </xsl:template> | |
56 | <xsl:template name="eval_ast"> | |
57 | <xsl:param name="env"/> | |
58 | <xsl:choose> | |
59 | <xsl:when test="value/malval/@kind = 'symbol'"> | |
60 | <xsl:variable name="val"> | |
61 | <xsl:sequence select="env:get($env, value/malval/@value)"/> | |
62 | </xsl:variable> | |
63 | <value> | |
64 | <xsl:sequence select="$val"/> | |
65 | </value> | |
66 | </xsl:when> | |
67 | <xsl:when test="value/malval/@kind = 'list'"> | |
68 | <value> | |
69 | <malval kind="list"> | |
70 | <lvalue> | |
71 | <xsl:for-each select="value/malval/lvalue/malval"> | |
72 | <xsl:variable name="ctx"> | |
73 | <value> | |
74 | <xsl:sequence select="."/> | |
75 | </value> | |
76 | </xsl:variable> | |
77 | <xsl:variable name="xctx"> | |
78 | <xsl:for-each select="$ctx"> | |
79 | <xsl:variable name="val"> | |
80 | <xsl:call-template name="EVAL"> | |
81 | <xsl:with-param name="env" select="$env"/> | |
82 | <xsl:with-param name="encode-env" select="false()"/> | |
83 | </xsl:call-template> | |
84 | </xsl:variable> | |
85 | <xsl:sequence select="$val/data/value"/> | |
86 | </xsl:for-each> | |
87 | </xsl:variable> | |
88 | <xsl:sequence select="$xctx/value/malval"/> | |
89 | </xsl:for-each> | |
90 | </lvalue> | |
91 | </malval> | |
92 | </value> | |
93 | </xsl:when> | |
94 | <xsl:when test="value/malval/@kind = 'vector'"> | |
95 | <value> | |
96 | <malval kind="vector"> | |
97 | <lvalue> | |
98 | <xsl:for-each select="value/malval/lvalue/malval"> | |
99 | <xsl:variable name="ctx"> | |
100 | <value> | |
101 | <xsl:sequence select="."/> | |
102 | </value> | |
103 | </xsl:variable> | |
104 | <xsl:variable name="xctx"> | |
105 | <xsl:for-each select="$ctx"> | |
106 | <xsl:variable name="val"> | |
107 | <xsl:call-template name="EVAL"> | |
108 | <xsl:with-param name="env" select="$env"/> | |
109 | <xsl:with-param name="encode-env" select="false()"/> | |
110 | </xsl:call-template> | |
111 | </xsl:variable> | |
112 | <xsl:sequence select="$val/data/value"/> | |
113 | </xsl:for-each> | |
114 | </xsl:variable> | |
115 | <xsl:sequence select="$xctx/value/malval"/> | |
116 | </xsl:for-each> | |
117 | </lvalue> | |
118 | </malval> | |
119 | </value> | |
120 | </xsl:when> | |
121 | <xsl:when test="value/malval/@kind = 'hash'"> | |
122 | <value> | |
123 | <malval kind="hash"> | |
124 | <lvalue> | |
125 | <xsl:for-each select="value/malval/lvalue/malval"> | |
126 | <xsl:variable name="ctx"> | |
127 | <value> | |
128 | <xsl:sequence select="."/> | |
129 | </value> | |
130 | </xsl:variable> | |
131 | <xsl:variable name="xctx"> | |
132 | <xsl:for-each select="$ctx"> | |
133 | <xsl:variable name="val"> | |
134 | <xsl:call-template name="EVAL"> | |
135 | <xsl:with-param name="env" select="$env"/> | |
136 | <xsl:with-param name="encode-env" select="false()"/> | |
137 | </xsl:call-template> | |
138 | </xsl:variable> | |
139 | <xsl:sequence select="$val/data/value"/> | |
140 | </xsl:for-each> | |
141 | </xsl:variable> | |
142 | <xsl:sequence select="$xctx/value/malval"/> | |
143 | </xsl:for-each> | |
144 | </lvalue> | |
145 | </malval> | |
146 | </value> | |
147 | </xsl:when> | |
148 | <xsl:otherwise> | |
149 | <xsl:sequence select="."/> | |
150 | </xsl:otherwise> | |
151 | </xsl:choose> | |
152 | </xsl:template> | |
153 | <!-- vapply[fn, args] :: fn/value/text() --> | |
154 | <xsl:template name="vapply"> | |
155 | <xsl:param name="func"/> | |
156 | <xsl:param name="args"/> | |
157 | <xsl:choose> | |
158 | <xsl:when test="$func/malval/@kind = 'function'"> | |
159 | <xsl:choose> | |
160 | <xsl:when test="$func/malval/@name = '+'"> | |
161 | <xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) + number($args/value/malval/lvalue/malval[2]/@value)"/> | |
162 | <xsl:sequence select="fn:makeMALType($result, 'number')"/> | |
163 | </xsl:when> | |
164 | <xsl:when test="$func/malval/@name = '-'"> | |
165 | <xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) - number($args/value/malval/lvalue/malval[2]/@value)"/> | |
166 | <xsl:sequence select="fn:makeMALType($result, 'number')"/> | |
167 | </xsl:when> | |
168 | <xsl:when test="$func/malval/@name = '*'"> | |
169 | <xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) * number($args/value/malval/lvalue/malval[2]/@value)"/> | |
170 | <xsl:sequence select="fn:makeMALType($result, 'number')"/> | |
171 | </xsl:when> | |
172 | <xsl:when test="$func/malval/@name = '/'"> | |
173 | <xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) div number($args/value/malval/lvalue/malval[2]/@value)"/> | |
174 | <xsl:sequence select="fn:makeMALType($result, 'number')"/> | |
175 | </xsl:when> | |
176 | <xsl:otherwise> | |
177 | <xsl:value-of select="error(QName('MAL', 'Error'), concat('Invalid function ', $func))"/> | |
178 | </xsl:otherwise> | |
179 | </xsl:choose> | |
180 | </xsl:when> | |
181 | <xsl:otherwise/> | |
182 | </xsl:choose> | |
183 | </xsl:template> | |
184 | <xsl:template name="EVAL"> | |
185 | <xsl:param name="env"/> | |
186 | <xsl:param name="encode-env" select="true()"/> | |
187 | <xsl:variable name="data"> | |
188 | <xsl:choose> | |
189 | <xsl:when test="value/malval/@kind = 'list'"> | |
190 | <xsl:choose> | |
191 | <xsl:when test="count(value/malval/lvalue/malval) = 0"> | |
192 | <xsl:sequence select="."/> | |
193 | <xsl:if test="$encode-env"> | |
194 | <env data="{env:serialise($env)}"/> | |
195 | </xsl:if> | |
196 | </xsl:when> | |
197 | <xsl:otherwise> | |
198 | <xsl:choose> | |
80e3d5eb A |
199 | <xsl:when test="let $fn := value/malval/lvalue/malval[1] |
200 | return $fn/@kind = 'symbol' and | |
201 | $fn/@value = 'def!'"> | |
e4882d7d A |
202 | <xsl:variable name="name"> |
203 | <xsl:value-of select="value/malval/lvalue/malval[2]/@value"/> | |
204 | </xsl:variable> | |
205 | <xsl:variable name="xvalue"> | |
206 | <value> | |
207 | <xsl:sequence select="value/malval/lvalue/malval[3]"/> | |
208 | </value> | |
209 | </xsl:variable> | |
210 | <xsl:variable name="value"> | |
211 | <xsl:for-each select="$xvalue"> | |
212 | <xsl:call-template name="EVAL"> | |
213 | <xsl:with-param name="env" select="$env"/> | |
214 | <xsl:with-param name="encode-env" select="false()"/> | |
215 | </xsl:call-template> | |
216 | </xsl:for-each> | |
217 | </xsl:variable> | |
218 | <xsl:sequence select="$value/data/value"/> | |
219 | <xsl:if test="$encode-env"> | |
220 | <env data="{env:serialise(env:set($env, $name, $value/data/value/malval))}"/> | |
221 | </xsl:if> | |
222 | </xsl:when> | |
80e3d5eb A |
223 | <xsl:when test="let $fn := value/malval/lvalue/malval[1] |
224 | return $fn/@kind = 'symbol' and | |
225 | $fn/@value = 'let*'"> | |
e4882d7d A |
226 | <xsl:variable name="xvalue"> |
227 | <value> | |
228 | <xsl:sequence select="value/malval/lvalue/malval[3]"/> | |
229 | </value> | |
230 | </xsl:variable> | |
231 | <xsl:variable name="new_env" select="env:close($env)"/> | |
232 | <xsl:iterate select="fn:group_consec(value/malval/lvalue/malval[2]/lvalue/malval)"> | |
233 | <xsl:param name="new_env" select="$env"/> | |
234 | <xsl:on-completion> | |
235 | <xsl:variable name="value"> | |
236 | <xsl:for-each select="$xvalue"> | |
237 | <xsl:call-template name="EVAL"> | |
238 | <xsl:with-param name="env" select="$new_env"/> | |
239 | <xsl:with-param name="encode-env" select="false()"/> | |
240 | </xsl:call-template> | |
241 | </xsl:for-each> | |
242 | </xsl:variable> | |
243 | <xsl:sequence select="$value/data/value"/> | |
244 | <xsl:if test="$encode-env"> | |
245 | <env data="{env:serialise($env)}"/> | |
246 | </xsl:if> | |
247 | </xsl:on-completion> | |
248 | <xsl:variable name="name"> | |
249 | <xsl:value-of select="node()[name() = 'first']/malval/@value"/> | |
250 | </xsl:variable> | |
251 | <xsl:variable name="xvalue"> | |
252 | <value> | |
253 | <xsl:sequence select="node()[name() = 'second']/malval"/> | |
254 | </value> | |
255 | </xsl:variable> | |
256 | <xsl:variable name="value"> | |
257 | <xsl:for-each select="$xvalue"> | |
258 | <xsl:call-template name="EVAL"> | |
259 | <xsl:with-param name="env" select="$new_env"/> | |
260 | <xsl:with-param name="encode-env" select="false()"/> | |
261 | </xsl:call-template> | |
262 | </xsl:for-each> | |
263 | </xsl:variable> | |
264 | <xsl:next-iteration> | |
265 | <xsl:with-param name="new_env" select="env:set($new_env, $name, $value/data/value/malval)"/> | |
266 | </xsl:next-iteration> | |
267 | </xsl:iterate> | |
268 | </xsl:when> | |
269 | <xsl:otherwise> | |
270 | <xsl:variable name="new_list"> | |
271 | <xsl:call-template name="eval_ast"> | |
272 | <xsl:with-param name="env" select="$env"/> | |
273 | </xsl:call-template> | |
274 | </xsl:variable> | |
275 | <xsl:variable name="func"> | |
276 | <xsl:for-each select="$new_list"> | |
277 | <xsl:sequence select="value/malval/lvalue/malval[1]"/> | |
278 | </xsl:for-each> | |
279 | </xsl:variable> | |
280 | <xsl:variable name="args"> | |
281 | <xsl:for-each select="$new_list"> | |
282 | <value> | |
283 | <malval kind="list"> | |
284 | <lvalue> | |
285 | <xsl:for-each select="value/malval/lvalue/node()[position() != 1]"> | |
286 | <xsl:sequence select="."/> | |
287 | </xsl:for-each> | |
288 | </lvalue> | |
289 | </malval> | |
290 | </value> | |
291 | </xsl:for-each> | |
292 | </xsl:variable> | |
293 | <xsl:call-template name="vapply"> | |
294 | <xsl:with-param name="func" select="$func"/> | |
295 | <xsl:with-param name="args" select="$args"/> | |
296 | </xsl:call-template> | |
297 | <xsl:if test="$encode-env"> | |
298 | <env data="{env:serialise($env)}"/> | |
299 | </xsl:if> | |
300 | </xsl:otherwise> | |
301 | </xsl:choose> | |
302 | </xsl:otherwise> | |
303 | </xsl:choose> | |
304 | </xsl:when> | |
305 | <xsl:otherwise> | |
306 | <xsl:call-template name="eval_ast"> | |
307 | <xsl:with-param name="env" select="$env"/> | |
308 | </xsl:call-template> | |
309 | <xsl:if test="$encode-env"> | |
310 | <env data="{env:serialise($env)}"/> | |
311 | </xsl:if> | |
312 | </xsl:otherwise> | |
313 | </xsl:choose> | |
314 | </xsl:variable> | |
315 | <data> | |
316 | <xsl:sequence select="$data/value"/> | |
317 | </data> | |
318 | <xsl:if test="$encode-env"> | |
319 | <env data="{$data/env/@data}"/> | |
320 | </xsl:if> | |
321 | </xsl:template> | |
322 | <xsl:template name="READ"> | |
323 | <xsl:variable name="context"> | |
324 | <str> | |
325 | <xsl:copy-of select="stdin/text()"/> | |
326 | </str> | |
327 | </xsl:variable> | |
328 | <xsl:variable name="form"> | |
329 | <xsl:for-each select="$context"> | |
330 | <xsl:call-template name="malreader-read_str"/> | |
331 | </xsl:for-each> | |
332 | </xsl:variable> | |
333 | <xsl:for-each select="$form"> | |
334 | <xsl:if test="error"> | |
335 | <xsl:value-of select="error(QName('MAL', 'Error'), string(error))"/> | |
336 | </xsl:if> | |
337 | <xsl:copy-of select="."/> | |
338 | </xsl:for-each> | |
339 | </xsl:template> | |
340 | <xsl:function name="fn:makeMALType"> | |
341 | <xsl:param name="value"/> | |
342 | <xsl:param name="kind"/> | |
343 | <value> | |
344 | <malval kind="{$kind}" value="{$value}"/> | |
345 | </value> | |
346 | </xsl:function> | |
347 | <xsl:function name="fn:group_consec"> | |
348 | <xsl:param name="nodes"/> | |
349 | <xsl:variable name="groups"> | |
350 | <xsl:for-each-group select="$nodes" group-by="position() mod 2"> | |
351 | <xsl:choose> | |
352 | <xsl:when test="position() = 1"> | |
353 | <first> | |
354 | <xsl:sequence select="current-group()"/> | |
355 | </first> | |
356 | </xsl:when> | |
357 | <xsl:otherwise> | |
358 | <second> | |
359 | <xsl:sequence select="current-group()"/> | |
360 | </second> | |
361 | </xsl:otherwise> | |
362 | </xsl:choose> | |
363 | </xsl:for-each-group> | |
364 | </xsl:variable> | |
365 | <xsl:iterate select="1 to count($groups/first/*)"> | |
366 | <element> | |
367 | <xsl:variable name="idx" select="number(.)"/> | |
368 | <first> | |
369 | <xsl:sequence select="$groups/first/node()[position() = $idx]"/> | |
370 | </first> | |
371 | <second> | |
372 | <xsl:sequence select="$groups/second/node()[position() = $idx]"/> | |
373 | </second> | |
374 | </element> | |
375 | </xsl:iterate> | |
376 | </xsl:function> | |
377 | </xsl:stylesheet> |