;;; -*-  Mode: Lisp; Package: Maxima; Syntax: Common-Lisp; Base: 10 -*- ;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;     The data in this file contains enhancments.                    ;;;;;
;;;                                                                    ;;;;;
;;;  Copyright (c) 1984,1987 by William Schelter,University of Texas   ;;;;;
;;;     All rights reserved                                            ;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(in-package :maxima)
;; Destructuring DEFUN must be added to this at some point.

(defvar *let-macro-vals* nil)

;; Kludge to avoid warning that a different file is redefining
;; LET and LET*.  SI has LET and LET* externed, so there is no
;; "illegally defining" warning.

(defmacro destructuring-let (pairs &body body)
  (do ((pairs pairs (cdr pairs))
       (vars nil)
       (*let-macro-vals* nil)
       (tem))
      ((null pairs)
       (cond ((not (null vars))
					;`((lambda ,(reverse vars) . ,body) .
					;,(reverse *let-macro-vals*))
	      `(cl:let ,(nreverse (loop for v in vars for w in
					   *let-macro-vals* collect
					   (list v w)))
		,@ body)
	      )
	     ((null (cdr body))
	      (car body))
	     (t `(progn . ,body))))
    (cond ((atom (car pairs))
	   (or (symbolp (car pairs))
	       (error 
		"Garbage found in `let' pattern: ~S" (car pairs)))
	   (setq vars (cons (car pairs) vars))
	   (setq *let-macro-vals* (cons nil *let-macro-vals*)))
	  (t
	   (setq tem vars)
	   (setq vars (let-macro-get-vars (caar pairs) vars))
	   (or (eq tem vars)
	       (setq body (nconc (let-macro-hair (caar pairs)
						 (cadar pairs)
						 *let-macro-vals*)
				 body)))))))

(defun let-macro-get-vars (pattern vars)
  (cond ((null pattern) vars)
	((atom pattern)
	 (or (symbolp pattern)
	     (error 
	      "Garbage found in `let' pattern: ~S" pattern))
	 (setq *let-macro-vals* (cons nil *let-macro-vals*))
	 (cons pattern vars))
	(t (let-macro-get-vars (cdr pattern)
			       (let-macro-get-vars (car pattern) vars)))))

(defmacro desetq (&rest p)
  (do ((p p (cddr p))
       (body nil)
       (tem))
      ((null p)
       `(progn . ,body))
    (cond ((atom (cdr p))
	   (error 
	    "Odd number of args to `desetq': ~S" p))
	  ((atom (car p))
	   (or (symbolp (car p))
	       (error 
		"Garbage found in `desetq' pattern: ~S" (car p)))
	   (and (null (car p))
		(error 
		 "Bad `desetq' pattern: ~S" (car p)))
	   (setq body (nconc body `((setq ,(car p) ,(cadr p))))))
	  (t
	   (setq tem (cons nil nil))
	   (setq body (nconc body
			     `((setq ,(let-macro-get-last-var (car p))
				. ,tem)
			       . ,(let-macro-hair (car p) (cadr p) tem))))))))


(defun let-macro-get-last-var (pattern)
  (cond ((atom pattern) pattern)
	(t
	 (or (let-macro-get-last-var (cdr pattern))
	     (let-macro-get-last-var (car pattern))))))

(defun let-macro-hair (pattern code cell)
  (cond ((null pattern) nil)
	((atom pattern)
	 (rplaca cell code)
	 nil)
	(t
	 ((lambda (avar dvar)
	    (cond ((null avar)
		   (cond ((null dvar) nil)
			 (t (let-macro-hair (cdr pattern)
					    `(cdr ,code)
					    cell))))
		  ((null dvar)
		   (let-macro-hair (car pattern)
				   `(car ,code)
				   cell))
		  (t
		   (rplaca cell code)
		   ((lambda (acell dcell)
		      (cons `(setq ,avar . ,acell)
			    (nconc (let-macro-hair (car pattern)
						   `(car ,dvar)
						   acell)
				   (cons `(setq ,dvar . ,dcell)
					 (let-macro-hair (cdr pattern)
							 `(cdr ,dvar)
							 dcell)))))
		    (cons nil nil)
		    (cons nil nil)))))
	  (let-macro-get-last-var (car pattern))
	  (let-macro-get-last-var (cdr pattern))))))

(defmacro destructuring-let* (pairs &body body)
  (cond ((loop for v in pairs
		always (or (symbolp v) (and (consp v) (symbolp (car v)))))
	 `(cl:let* ,pairs ,@body))
	(t
	 (do ((a (reverse pairs) (cdr a))
	      (b body `((destructuring-let (,(car a)) . ,b))))
	     ((null a)
	      (cond ((null (cdr b)) (car b))
		    (t `(progn . ,b))))))))

