258eec2b1415d95992b2b683aca0ce37c56783f6
[jackhill/mal.git] / impls / xslt / core.xslt
1 <?xml version="1.0" encoding="UTF-8"?>
2 <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:core="CORE" version="3.0" exclude-result-prefixes="core fn xsl xs">
3 <xsl:function name="core:ns">
4 <xsl:sequence>
5 <malval kind="function" name="+">
6 <is_macro>false</is_macro>
7 </malval>
8 <malval kind="function" name="-">
9 <is_macro>false</is_macro>
10 </malval>
11 <malval kind="function" name="*">
12 <is_macro>false</is_macro>
13 </malval>
14 <malval kind="function" name="/">
15 <is_macro>false</is_macro>
16 </malval>
17 <malval kind="function" name="prn">
18 <is_macro>false</is_macro>
19 </malval>
20 <malval kind="function" name="pr-str">
21 <is_macro>false</is_macro>
22 </malval>
23 <malval kind="function" name="str">
24 <is_macro>false</is_macro>
25 </malval>
26 <malval kind="function" name="println">
27 <is_macro>false</is_macro>
28 </malval>
29 <malval kind="function" name="list">
30 <is_macro>false</is_macro>
31 </malval>
32 <malval kind="function" name="list?">
33 <is_macro>false</is_macro>
34 </malval>
35 <malval kind="function" name="empty?">
36 <is_macro>false</is_macro>
37 </malval>
38 <malval kind="function" name="count">
39 <is_macro>false</is_macro>
40 </malval>
41 <malval kind="function" name="=">
42 <is_macro>false</is_macro>
43 </malval>
44 <malval kind="function" name="&lt;">
45 <is_macro>false</is_macro>
46 </malval>
47 <malval kind="function" name="&lt;=">
48 <is_macro>false</is_macro>
49 </malval>
50 <malval kind="function" name="&gt;">
51 <is_macro>false</is_macro>
52 </malval>
53 <malval kind="function" name="&gt;=">
54 <is_macro>false</is_macro>
55 </malval>
56 <malval kind="function" name="read-string">
57 <is_macro>false</is_macro>
58 </malval>
59 <malval kind="function" name="slurp">
60 <is_macro>false</is_macro>
61 </malval>
62 <malval kind="function" name="eval">
63 <is_macro>false</is_macro>
64 </malval>
65 <!-- defined in the step files -->
66 <malval kind="function" name="atom">
67 <is_macro>false</is_macro>
68 </malval>
69 <!-- defined in the step files -->
70 <malval kind="function" name="atom?">
71 <is_macro>false</is_macro>
72 </malval>
73 <malval kind="function" name="deref">
74 <is_macro>false</is_macro>
75 </malval>
76 <!-- defined in the step files -->
77 <malval kind="function" name="swap!">
78 <is_macro>false</is_macro>
79 </malval>
80 <!-- defined in the step files -->
81 <malval kind="function" name="reset!">
82 <is_macro>false</is_macro>
83 </malval>
84 <!-- defined in the step files -->
85 <malval kind="function" name="cons">
86 <is_macro>false</is_macro>
87 </malval>
88 <malval kind="function" name="concat">
89 <is_macro>false</is_macro>
90 </malval>
91 <malval kind="function" name="nth">
92 <is_macro>false</is_macro>
93 </malval>
94 <malval kind="function" name="first">
95 <is_macro>false</is_macro>
96 </malval>
97 <malval kind="function" name="rest">
98 <is_macro>false</is_macro>
99 </malval>
100 <malval kind="function" name="throw">
101 <is_macro>false</is_macro>
102 </malval>
103 <malval kind="function" name="apply">
104 <is_macro>false</is_macro>
105 </malval>
106 <!-- defined in the step files -->
107 <malval kind="function" name="map">
108 <is_macro>false</is_macro>
109 </malval>
110 <!-- defined in the step files -->
111 <malval kind="function" name="nil?">
112 <is_macro>false</is_macro>
113 </malval>
114 <malval kind="function" name="true?">
115 <is_macro>false</is_macro>
116 </malval>
117 <malval kind="function" name="false?">
118 <is_macro>false</is_macro>
119 </malval>
120 <malval kind="function" name="symbol?">
121 <is_macro>false</is_macro>
122 </malval>
123 <malval kind="function" name="symbol">
124 <is_macro>false</is_macro>
125 </malval>
126 <malval kind="function" name="keyword">
127 <is_macro>false</is_macro>
128 </malval>
129 <malval kind="function" name="keyword?">
130 <is_macro>false</is_macro>
131 </malval>
132 <malval kind="function" name="vector">
133 <is_macro>false</is_macro>
134 </malval>
135 <malval kind="function" name="vector?">
136 <is_macro>false</is_macro>
137 </malval>
138 <malval kind="function" name="sequential?">
139 <is_macro>false</is_macro>
140 </malval>
141 <malval kind="function" name="hash-map">
142 <is_macro>false</is_macro>
143 </malval>
144 <malval kind="function" name="map?">
145 <is_macro>false</is_macro>
146 </malval>
147 <malval kind="function" name="assoc">
148 <is_macro>false</is_macro>
149 </malval>
150 <malval kind="function" name="dissoc">
151 <is_macro>false</is_macro>
152 </malval>
153 <malval kind="function" name="get">
154 <is_macro>false</is_macro>
155 </malval>
156 <malval kind="function" name="contains?">
157 <is_macro>false</is_macro>
158 </malval>
159 <malval kind="function" name="keys">
160 <is_macro>false</is_macro>
161 </malval>
162 <malval kind="function" name="vals">
163 <is_macro>false</is_macro>
164 </malval>
165 <malval kind="function" name="readline">
166 <is_macro>false</is_macro>
167 </malval>
168 <!-- defined in step file -->
169 <malval kind="function" name="meta">
170 <is_macro>false</is_macro>
171 </malval>
172 <malval kind="function" name="with-meta">
173 <is_macro>false</is_macro>
174 </malval>
175 <malval kind="function" name="time-ms">
176 <is_macro>false</is_macro>
177 </malval>
178 <malval kind="function" name="conj">
179 <is_macro>false</is_macro>
180 </malval>
181 <malval kind="function" name="string?">
182 <is_macro>false</is_macro>
183 </malval>
184 <malval kind="function" name="number?">
185 <is_macro>false</is_macro>
186 </malval>
187 <malval kind="function" name="fn?">
188 <is_macro>false</is_macro>
189 </malval>
190 <malval kind="function" name="macro?">
191 <is_macro>false</is_macro>
192 </malval>
193 <malval kind="function" name="seq">
194 <is_macro>false</is_macro>
195 </malval>
196 <malval kind="function" name="xpath-eval">
197 <is_macro>false</is_macro>
198 </malval>
199 <!-- evaluate xpath, no context node | requires Saxon PE/EE [paywalls piss me off] -->
200 </xsl:sequence>
201 </xsl:function>
202 <xsl:template name="core-apply">
203 <xsl:param name="func"/>
204 <xsl:param name="args"/>
205 <xsl:variable name="atoms" select="atoms"/>
206 <xsl:choose>
207 <xsl:when test="$func/malval/@kind = 'function'">
208 <xsl:choose>
209 <xsl:when test="$func/malval/@name = '+'">
210 <xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) + number($args/value/malval/lvalue/malval[2]/@value)"/>
211 <xsl:sequence select="core:makeMALType($result, 'number')"/>
212 </xsl:when>
213 <xsl:when test="$func/malval/@name = '-'">
214 <xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) - number($args/value/malval/lvalue/malval[2]/@value)"/>
215 <xsl:sequence select="core:makeMALType($result, 'number')"/>
216 </xsl:when>
217 <xsl:when test="$func/malval/@name = '*'">
218 <xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) * number($args/value/malval/lvalue/malval[2]/@value)"/>
219 <xsl:sequence select="core:makeMALType($result, 'number')"/>
220 </xsl:when>
221 <xsl:when test="$func/malval/@name = '/'">
222 <xsl:variable name="result" select="number($args/value/malval/lvalue/malval[1]/@value) div number($args/value/malval/lvalue/malval[2]/@value)"/>
223 <xsl:sequence select="core:makeMALType($result, 'number')"/>
224 </xsl:when>
225 <xsl:when test="$func/malval/@name = 'prn'">
226 <xsl:variable name="args" select="$args/value/malval/lvalue/malval"/>
227 <xsl:variable name="sargs">
228 <xsl:for-each select="$args">
229 <xsl:variable name="arg">
230 <value>
231 <xsl:sequence select="."/>
232 </value>
233 <xsl:sequence select="$atoms"/>
234 </xsl:variable>
235 <str>
236 <xsl:for-each select="$arg">
237 <xsl:call-template name="malprinter-pr_str">
238 <xsl:with-param name="readably" select="true()"/>
239 </xsl:call-template>
240 </xsl:for-each>
241 </str>
242 </xsl:for-each>
243 </xsl:variable>
244 <xsl:message>
245 <request kind="display" value="{string-join($sargs/str, ' ')}"/>
246 </xsl:message>
247 <xsl:sequence select="core:makeMALType((), 'nil')"/>
248 </xsl:when>
249 <xsl:when test="$func/malval/@name = 'pr-str'">
250 <xsl:variable name="args" select="$args/value/malval/lvalue/malval"/>
251 <xsl:variable name="sargs">
252 <xsl:for-each select="$args">
253 <xsl:variable name="arg">
254 <value>
255 <xsl:sequence select="."/>
256 </value>
257 <xsl:sequence select="$atoms"/>
258 </xsl:variable>
259 <str>
260 <xsl:for-each select="$arg">
261 <xsl:call-template name="malprinter-pr_str">
262 <xsl:with-param name="readably" select="true()"/>
263 </xsl:call-template>
264 </xsl:for-each>
265 </str>
266 </xsl:for-each>
267 </xsl:variable>
268 <xsl:sequence select="core:makeMALType(string-join($sargs/str, ' '), 'string')"/>
269 </xsl:when>
270 <xsl:when test="$func/malval/@name = 'str'">
271 <xsl:variable name="args" select="$args/value/malval/lvalue/malval"/>
272 <xsl:variable name="sargs">
273 <xsl:for-each select="$args">
274 <xsl:variable name="arg">
275 <value>
276 <xsl:sequence select="."/>
277 </value>
278 <xsl:sequence select="$atoms"/>
279 </xsl:variable>
280 <str>
281 <xsl:for-each select="$arg">
282 <xsl:call-template name="malprinter-pr_str">
283 <xsl:with-param name="readably" select="false()"/>
284 </xsl:call-template>
285 </xsl:for-each>
286 </str>
287 </xsl:for-each>
288 </xsl:variable>
289 <xsl:sequence select="core:makeMALType(string-join($sargs/str, ''), 'string')"/>
290 </xsl:when>
291 <xsl:when test="$func/malval/@name = 'println'">
292 <xsl:variable name="args" select="$args/value/malval/lvalue/malval"/>
293 <xsl:variable name="sargs">
294 <xsl:for-each select="$args">
295 <xsl:variable name="arg">
296 <value>
297 <xsl:sequence select="."/>
298 </value>
299 <xsl:sequence select="$atoms"/>
300 </xsl:variable>
301 <str>
302 <xsl:for-each select="$arg">
303 <xsl:call-template name="malprinter-pr_str">
304 <xsl:with-param name="readably" select="false()"/>
305 </xsl:call-template>
306 </xsl:for-each>
307 </str>
308 </xsl:for-each>
309 </xsl:variable>
310 <xsl:message>
311 <request kind="display" value="{string-join($sargs/str, ' ')}"/>
312 </xsl:message>
313 <xsl:sequence select="core:makeMALType((), 'nil')"/>
314 </xsl:when>
315 <xsl:when test="$func/malval/@name = 'list'">
316 <xsl:sequence select="$args"/>
317 </xsl:when>
318 <xsl:when test="$func/malval/@name = 'list?'">
319 <xsl:sequence select="core:makeMALType((), if ($args/value/malval/lvalue/malval[1]/@kind = 'list') then 'true' else 'false')"/>
320 </xsl:when>
321 <xsl:when test="$func/malval/@name = 'empty?'">
322 <xsl:sequence select="core:makeMALType((), if (count($args/value/malval/lvalue/malval[1]/lvalue/malval) = 0) then 'true' else 'false')"/>
323 </xsl:when>
324 <xsl:when test="$func/malval/@name = 'count'">
325 <xsl:choose>
326 <xsl:when test="$args/value/malval/lvalue/malval[1]/@kind = 'hash'">
327 <xsl:sequence select="core:makeMALType(count($args/value/malval/lvalue/malval[1]/lvalue/malval) div 2, 'number')"/>
328 </xsl:when>
329 <xsl:otherwise>
330 <xsl:sequence select="core:makeMALType(count($args/value/malval/lvalue/malval[1]/lvalue/malval), 'number')"/>
331 </xsl:otherwise>
332 </xsl:choose>
333 </xsl:when>
334 <xsl:when test="$func/malval/@name = '='">
335 <xsl:sequence select="core:makeMALType((), if (core:equal($args/value/malval/lvalue/malval[1], $args/value/malval/lvalue/malval[2])) then 'true' else 'false')"/>
336 </xsl:when>
337 <xsl:when test="$func/malval/@name = '&lt;'">
338 <xsl:sequence select="core:makeMALType((), if (number($args/value/malval/lvalue/malval[1]/@value) lt number($args/value/malval/lvalue/malval[2]/@value)) then 'true' else 'false')"/>
339 </xsl:when>
340 <xsl:when test="$func/malval/@name = '&lt;='">
341 <xsl:sequence select="core:makeMALType((), if (number($args/value/malval/lvalue/malval[1]/@value) le number($args/value/malval/lvalue/malval[2]/@value)) then 'true' else 'false')"/>
342 </xsl:when>
343 <xsl:when test="$func/malval/@name = '&gt;'">
344 <xsl:sequence select="core:makeMALType((), if (number($args/value/malval/lvalue/malval[1]/@value) gt number($args/value/malval/lvalue/malval[2]/@value)) then 'true' else 'false')"/>
345 </xsl:when>
346 <xsl:when test="$func/malval/@name = '&gt;='">
347 <xsl:sequence select="core:makeMALType((), if (number($args/value/malval/lvalue/malval[1]/@value) ge number($args/value/malval/lvalue/malval[2]/@value)) then 'true' else 'false')"/>
348 </xsl:when>
349 <xsl:when test="$func/malval/@name = 'read-string'">
350 <xsl:variable name="read-string-context">
351 <str>
352 <xsl:value-of select="$args/value/malval/lvalue/malval[1]/@value"/>
353 </str>
354 </xsl:variable>
355 <xsl:for-each select="$read-string-context">
356 <xsl:call-template name="malreader-read_str"/>
357 </xsl:for-each>
358 </xsl:when>
359 <xsl:when test="$func/malval/@name = 'slurp'">
360 <xsl:sequence select="core:makeMALType(unparsed-text($args/value/malval/lvalue/malval[1]/@value), 'string')"/>
361 </xsl:when>
362 <xsl:when test="$func/malval/@name = 'atom?'">
363 <xsl:sequence select="core:makeMALType((), if ($args/value/malval/lvalue/malval[1]/@kind = 'atom') then 'true' else 'false')"/>
364 </xsl:when>
365 <xsl:when test="$func/malval/@name = 'cons'">
366 <xsl:variable name="result">
367 <value>
368 <malval kind="list">
369 <lvalue>
370 <xsl:sequence select="$args/value/malval/lvalue/malval[1]"/>
371 <xsl:sequence select="$args/value/malval/lvalue/malval[2]/lvalue/malval"/>
372 </lvalue>
373 </malval>
374 </value>
375 </xsl:variable>
376 <xsl:sequence select="$result"/>
377 </xsl:when>
378 <xsl:when test="$func/malval/@name = 'concat'">
379 <xsl:variable name="result">
380 <value>
381 <malval kind="list">
382 <lvalue>
383 <xsl:sequence select="$args/value/malval/lvalue/malval/lvalue/malval"/>
384 </lvalue>
385 </malval>
386 </value>
387 </xsl:variable>
388 <xsl:sequence select="$result"/>
389 </xsl:when>
390 <xsl:when test="$func/malval/@name = 'nth'">
391 <value>
392 <xsl:variable name="res" select="$args/value/malval/lvalue/malval[1]/lvalue/malval[position() = (number($args/value/malval/lvalue/malval[2]/@value) + 1)]"/>
393 <xsl:if test="empty($res)">
394 <xsl:value-of select="error(QName('MAL', 'Error'), 'Index out of bounds', core:makeMALValue('Index out of bounds', 'string'))"/>
395 </xsl:if>
396 <xsl:sequence select="$res"/>
397 </value>
398 </xsl:when>
399 <xsl:when test="$func/malval/@name = 'first'">
400 <value>
401 <xsl:variable name="res" select="$args/value/malval/lvalue/malval[1]/lvalue/malval[1]"/>
402 <xsl:choose>
403 <xsl:when test="empty($res)">
404 <malval kind="nil"/>
405 </xsl:when>
406 <xsl:otherwise>
407 <xsl:sequence select="$res"/>
408 </xsl:otherwise>
409 </xsl:choose>
410 </value>
411 </xsl:when>
412 <xsl:when test="$func/malval/@name = 'rest'">
413 <value>
414 <malval kind="list">
415 <lvalue>
416 <xsl:sequence select="$args/value/malval/lvalue/malval[1]/lvalue/malval[position() &gt; 1]"/>
417 </lvalue>
418 </malval>
419 </value>
420 </xsl:when>
421 <xsl:when test="$func/malval/@name = 'throw'">
422 <xsl:variable name="err" select="$args/value/malval/lvalue/malval[1]"/>
423 <xsl:value-of select="error(QName('MAL', 'Error'), core:pr-str($err), $err)"/>
424 </xsl:when>
425 <xsl:when test="$func/malval/@name = 'nil?'">
426 <xsl:sequence select="core:makeMALType((), if ($args/value/malval/lvalue/malval[1]/@kind = 'nil') then 'true' else 'false')"/>
427 </xsl:when>
428 <xsl:when test="$func/malval/@name = 'true?'">
429 <xsl:sequence select="core:makeMALType((), if ($args/value/malval/lvalue/malval[1]/@kind = 'true') then 'true' else 'false')"/>
430 </xsl:when>
431 <xsl:when test="$func/malval/@name = 'false?'">
432 <xsl:sequence select="core:makeMALType((), if ($args/value/malval/lvalue/malval[1]/@kind = 'false') then 'true' else 'false')"/>
433 </xsl:when>
434 <xsl:when test="$func/malval/@name = 'symbol?'">
435 <xsl:sequence select="core:makeMALType((), if ($args/value/malval/lvalue/malval[1]/@kind = 'symbol') then 'true' else 'false')"/>
436 </xsl:when>
437 <xsl:when test="$func/malval/@name = 'symbol'">
438 <xsl:sequence select="core:makeMALType($args/value/malval/lvalue/malval[1]/@value, 'symbol')"/>
439 </xsl:when>
440 <xsl:when test="$func/malval/@name = 'keyword'">
441 <xsl:sequence select="core:makeMALType($args/value/malval/lvalue/malval[1]/@value, 'keyword')"/>
442 </xsl:when>
443 <xsl:when test="$func/malval/@name = 'keyword?'">
444 <xsl:sequence select="core:makeMALType((), if ($args/value/malval/lvalue/malval[1]/@kind = 'keyword') then 'true' else 'false')"/>
445 </xsl:when>
446 <xsl:when test="$func/malval/@name = 'vector'">
447 <value>
448 <malval kind="vector">
449 <xsl:sequence select="$args/value/malval/lvalue"/>
450 </malval>
451 </value>
452 </xsl:when>
453 <xsl:when test="$func/malval/@name = 'vector?'">
454 <xsl:sequence select="core:makeMALType((), if ($args/value/malval/lvalue/malval[1]/@kind = 'vector') then 'true' else 'false')"/>
455 </xsl:when>
456 <xsl:when test="$func/malval/@name = 'sequential?'">
457 <xsl:sequence select="core:makeMALType((), if (let $kind := $args/value/malval/lvalue/malval[1]/@kind return $kind = 'vector' or $kind = 'list') then 'true' else 'false')"/>
458 </xsl:when>
459 <xsl:when test="$func/malval/@name = 'hash-map'">
460 <xsl:if test="count($args/value/malval/lvalue/malval) mod 2 = 1">
461 <xsl:value-of select="error(QName('MAL', 'Error'), 'Odd number of args to hash-map', core:makeMALValue('Odd number of args to hash-map', 'string'))"/>
462 </xsl:if>
463 <value>
464 <malval kind="hash">
465 <xsl:sequence select="$args/value/malval/lvalue"/>
466 </malval>
467 </value>
468 </xsl:when>
469 <xsl:when test="$func/malval/@name = 'map?'">
470 <xsl:sequence select="core:makeMALType((), if ($args/value/malval/lvalue/malval[1]/@kind = 'hash') then 'true' else 'false')"/>
471 </xsl:when>
472 <xsl:when test="$func/malval/@name = 'assoc'">
473 <xsl:if test="count($args/value/malval/lvalue/malval) mod 2 = 0">
474 <xsl:value-of select="error(QName('MAL', 'Error'), 'Odd number of args to assoc', core:makeMALValue('Odd number of args to assoc', 'string'))"/>
475 </xsl:if>
476 <xsl:variable name="names" select="$args/value/malval/lvalue/malval[(position() gt 1) and (position() mod 2 = 0)]"/>
477 <xsl:variable name="values" select="$args/value/malval/lvalue/malval[(position() gt 2) and (position() mod 2 = 1)]"/>
478 <xsl:sequence select="let $hash := $args/value/malval/lvalue/malval[1] return core:map-dissoc($hash/lvalue/malval, $names) =&gt; core:map-assoc($names, $values) =&gt; core:makeMALList('hash')"/>
479 </xsl:when>
480 <xsl:when test="$func/malval/@name = 'dissoc'">
481 <xsl:variable name="names" select="$args/value/malval/lvalue/malval[position() gt 1]"/>
482 <xsl:sequence select="let $hash := $args/value/malval/lvalue/malval[1] return core:map-dissoc($hash/lvalue/malval, $names) =&gt; core:makeMALList('hash')"/>
483 </xsl:when>
484 <xsl:when test="$func/malval/@name = 'get'">
485 <xsl:variable name="name" select="$args/value/malval/lvalue/malval[2]"/>
486 <value>
487 <xsl:sequence select="let $hash := $args/value/malval/lvalue/malval[1] return (core:map-get($hash/lvalue/malval, $name), core:makeMALValue((), 'nil'))[1]"/>
488 </value>
489 </xsl:when>
490 <xsl:when test="$func/malval/@name = 'contains?'">
491 <xsl:variable name="name" select="$args/value/malval/lvalue/malval[2]"/>
492 <xsl:sequence select="let $hash := $args/value/malval/lvalue/malval[1] return core:makeMALType((), if (empty(core:map-get($hash/lvalue/malval, $name))) then 'false' else 'true')"/>
493 </xsl:when>
494 <xsl:when test="$func/malval/@name = 'keys'">
495 <xsl:sequence select="let $hash := $args/value/malval/lvalue/malval[1] return ($hash/lvalue/malval[position() mod 2 = 1]) =&gt; core:makeMALList('list')"/>
496 </xsl:when>
497 <xsl:when test="$func/malval/@name = 'vals'">
498 <xsl:sequence select="let $hash := $args/value/malval/lvalue/malval[1] return ($hash/lvalue/malval[position() mod 2 = 0]) =&gt; core:makeMALList('list')"/>
499 </xsl:when>
500 <xsl:when test="$func/malval/@name = 'meta'">
501 <value>
502 <xsl:sequence select="($args/value/malval/lvalue/malval[1]/meta/malval, core:makeMALValue((), 'nil'))[1]"/>
503 </value>
504 </xsl:when>
505 <xsl:when test="$func/malval/@name = 'with-meta'">
506 <value>
507 <malval>
508 <xsl:sequence select="$args/value/malval/lvalue/malval[1]/(*[name() != 'meta']|@*)"/>
509 <meta>
510 <xsl:sequence select="$args/value/malval/lvalue/malval[2]"/>
511 </meta>
512 </malval>
513 </value>
514 </xsl:when>
515 <xsl:when test="$func/malval/@name = 'time-ms'">
516 <!-- current-dateTime() does not change while transforming :( -->
517 <xsl:sequence select="core:makeMALType(core:mstime(), 'number')"/>
518 </xsl:when>
519 <xsl:when test="$func/malval/@name = 'conj'">
520 <xsl:variable name="xargs" select="$args/value/malval/lvalue/malval[position() &gt; 1]"/>
521 <xsl:variable name="coll">
522 <xsl:sequence select="$args/value/malval/lvalue/malval[1]"/>
523 </xsl:variable>
524 <value>
525 <xsl:choose>
526 <xsl:when test="$coll/malval/@kind = 'list'">
527 <malval kind="list">
528 <lvalue>
529 <xsl:sequence select="reverse($xargs)"/>
530 <xsl:sequence select="$coll/malval/lvalue/malval"/>
531 </lvalue>
532 </malval>
533 </xsl:when>
534 <xsl:otherwise>
535 <malval kind="vector">
536 <lvalue>
537 <xsl:sequence select="$coll/malval/lvalue/malval"/>
538 <xsl:sequence select="$xargs"/>
539 </lvalue>
540 </malval>
541 </xsl:otherwise>
542 </xsl:choose>
543 </value>
544 </xsl:when>
545 <xsl:when test="$func/malval/@name = 'string?'">
546 <xsl:sequence select="core:makeMALType((), if ($args/value/malval/lvalue/malval[1]/@kind = 'string') then 'true' else 'false')"/>
547 </xsl:when>
548 <xsl:when test="$func/malval/@name = 'number?'">
549 <xsl:sequence select="core:makeMALType((), if ($args/value/malval/lvalue/malval[1]/@kind = 'number') then 'true' else 'false')"/>
550 </xsl:when>
551 <xsl:when test="$func/malval/@name = 'fn?'">
552 <xsl:sequence select="core:makeMALType((), if (let $f := $args/value/malval/lvalue/malval[1] return ($f/@kind = 'userfunction' or $f/@kind = 'function') and $f/is_macro/text() != 'true') then 'true' else 'false')"/>
553 </xsl:when>
554 <xsl:when test="$func/malval/@name = 'macro?'">
555 <xsl:sequence select="core:makeMALType((), if (let $f := $args/value/malval/lvalue/malval[1] return ($f/@kind = 'userfunction' or $f/@kind = 'function') and $f/is_macro/text() = 'true') then 'true' else 'false')"/>
556 </xsl:when>
557 <xsl:when test="$func/malval/@name = 'seq'">
558 <xsl:variable name="arg" select="$args/value/malval/lvalue/malval[1]"/>
559 <xsl:choose>
560 <xsl:when test="$arg/@kind = 'string'">
561 <xsl:choose>
562 <xsl:when test="string-length($arg/@value) = 0">
563 <xsl:sequence select="core:makeMALType((), 'nil')"/>
564 </xsl:when>
565 <xsl:otherwise>
566 <value>
567 <malval kind="list">
568 <lvalue>
569 <xsl:for-each select="string-to-codepoints($arg/@value)">
570 <xsl:sequence select="core:makeMALValue(codepoints-to-string(.), 'string')"/>
571 </xsl:for-each>
572 </lvalue>
573 </malval>
574 </value>
575 </xsl:otherwise>
576 </xsl:choose>
577 </xsl:when>
578 <xsl:otherwise>
579 <xsl:choose>
580 <xsl:when test="count($arg/lvalue/malval) = 0">
581 <xsl:sequence select="core:makeMALType((), 'nil')"/>
582 </xsl:when>
583 <xsl:otherwise>
584 <value>
585 <malval kind="list">
586 <xsl:sequence select="$arg/lvalue"/>
587 </malval>
588 </value>
589 </xsl:otherwise>
590 </xsl:choose>
591 </xsl:otherwise>
592 </xsl:choose>
593 </xsl:when>
594 <xsl:when test="$func/malval/@name = 'xpath-eval'">
595 <xsl:message>
596 <request kind="xpath-eval" value="{$args/value/malval/lvalue/malval[1]/@value}" context="{$args/value/malval/lvalue/malval[2] =&gt; serialize()}"/>
597 </xsl:message>
598 <value>
599 <xsl:sequence select="document('xsl_input-string')"/>
600 </value>
601 </xsl:when>
602 <xsl:otherwise>
603 <xsl:value-of select="error(QName('MAL', 'Error'), concat('Invalid function ', $func/malval/@name), core:makeMALValue(concat('Invalid function ', $func/malval/@name), 'string'))"/>
604 </xsl:otherwise>
605 </xsl:choose>
606 </xsl:when>
607 <xsl:otherwise/>
608 </xsl:choose>
609 </xsl:template>
610 <xsl:function name="core:makeMALList">
611 <xsl:param name="values"/>
612 <xsl:param name="kind"/>
613 <value>
614 <malval kind="{$kind}">
615 <lvalue>
616 <xsl:sequence select="$values"/>
617 </lvalue>
618 </malval>
619 </value>
620 </xsl:function>
621 <xsl:function name="core:makeMALType">
622 <xsl:param name="value"/>
623 <xsl:param name="kind"/>
624 <value>
625 <malval kind="{$kind}" value="{$value}"/>
626 </value>
627 </xsl:function>
628 <xsl:function name="core:makeMALValue">
629 <xsl:param name="value"/>
630 <xsl:param name="kind"/>
631 <malval kind="{$kind}" value="{$value}"/>
632 </xsl:function>
633 <xsl:function name="core:pr-str">
634 <xsl:param name="value"/>
635 <xsl:variable name="ctx">
636 <value>
637 <xsl:sequence select="$value"/>
638 </value>
639 </xsl:variable>
640 <xsl:variable name="res">
641 <xsl:for-each select="$ctx">
642 <xsl:call-template name="malprinter-pr_str">
643 <xsl:with-param name="readably" select="true()"/>
644 </xsl:call-template>
645 </xsl:for-each>
646 </xsl:variable>
647 <xsl:sequence select="$res"/>
648 </xsl:function>
649 <xsl:function name="core:all-equal">
650 <xsl:param name="seq"/>
651 <xsl:param name="left"/>
652 <xsl:param name="right"/>
653 <xsl:choose>
654 <xsl:when test="empty($seq)">
655 <xsl:sequence select="true()"/>
656 </xsl:when>
657 <xsl:otherwise>
658 <xsl:choose>
659 <xsl:when test="core:list-equal($left, $right, head($seq))">
660 <xsl:sequence select="core:all-equal(tail($seq), $right, $left)"/>
661 </xsl:when>
662 <xsl:otherwise>
663 <xsl:sequence select="false()"/>
664 </xsl:otherwise>
665 </xsl:choose>
666 </xsl:otherwise>
667 </xsl:choose>
668 </xsl:function>
669 <xsl:function name="core:any-equal">
670 <xsl:param name="comps"/>
671 <xsl:param name="value"/>
672 <xsl:choose>
673 <xsl:when test="empty($comps)">
674 <xsl:sequence select="false()"/>
675 </xsl:when>
676 <xsl:when test="core:equal($value, head($comps))">
677 <xsl:sequence select="true()"/>
678 </xsl:when>
679 <xsl:otherwise>
680 <xsl:sequence select="core:any-equal(tail($comps), $value)"/>
681 </xsl:otherwise>
682 </xsl:choose>
683 </xsl:function>
684 <xsl:function name="core:map-values-equal">
685 <xsl:param name="ma"/>
686 <xsl:param name="mb"/>
687 <xsl:choose>
688 <xsl:when test="empty($ma)">
689 <xsl:sequence select="true()"/>
690 </xsl:when>
691 <xsl:otherwise>
692 <xsl:sequence select="core:equal($ma[2], core:map-get($mb, $ma[1])) and core:map-values-equal($ma[position() gt 2], $mb)"/>
693 </xsl:otherwise>
694 </xsl:choose>
695 </xsl:function>
696 <xsl:function name="core:equal">
697 <xsl:param name="left"/>
698 <xsl:param name="right"/>
699 <xsl:choose>
700 <!-- equal kinds -->
701 <xsl:when test="$left/@kind = $right/@kind">
702 <xsl:choose>
703 <xsl:when test="$left/@kind = 'hash' and $right/@kind = 'hash'">
704 <!-- counts are equal, check if all keys share the same value -->
705 <xsl:sequence select="core:map-values-equal($left/lvalue/malval, $right/lvalue/malval)"/>
706 </xsl:when>
707 <!-- sequence? -->
708 <xsl:when test="$left/@kind = 'list' or $left/@kind = 'vector' or $left/@kind = 'hash'">
709 <xsl:choose>
710 <!-- same counts -->
711 <xsl:when test="count($left/lvalue/malval) = count($right/lvalue/malval)">
712 <xsl:sequence select="core:all-equal(1 to count($left/lvalue/malval), $left, $right)"/>
713 </xsl:when>
714 <!-- different counts -->
715 <xsl:otherwise>
716 <xsl:sequence select="false()"/>
717 </xsl:otherwise>
718 </xsl:choose>
719 </xsl:when>
720 <!-- simple 'value' type -->
721 <xsl:otherwise>
722 <xsl:sequence select="string($left/@value) = string($right/@value)"/>
723 </xsl:otherwise>
724 </xsl:choose>
725 </xsl:when>
726 <!-- different types -->
727 <xsl:otherwise>
728 <xsl:choose>
729 <xsl:when test="($left/@kind = 'list' and $right/@kind = 'vector') or ($left/@kind = 'vector' and $right/@kind = 'list')">
730 <xsl:choose>
731 <!-- same counts -->
732 <xsl:when test="count($left/lvalue/malval) = count($right/lvalue/malval)">
733 <xsl:sequence select="core:all-equal(1 to count($left/lvalue/malval), $left, $right)"/>
734 </xsl:when>
735 <!-- different counts -->
736 <xsl:otherwise>
737 <xsl:sequence select="false()"/>
738 </xsl:otherwise>
739 </xsl:choose>
740 </xsl:when>
741 <xsl:otherwise>
742 <xsl:sequence select="false()"/>
743 </xsl:otherwise>
744 </xsl:choose>
745 </xsl:otherwise>
746 </xsl:choose>
747 </xsl:function>
748 <xsl:function name="core:list-equal">
749 <xsl:param name="l"/>
750 <xsl:param name="r"/>
751 <xsl:param name="v"/>
752 <xsl:sequence select="core:equal($l/lvalue/malval[$v], $r/lvalue/malval[$v])"/>
753 </xsl:function>
754 <xsl:function name="core:map-assoc">
755 <xsl:param name="map"/>
756 <xsl:param name="names"/>
757 <xsl:param name="values"/>
758 <xsl:sequence select="$map"/>
759 <xsl:for-each select="1 to count($names)">
760 <xsl:variable name="idx" select="position()"/>
761 <xsl:sequence select="$names[position() = $idx]"/>
762 <xsl:sequence select="$values[position() = $idx]"/>
763 </xsl:for-each>
764 </xsl:function>
765 <xsl:function name="core:map-dissoc">
766 <xsl:param name="map"/>
767 <xsl:param name="names"/>
768 <xsl:sequence select="$map[let $pos := position() return not(($pos mod 2 = 1 and core:any-equal($names, .)) or ($pos mod 2 = 0 and core:any-equal($names, ../malval[$pos - 1])))]"/>
769 </xsl:function>
770 <xsl:function name="core:map-get">
771 <xsl:param name="map"/>
772 <xsl:param name="name"/>
773 <xsl:sequence select="$map[let $pos := position() return $pos mod 2 = 0 and core:equal($name, ../malval[$pos - 1])]"/>
774 </xsl:function>
775 <xsl:function name="core:mstime">
776 <xsl:message>
777 <request kind="time" value="now"/>
778 </xsl:message>
779 <xsl:sequence select="unparsed-text('xsl_input-string')"/>
780 </xsl:function>
781 </xsl:stylesheet>