[armedbear-cvs] r14147 - trunk/abcl/src/org/armedbear/lisp
ehuelsmann at common-lisp.net
ehuelsmann at common-lisp.net
Sun Sep 2 11:38:32 UTC 2012
Author: ehuelsmann
Date: Sun Sep 2 04:38:30 2012
New Revision: 14147
Log:
Close #241: Fix "part 2": ABCL accepts disallowed lambda list ordering.
Note: Solved by rewriting PARSE-LAMBDA-LIST.
Modified:
trunk/abcl/src/org/armedbear/lisp/compiler-pass1.lisp
Modified: trunk/abcl/src/org/armedbear/lisp/compiler-pass1.lisp
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/compiler-pass1.lisp Sat Sep 1 14:45:33 2012 (r14146)
+++ trunk/abcl/src/org/armedbear/lisp/compiler-pass1.lisp Sun Sep 2 04:38:30 2012 (r14147)
@@ -94,6 +94,7 @@
"
(let ((remaining lambda-list)
(state :req)
+ keyword-required
req opt key rest whole env aux key-p allow-others-p)
(when (eq (car lambda-list) '&WHOLE)
(let ((var (second lambda-list)))
@@ -104,59 +105,99 @@
:format-arguments (list var lambda-list)))
(setf whole (list var))
(setf remaining (nthcdr 2 lambda-list))))
- (dolist (arg remaining)
- (case arg
- (&optional (setf state :opt))
- (&key (setf state :key
- key-p t))
- (&rest (setf state :rest))
- (&aux (setf state :aux))
- (&allow-other-keys (setf state :none
- allow-others-p t))
- (&whole (setf state :whole))
- (&environment (setf state :env))
- (&whole
- (error 'program-error
- :format-control "&WHOLE must appear first in lambda list ~A."
- :format-arguments (list lambda-list)))
- (t
- (case state
- (:req (push (list arg) req))
- (:rest (setf rest (list arg)
- state :none))
- (:env (setf env (list arg)
- state :req))
- (:none
- (error "Invalid lambda list: argument found in :none state."))
- (:opt
- (cond
- ((symbolp arg)
- (push (list arg nil nil nil) opt))
- ((consp arg)
- (push (list (car arg) (cadr arg) (caddr arg)) opt))
- (t
- (error "Invalid state."))))
- (:aux
- (cond
- ((symbolp arg)
- (push (list arg nil nil nil) aux))
- ((consp arg)
- (push (list (car arg) (cadr arg) nil nil) aux))
- (t
- (error "Invalid :aux state."))))
- (:key
- (cond
- ((symbolp arg)
- (push (list arg nil nil (sys::keywordify arg)) key))
- ((and (consp arg)
- (consp (car arg)))
- (push (list (cadar arg) (cadr arg) (caddr arg) (caar arg)) key))
- ((consp arg)
- (push (list (car arg) (cadr arg) (caddr arg)
- (sys::keywordify (car arg))) key))
- (t
- (error "Invalid :key state."))))
- (t (error "Invalid state found."))))))
+
+ (do* ((arg (pop remaining) (pop tail))
+ (tail remaining tail))
+ ((and (null arg)
+ (endp tail)))
+ (let* ((allowable-previous-states
+ ;; even if the arglist could theoretically contain the
+ ;; keyword :req, this still works, because the cdr will
+ ;; be NIL, meaning that the code below thinks we DIDN'T
+ ;; find a new state. Which happens to be true.
+ (cdr (member arg '(&whole &environment &aux &allow-other-keys
+ &key &rest &optional :req)))))
+ (cond
+ (allowable-previous-states
+ (setf keyword-required nil) ;; we have a keyword...
+ (case arg
+ (&key
+ (setf key-p t))
+ (&rest
+ (when (endp tail)
+ (error 'program-error
+ :format-control "&REST without variable in lambda list ~A."
+ :format-arguments (list lambda-list)))
+ (setf rest (list (pop tail))
+ keyword-required t))
+ (&allow-other-keys
+ (unless (eq state '&KEY)
+ (error 'program-error
+ :format-control "&ALLOW-OTHER-KEYS outside of &KEY ~
+ section in lambda list ~A"
+ :format-arguments (list lambda-list)))
+ (setf allow-others-p t
+ keyword-required t
+ arg nil))
+ (&environment
+ (setf env (list (pop tail))
+ keyword-required t
+ ;; &ENVIRONMENT can appear anywhere; retain our last
+ ;; state so we know what next keywords are valid
+ arg state))
+ (&whole
+ (error 'program-error
+ :format-control "&WHOLE must appear first in lambda list ~A."
+ :format-arguments (list lambda-list))))
+ (when arg
+ ;; ### verify that the next state is valid
+ (unless (or (null state)
+ (member state allowable-previous-states))
+ (error 'program-error
+ :format-control "~A not allowed after ~A ~
+ in lambda-list ~S"
+ :format-arguments (list arg state lambda-list)))
+ (setf state arg)))
+ (keyword-required
+ ;; a keyword was required, but none was found...
+ (error 'program-error
+ :format-control "Lambda list keyword expected, but found ~
+ ~A in lambda list ~A"
+ :format-arguments (list arg lambda-list)))
+ (t ;; a variable specification
+ (case state
+ (:req (push (list arg) req))
+ (&optional
+ (cond ((symbolp arg)
+ (push (list arg) opt))
+ ((consp arg)
+ (push (list (car arg) (cadr arg)
+ (caddr arg)) opt))
+ (t
+ (error "Invalid &OPTIONAL variable."))))
+ (&key
+ (cond ((symbolp arg)
+ (push (list arg nil nil (sys::keywordify arg)) key))
+ ((consp arg)
+ (push (list (if (consp (car arg))
+ (cadar arg) (car arg))
+ (cadr arg) (caddr arg)
+ (if (consp (car arg))
+ (caar arg)
+ (sys::keywordify (car arg)))) key))
+ (t
+ (error "Invalid &KEY variable."))))
+ (&aux
+ (cond ((symbolp arg)
+ (push (list arg nil nil nil) aux))
+ ((consp arg)
+ (push (list (car arg) (cadr arg) nil nil) aux))
+ (t
+ (error "Invalid &aux state."))))
+ (t
+ (error 'program-error
+ :format-control "Invalid state found: ~A."
+ :format-arguments (list state))))))))
(values
(nreverse req)
(nreverse opt)
More information about the armedbear-cvs
mailing list