Skip to content

Commit 0298f87

Browse files
committed
support &environment macro parameter
1 parent 0c498f0 commit 0298f87

File tree

2 files changed

+55
-27
lines changed

2 files changed

+55
-27
lines changed

src/lambda-list.lisp

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020

2121
(defvar !lambda-list-keywords
22-
'(&optional &rest &key &aux &allow-other-keys &body &optional))
22+
'(&optional &rest &key &aux &allow-other-keys &body &optional &environment))
2323

2424
;;;; Lambda list parsing
2525

@@ -39,7 +39,8 @@
3939
restvar
4040
allow-other-keys
4141
keyvars
42-
auxvars)
42+
auxvars
43+
envvar)
4344

4445
(defun var-or-pattern (x)
4546
(etypecase x
@@ -104,41 +105,50 @@
104105
(make-auxvar :variable (var-or-pattern variable)
105106
:initform initform)))))
106107

107-
(defun parse-destructuring-lambda-list (lambda-list)
108+
(defun parse-destructuring-lambda-list (lambda-list &optional accept-environment-p)
108109
(let (;; Destructure lambda list structure where we accumulate the
109110
;; results of the parsing.
110111
(ll (make-lambda-list))
111112
;; List of lambda list keywords which we have already seen.
112113
(lambda-keywords nil))
113-
(flet (;; Check if we are in the beginning of the section NAME in
114-
;; the lambda list. It also checks if the section is in the
115-
;; proper place and it is new.
116-
(lambda-section (name)
117-
(let ((section (and (consp lambda-list) (first lambda-list))))
118-
(when (find section lambda-keywords)
119-
(error "Bad placed ~a in the lambda-list ~S." section lambda-list))
120-
(when (eq name section)
121-
(push name lambda-keywords)
122-
(pop lambda-list)
123-
t)))
124-
;; Check if we are in the middle of a lambda list section,
125-
;; looking for a lambda list keyword in the current
126-
;; position of the lambda list.
127-
(in-section-p ()
128-
(and (consp lambda-list)
129-
(not (find (first lambda-list) !lambda-list-keywords)))))
114+
(labels (;; Check if we are in the beginning of the section NAME in
115+
;; the lambda list. It also checks if the section is in the
116+
;; proper place and it is new.
117+
(lambda-section (name)
118+
(let ((section (and (consp lambda-list) (first lambda-list))))
119+
(when (find section lambda-keywords)
120+
(error "Bad placed ~a in the lambda-list ~S." section lambda-list))
121+
(when (eq name section)
122+
(push name lambda-keywords)
123+
(pop lambda-list)
124+
t)))
125+
;; Check if we are in the middle of a lambda list section,
126+
;; looking for a lambda list keyword in the current
127+
;; position of the lambda list.
128+
(in-section-p ()
129+
(and (consp lambda-list)
130+
(not (find (first lambda-list) !lambda-list-keywords))))
131+
(maybe-parse-env ()
132+
(when accept-environment-p
133+
(when (lambda-section '&environment)
134+
(let ((envvar (pop lambda-list)))
135+
(setf (lambda-list-envvar ll) (var-or-pattern envvar)))))))
130136

131137
;; &whole var
132138
(when (lambda-section '&whole)
133139
(let ((wholevar (pop lambda-list)))
134140
(setf (lambda-list-wholevar ll) (var-or-pattern wholevar))))
135-
141+
142+
(maybe-parse-env)
143+
136144
;; required vars
137145
(while (in-section-p)
138146
(let ((var (pop lambda-list)))
139147
(push (var-or-pattern var) (lambda-list-reqvars ll))))
140148
(setf (lambda-list-reqvars ll)
141149
(reverse (lambda-list-reqvars ll)))
150+
151+
(maybe-parse-env)
142152

143153
;; optional vars
144154
(when (lambda-section '&optional)
@@ -147,6 +157,8 @@
147157
(lambda-list-optvars ll)))
148158
(setf (lambda-list-optvars ll)
149159
(reverse (lambda-list-optvars ll))))
160+
161+
(maybe-parse-env)
150162

151163
;; Dotted lambda-list and &rest/&body vars. If the lambda-list
152164
;; is dotted. Convert it the tail to a &rest and finish.
@@ -158,23 +170,30 @@
158170
(setf (lambda-list-restvar ll)
159171
(var-or-pattern (pop lambda-list))))
160172

173+
(maybe-parse-env)
174+
161175
;; Keyword arguments
162176
(when (lambda-section '&key)
163177
(while (in-section-p)
164178
(push (parse-keyvar (pop lambda-list))
165179
(lambda-list-keyvars ll)))
166180
(setf (lambda-list-keyvars ll)
167-
(reverse (lambda-list-keyvars ll))))
181+
(reverse (lambda-list-keyvars ll))))
168182
(when (lambda-section '&allow-other-keys)
169183
(setf (lambda-list-allow-other-keys ll) t))
170184

185+
(maybe-parse-env)
186+
171187
;; Aux variables
172188
(when (lambda-section '&aux)
173189
(while (in-section-p)
174190
(push (parse-auxvar (pop lambda-list))
175191
(lambda-list-auxvars ll)))
176192
(setf (lambda-list-auxvars ll)
177193
(reverse (lambda-list-auxvars ll))))
194+
195+
(maybe-parse-env)
196+
178197
ll)))
179198

180199

@@ -351,15 +370,19 @@
351370
(parse-body body :declarations t :docstring t)
352371
(let* ((whole (gensym))
353372
(env (gensym))
354-
(ll (parse-destructuring-lambda-list lambda-list))
355-
(wholevar (lambda-list-wholevar ll)))
356-
(setf (lambda-list-wholevar ll) nil)
373+
(ll (parse-destructuring-lambda-list lambda-list t))
374+
(wholevar (lambda-list-wholevar ll))
375+
(envvar (lambda-list-envvar ll)))
376+
(setf (lambda-list-wholevar ll) nil
377+
(lambda-list-envvar ll) nil)
357378
`(lambda (,whole ,env)
358379
,@(when docstring (list docstring))
359-
(declare (ignorable ,env))
380+
,@(unless envvar `((declare (ignore ,env))))
360381
(block ,name
361382
(let (,@(when wholevar
362-
`((,wholevar ,whole))))
383+
`((,wholevar ,whole)))
384+
,@(when envvar
385+
`((,envvar ,env))))
363386
,(!expand-destructuring-bind
364387
ll
365388
`(cdr ,whole)

tests/macros.lisp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,8 @@
1515
(test (eq 2 (eval '(macrolet ((foo () 2))
1616
(macrolet ((bar () (macroexpand-1 '(foo) *environment*)))
1717
(bar))))))
18+
19+
(test (eq 2 (eval '(macrolet ((foo () 2))
20+
(macrolet ((bar (&environment env)
21+
(macroexpand-1 '(foo) env)))
22+
(bar))))))

0 commit comments

Comments
 (0)