-
Notifications
You must be signed in to change notification settings - Fork 1
/
let-over-lambda.lisp
146 lines (128 loc) · 4.88 KB
/
let-over-lambda.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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
;; This file contains utility functions and macros, taken from
;; let-over-lambda, which are used in the agutil project. The only
;; modification is that the functions and macros have been moved from
;; the :let-over-lambda package to the :agutil package, and the
;; flatten function has been renamed to lol-flatten to avoid conflicts
;; with the flatten function from the alexandria package.
;; The components used, from let-over-lambda, are copied directly into
;; this project, as opposed to adding let-over-lambda as a dependency,
;; in order to remove some of the dependencies of let-over-lambda,
;; such as named-readtables, which do not work reliably across all
;; Common Lisp implementations.
;; Antiweb (C) Doug Hoyte
;; This is a "production" version of LOL with bug-fixes
;; and new features in the spirit of the book.
;; See http://letoverlambda.com
;; This is the source code for the book
;; _Let_Over_Lambda_ by Doug Hoyte.
;; This code is (C) 2002-2008, Doug Hoyte.
;;
;; You are free to use, modify, and re-distribute
;; this code however you want, except that any
;; modifications must be clearly indicated before
;; re-distribution. There is no warranty,
;; expressed nor implied.
;;
;; Attribution of this code to me, Doug Hoyte, is
;; appreciated but not necessary. If you find the
;; code useful, or would like documentation,
;; please consider buying the book!
;; Modifications by "the Phoeron" Colin J.E. Lupton, 2012--2014
;; - Support for ASDF/Quicklisp
;; - Cheap hacks to support new Backquote implementation in SBCL v1.2.2
(in-package :agutil)
#+sbcl
(eval-when (:compile-toplevel :execute)
(handler-case
(progn
(sb-ext:assert-version->= 1 2 2)
(setq *features* (remove 'old-sbcl *features*)))
(error ()
(pushnew 'old-sbcl *features*))))
(defun group (source n)
(if (zerop n) (error "zero length"))
(labels ((rec (source acc)
(let ((rest (nthcdr n source)))
(if (consp rest)
(rec rest (cons
(subseq source 0 n)
acc))
(nreverse
(cons source acc))))))
(if source (rec source nil) nil)))
(eval-when (:compile-toplevel :execute :load-toplevel)
(defun mkstr (&rest args)
(with-output-to-string (s)
(dolist (a args) (princ a s))))
(defun symb (&rest args)
(values (intern (apply #'mkstr args))))
(defun lol-flatten (x)
(labels ((rec (x acc)
(cond ((null x) acc)
#+(and sbcl (not old-sbcl))
((typep x 'sb-impl::comma) (rec (sb-impl::comma-expr x) acc))
((atom x) (cons x acc))
(t (rec
(car x)
(rec (cdr x) acc))))))
(rec x nil)))
(defun g!-symbol-p (s)
(and (symbolp s)
(> (length (symbol-name s)) 2)
(string= (symbol-name s)
"G!"
:start1 0
:end1 2)))
(defun o!-symbol-p (s)
(and (symbolp s)
(> (length (symbol-name s)) 2)
(string= (symbol-name s)
"O!"
:start1 0
:end1 2)))
(defun o!-symbol-to-g!-symbol (s)
(symb "G!"
(subseq (symbol-name s) 2))))
(defmacro defmacro/g! (name args &rest body)
(let ((syms (remove-duplicates
(remove-if-not #'g!-symbol-p
(lol-flatten body)))))
(multiple-value-bind (body declarations docstring)
(parse-body body :documentation t)
`(defmacro ,name ,args
,@(when docstring
(list docstring))
,@declarations
(let ,(mapcar
(lambda (s)
`(,s (gensym ,(subseq
(symbol-name s)
2))))
syms)
,@body)))))
(defmacro defmacro! (name args &rest body)
(let* ((os (remove-if-not #'o!-symbol-p (lol-flatten args)))
(gs (mapcar #'o!-symbol-to-g!-symbol os)))
(multiple-value-bind (body declarations docstring)
(parse-body body :documentation t)
`(defmacro/g! ,name ,args
,@(when docstring
(list docstring))
,@declarations
`(let ,(mapcar #'list (list ,@gs) (list ,@os))
,(progn ,@body))))))
(defmacro defun! (name args &body body)
(let ((syms (remove-duplicates
(remove-if-not #'g!-symbol-p
(lol-flatten body)))))
(multiple-value-bind (body declarations docstring)
(parse-body body :documentation t)
`(defun ,name ,args
,@(when docstring
(list docstring))
,@declarations
(let ,(mapcar (lambda (s)
`(,s (gensym ,(subseq (symbol-name s)
2))))
syms)
,@body)))))