-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.lisp
50 lines (46 loc) · 1.99 KB
/
main.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
(in-package #:xcall)
(defun %generate-template-calls (template-name structure)
(declare (ignore template-name))
(labels ((ignore (branch)
(etypecase branch
((eql t)
nil)
(cons
(cons nil (mapcan #'ignore branch)))))
(select (branch)
(etypecase branch
((eql t)
nil)
(cons
(maplist (let ((index 0))
(lambda (tail)
(prog1 (nconc (mapcan #'ignore (ldiff branch tail))
(cons index (select (first tail)))
(mapcan #'ignore (rest tail)))
(incf index))))
branch)))))
(select structure)))
(defun %make-circular-dispenser (list)
(let ((elements (copy-list list)))
(nconc elements elements)
(lambda ()
(prog1 (car elements)
(setf elements (cdr elements))))))
(defun %generate-ejumpcase (template-var alternatives)
`(ejumpcase ,template-var
,@alternatives))
(defmacro xcall (alt prologue &body forms &environment env)
(let* ((structure (%analyze-xcall-structure alt `(progn ,@forms) env))
(template-name (gensym (string '#:template)))
(template-vars (map-into (make-list (length structure))
(lambda ()
(gensym (string '#:var)))))
(template-var-dispenser (gensym (string '#:template-var-dispenser))))
(setf (symbol-function template-var-dispenser)
(%make-circular-dispenser template-vars))
`(flet ((,template-name (,@template-vars)
(macrolet ((,alt (&body alternatives)
(%generate-ejumpcase (funcall ',template-var-dispenser)
alternatives)))
,@forms)))
(,@prologue ,@(%generate-template-calls template-name structure)))))