[movitz-cvs] CVS movitz/losp/muerte

ffjeld ffjeld at common-lisp.net
Fri Mar 7 23:38:21 UTC 2008


Update of /project/movitz/cvsroot/movitz/losp/muerte
In directory clnet:/tmp/cvs-serv13672

Modified Files:
	more-macros.lisp 
Log Message:
Implement macro destructuring-bind.


--- /project/movitz/cvsroot/movitz/losp/muerte/more-macros.lisp	2006/05/06 20:31:23	1.36
+++ /project/movitz/cvsroot/movitz/losp/muerte/more-macros.lisp	2008/03/07 23:38:21	1.37
@@ -10,7 +10,7 @@
 ;;;; Author:        Frode Vatvedt Fjeld <frodef at acm.org>
 ;;;; Created at:    Fri Jun  7 15:05:57 2002
 ;;;;                
-;;;; $Id: more-macros.lisp,v 1.36 2006/05/06 20:31:23 ffjeld Exp $
+;;;; $Id: more-macros.lisp,v 1.37 2008/03/07 23:38:21 ffjeld Exp $
 ;;;;                
 ;;;;------------------------------------------------------------------
 
@@ -130,6 +130,129 @@
        (let ((,var (pop ,cons-var)))
 	 , at declarations-and-body))))
 
+
+(defmacro destructuring-bind (lambda-list expression &body declarations-and-body)
+  (let ((bindings (list (list (gensym)
+			      expression)))
+	(ignores nil))
+    (macrolet ((pop* (place)
+		 "Like pop, but err if place is already NIL."
+		 `(let ((x ,place))
+		    (assert x () "Syntax error in destructuring lambda-list: ~S" lambda-list)
+		    (setf ,place (cdr x))
+		    (car x)))
+	       (pop-match (item place)
+		 "Pop place if (car place) is eq to item."
+		 `(let ((item ,item)
+			(x ,place))
+		    (when (eq (car x) item)
+		      (setf ,place (cdr x))
+		      (car x)))))
+      (labels
+	  ((gen-end (var)
+	     (let ((dummy-var (gensym)))
+	       (push (list dummy-var (list 'when var '(error "Too many elements in expression for lambda-list.")))
+		     bindings)
+	       (push dummy-var ignores)))
+	   (gen-lambda-list (var sub-lambda-list)
+	     (when (pop-match '&whole sub-lambda-list)
+	       (push (list (pop* sub-lambda-list) var)
+		     bindings))
+	     (gen-reqvars var sub-lambda-list))
+	   (gen-reqvars (var sub-lambda-list)
+	     (cond
+	       ((null sub-lambda-list)
+		(gen-end var))
+	       ((symbolp sub-lambda-list) ; dotted lambda-list?
+		(push (list sub-lambda-list var)
+		      bindings))
+	       ((pop-match '&optional sub-lambda-list)
+		(gen-optvars var sub-lambda-list))
+	       ((pop-match '&rest sub-lambda-list)
+		(gen-restvar var sub-lambda-list))
+	       ((consp (car sub-lambda-list)) ; recursive lambda-list?
+		(let ((sub-var (gensym)))
+		  (push (list sub-var `(pop ,var))
+			bindings)
+		  (gen-lambda-list sub-var (pop sub-lambda-list)))
+		(gen-reqvars var sub-lambda-list))
+	       (t (push (let ((b (pop* sub-lambda-list)))
+			  (list b
+				`(if (null ,var)
+				     (error "Value for required argument ~S is missing." ',b)
+				     (pop ,var))))
+			bindings)
+		  (gen-reqvars var sub-lambda-list))))
+	   (gen-optvars (var sub-lambda-list)
+	     (cond
+	       ((null sub-lambda-list)
+		(gen-end var))
+	       ((symbolp sub-lambda-list) ; dotted lambda-list?
+		(push (list sub-lambda-list var)
+		      bindings))
+	       ((pop-match '&rest sub-lambda-list)
+		(gen-restvar var sub-lambda-list))
+	       ((pop-match '&key sub-lambda-list)
+		(gen-keyvars var sub-lambda-list))
+	       (t (multiple-value-bind (opt-var init-form supplied-var)
+		      (let ((b (pop sub-lambda-list)))
+			(if (atom b)
+			    (values b nil nil)
+			    (values (pop b) (pop b) (pop b))))
+		    (when supplied-var
+		      (push (list supplied-var `(if ,var t nil))
+			    bindings))
+		    (push (list opt-var
+				(if (not init-form)
+				    `(pop ,var)
+				    `(if ,var (pop ,var) ,init-form)))
+			  bindings))
+		  (gen-optvars var sub-lambda-list))))
+	   (gen-restvar (var sub-lambda-list)
+	     (let ((rest-var (pop* sub-lambda-list)))
+	       (push (list rest-var var)
+		     bindings))
+	     (when (pop-match '&key sub-lambda-list)
+	       (gen-keyvars var sub-lambda-list)))
+	   (gen-keyvars (var sub-lambda-list &optional keys)
+	     (cond
+	       ((endp sub-lambda-list)
+		(push (list (gensym)
+			    `(d-bind-veryfy-keys ,var ',keys))
+		      bindings)
+		(push (caar bindings)
+		      ignores))
+	       ((pop-match '&allow-other-keys sub-lambda-list)
+		(when sub-lambda-list
+		  (error "Bad destructuring lambda-list; junk after ~S." '&allow-other-keys)))
+	       (t (multiple-value-bind (key-var key-name init-form supplied-var)
+		      (let ((b (pop sub-lambda-list)))
+			(cond
+			  ((atom b)
+			   (values b (intern (string b) :keyword) nil nil))
+			  ((atom (car b))
+			   (values (car b) (intern (string (car b)) :keyword) nil nil))
+			  (t (let ((bn (pop b)))
+			       (values (cadr bn) (car bn) (pop b) (pop b))))))
+		    (when supplied-var
+		      (push supplied-var bindings))
+		    (push (list key-var
+				`(let ((x (d-bind-lookup-key ',key-name ,var)))
+				   ,@(when supplied-var
+					   `((setf ,supplied-var (if x t nil))))
+				   ,(if (not init-form)
+					'(car x)
+					(if x
+					    (car x)
+					    ,init-form))))
+			  bindings)
+		    (gen-keyvars var sub-lambda-list (cons key-name keys)))))))
+	(gen-lambda-list (caar bindings)
+			 lambda-list)
+	`(let* ,(nreverse bindings)
+	   (declare (ignore , at ignores))
+	   , at declarations-and-body)))))
+
 (define-compiler-macro member (&whole form item list &key (key ''identity) (test ''eql)
 			       &environment env)
   (let* ((test (or (and (movitz:movitz-constantp test env)




More information about the Movitz-cvs mailing list