-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmerge.lisp
97 lines (82 loc) · 3.01 KB
/
merge.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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
(in-package #:explicit-bind-merger)
(defvar *mergers* (make-hash-table :test 'eq))
(defclass merger ()
((name :initarg :name
:reader name
:type (and symbol (not null)))
(function :initarg :function
:reader function)
(lambda-list :initarg :lambda-list
:reader lambda-list
:type list)))
(defun find (name &key (errorp t))
(check-type name symbol)
(or (gethash name *mergers*)
(when errorp
(error "There is no ~S called ~S." 'merger name))))
(defun (setf find) (new name &key (errorp t))
(declare (ignore errorp))
(check-type new merger)
(check-type name (and symbol (not null)))
(setf (gethash name *mergers*) new))
(defmacro define (name ((op &rest args) body-var keys-pattern) &body body)
(check-type name (and symbol (not null)))
(let ((spec (gensym (string '#:spec)))
(keys (gensym (string '#:keys)))
(op-gensym (unless op (gensym (string '#:op)))))
`(setf (find ',name)
(make-instance
'merger
:name ',name
:function
(lambda (,spec ,body-var ,keys)
(destructuring-bind ((,(or op op-gensym) ,@args)
,body-var
,keys-pattern)
(list ,spec ,body-var ,keys)
,@(when op-gensym `((declare (ignorable ,op-gensym))))
,@body))
:lambda-list ',args))))
(defun merge1 (spec body keys)
(funcall (function (find (first spec))) spec body keys))
(defun merge (specs body &key keys)
(let ((body (reduce (lambda (specs body)
(multiple-value-bind (body new-keys)
(merge1 specs body keys)
(setf keys new-keys)
body))
specs
:from-end t
:initial-value body))
(declarations (getf keys :declarations)))
(declare (ignore declarations))
body))
(define declare ((nil &rest declaration-specifiers) body keys)
(values body
(if declaration-specifiers
(list* :declarations (append declaration-specifiers
(getf keys :declarations))
keys)
keys)))
(define progn ((nil &body forms) body keys)
(values (append forms body) keys))
(define variable ((nil name form) body keys)
(values (list `(let ((,name ,form))
,@body))
keys))
(define cl:function ((nil name form) body keys)
(values (list `(eflet:eflet* ((,name ,form))
,@body))
keys))
(define :destructuring ((nil lambda-list form) body keys)
(values (list `(destructuring-bind ,lambda-list ,form
,@body))
keys))
(define :accessors ((nil accessor-specifications instance-form) body keys)
(values (list `(with-accessors ,accessor-specifications ,instance-form
,@body))
keys))
(define :slots ((nil slot-specifications instance-form) body keys)
(values (list `(with-slots ,slot-specifications ,instance-form
,@body))
keys))