-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathglambda.lisp
61 lines (55 loc) · 2.58 KB
/
glambda.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
51
52
53
54
55
56
57
58
59
60
61
(in-package :fwoar.anonymous-gf)
(fw.lu:defun-ct get-specializers (specialized-lambda-list)
(flet ((get-specializer (specializer)
(etypecase specializer
(symbol (find-class specializer))
(cons (ecase (car specializer)
('eql (closer-mop:intern-eql-specializer (cdr specializer))))))))
(mapcar (lambda (specialized-arg)
(if (listp specialized-arg)
(get-specializer (cadr specialized-arg))
(find-class t)))
specialized-lambda-list)))
(fw.lu:defun-ct make-anonymous-generic-function (lambda-list methods)
(declare (optimize (debug 3)))
(let* ((gf (make-instance 'standard-generic-function
:lambda-list lambda-list))
(mc (closer-mop:generic-function-method-class gf)))
(prog1 gf
(loop for (specializers qualifiers body) in methods
for (method-lambda initargs) = (multiple-value-list (closer-mop:make-method-lambda gf (closer-mop:class-prototype mc)
`(lambda ,lambda-list
,@body)
nil))
do
(add-method gf
(apply #'make-instance mc
:function (compile nil method-lambda)
:specializers (get-specializers specializers)
:qualifiers qualifiers
:lambda-list lambda-list
initargs))))))
(fw.lu:defun-ct take-until (pred list)
(loop for (item . rest) on list
until (funcall pred item)
collect item into items
finally
(return (values items
(cons item rest)))))
(fw.lu:defun-ct get-methods (method-definition-list)
(loop for (keyword . rest) in method-definition-list
unless (eq keyword :method) do
(error "method definitions must begin with the :METHOD keyword")
collect
(multiple-value-bind (qualifiers rest) (take-until #'listp rest)
(list (car rest)
qualifiers
(cdr rest)))))
(defmacro glambda ((&rest lambda-list) &body methods)
(let ((methods (get-methods methods)))
`(make-anonymous-generic-function ',lambda-list ',methods)))
#+null
(glambda (a b)
(:method ((a integer) (b integer)) (+ a b))
(:method (a b) 2)
(:method :after (a b) (format t "~&~d ~d~%" a b)))