;;; -*-  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                                            ;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;     (c) Copyright 1981 Massachusetts Institute of Technology         ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(in-package "MAXIMA")
(macsyma-module ar)

(declare-top (SPECIAL EVARRP MUNBOUND FLOUNBOUND FIXUNBOUND #+cl $use_fast_arrays))

;;; This code needs to be checked carefully for the lispm.



(defstruct #-cl (mgenarray conc-name array)
	   #+cl (mgenarray (:conc-name mgenarray-) (:type vector))
  aref
  aset
  type
  NULL
  GENERATOR
  CONTENT)

#-cl
(DEFUN MARRAY-TYPE (X)
  
  (OR (CDR (ASSQ (ARRAY-TYPE X)
		 '((FLONUM . $FLOAT)
		   (FIXNUM . $FIXNUM))))
      (MGENARRAY-TYPE X)))
#+cl
(DEFUN MARRAY-TYPE (X)
  (case (ml-typep x)
    (array (array-element-type x))
    (hash-table 'hash-table)
    #+lispm (si::equal-hash-table 'hash-table)
    (lisp::array  (princ "confusion over array and lisp::array")
	    (array-element-type x))
    (otherwise
 
  (OR (CDR (ASSQ (array-type x)
		 '((FLONUM . $FLOAT)
		   (FIXNUM . $FIXNUM))))
      (MGENARRAY-TYPE X)))))

;#+lispm
;(defmfun $Show_hash_array (table)
;  (send table :map-hash
;   `(lambda (u v) 
;    (format t "~%~A-->~A" u v)))
;  table)

(DEFMFUN $MAKE_ARRAY (TYPE &REST DIML)
  (LET ((LTYPE (ASSQ TYPE '(($FLOAT . FLONUM) ($FLONUM . FLONUM)
					      ($FIXNUM . FIXNUM)))))
    (COND ((NOT LTYPE)
	   (COND ((EQ TYPE '$ANY)
		  #+cl (make-array diml :initial-element nil)
		  #-cl
		  (MAKE-MGENARRAY  #+cl :type #-cl type  '$ANY
				  #+cl :CONTENT #-cl CONTENT (APPLY '*ARRAY NIL T DIML)))
		 ((EQ TYPE '$HASHED)
		  (LET ((KLUDGE (GENSYM)))
		    (OR (INTEGERP (CAR DIML))
			(MERROR "non-integer number of dimensions: ~M"
				(CAR DIML)))
		    (INSURE-ARRAY-PROPS KLUDGE () (CAR DIML))
		    (MAKE-MGENARRAY #+cl :TYPE #-cl TYPE '$HASHED
				    #+cl :CONTENT #-cl CONTENT KLUDGE)))
		 ((EQ TYPE '$FUNCTIONAL)
		  ;; MAKE_ARRAY('FUNCTIONAL,LAMBDA(...),'ARRAY_TYPE,...)
		  (OR (> (LENGTH DIML) 1)
		      (MERROR "not enough arguments for functional array specification"))
		  (LET ((AR (APPLY #'$MAKE_ARRAY (CDR DIML)))
			(THE-NULL))
		    (CASE (MARRAY-TYPE AR)
		      (($FIXNUM)
		       (FILLARRAY AR (LIST (SETQ THE-NULL FIXUNBOUND))))
		      (($FLOAT)
		       (FILLARRAY AR (LIST (SETQ THE-NULL FLOUNBOUND))))
		      (($ANY)
		       (FILLARRAY (MGENARRAY-CONTENT AR) (LIST (SETQ THE-NULL MUNBOUND))))
		      (T
		       ;; Nothing to do for hashed arrays. Is FUNCTIONAL here
		       ;; an error?
		       (SETQ THE-NULL 'NOTEXIST)))
		    (MAKE-MGENARRAY #+cl :TYPE #-cl TYPE '$FUNCTIONAL
				    #+cl :CONTENT #-cl CONTENT AR
				    #+cl :GENERATOR #-cl GENERATOR (CAR DIML)
				    #+cl :NULL #-cl NULL THE-NULL)))
		 ('ELSE
		  (MERROR "Array type of ~M is not recognized by MAKE_ARRAY" TYPE))))
	  ('ELSE
	   (APPLY '*ARRAY NIL (CDR LTYPE) DIML)))))
#+cl
(defmfun maknum (x)
  (cond ($use_fast_arrays
  (exploden (format nil "~A" x)))
	(t (format nil "~A" x))))

(DEFMFUN DIMENSION-ARRAY-OBJECT (FORM RESULT &AUX (MTYPE (MARRAY-TYPE FORM)))
  (cond ($use_fast_arrays (dimension-string  (maknum form) result))
	(t
	 (DIMENSION-STRING
	   (NCONC (EXPLODEN "{Array: ")
		  (CDR (EXPLODEN MTYPE))
		  (EXPLODEN " ")
		  (EXPLODEN (MAKNUM FORM))
		  (IF (MEMQ MTYPE '($FLOAT $FIXNUM $ANY))
		      (NCONC (EXPLODEN "[")
			     (DO ((L (CDR (ARRAYDIMS (IF (MEMQ MTYPE '($FLOAT $FIXNUM))
							 FORM
							 (MGENARRAY-CONTENT FORM))))
				     (CDR L))
				  (V NIL
				     (NCONC (NREVERSE (EXPLODEN (CAR L))) V)))
				 ((NULL L) (NREVERSE V))
			       (IF V (PUSH #\, V)))
			     (EXPLODEN "]")))
		  (EXPLODEN "}"))
	   RESULT))))



(DEFUN MARRAY-CHECK (A)
  (IF (EQ (ml-typep A) 'array)
      (CASE (MARRAY-TYPE A)
	((art-q ) a)
	(($FIXNUM $FLOAT) A)
	(($ANY) (MGENARRAY-CONTENT A))
	(($HASHED $FUNCTIONAL)
	
	 ;; BUG: It does have a number of dimensions! Gosh. -GJC
	 (MERROR "Hashed array has no dimension info: ~M" A))
	(T
	 (MARRAY-TYPE-UNKNOWN A)))
      (MERROR "Not an array: ~M" A)))

(DEFMFUN $ARRAY_NUMBER_OF_DIMENSIONS (A)
  (ARRAY-/#-DIMS (MARRAY-CHECK A)))

(DEFMFUN $ARRAY_DIMENSION_N (N A)
  #-cl(ARRAY-DIMENSION-N N (MARRAY-CHECK A))
  #+cl(array-dimension  (MARRAY-CHECK A) n)
  )

(DEFUN MARRAY-TYPE-UNKNOWN (X)
  (MERROR "BUG: Array of unhandled type: ~S" X))

(DEFUN MARRAYREF-GENSUB (AARRAY IND1 INDS)  
       (CASE (MARRAY-TYPE AARRAY)
    ;; We are using a CASE on the TYPE instead of a FUNCALL, (or SUBRCALL)
    ;; because we are losers. All this stuff uses too many functions from
    ;; the "MLISP" modual, which are not really suitable for the kind of
    ;; speed and simplicity we want anyway. Ah me. Also, passing the single
    ;; unconsed index IND1 around is a dubious optimization, which causes
    ;; extra consing in the case of hashed arrays.
#+cl((t) (apply #'aref aarray ind1 inds))
#+cl((hash-table) (gethash (if inds (cons ind1 inds) ind1) aarray))
    (($HASHED)
     (APPLY #'MARRAYREF (MGENARRAY-CONTENT AARRAY) IND1 INDS))
    (($FLOAT $FIXNUM)
     (APPLY AARRAY IND1 INDS))
    (($ANY)
     (APPLY (MGENARRAY-CONTENT AARRAY) IND1 INDS))
    (($FUNCTIONAL)
     (LET ((VALUE (LET ((EVARRP T))
		    ;; special variable changes behavior of hashed-array
		    ;; referencing functions in case of not finding an element.
		    (CATCH 'EVARRP (MARRAYREF-GENSUB
				      (MGENARRAY-CONTENT AARRAY) IND1 INDS)))))
       (IF (EQUAL VALUE (MGENARRAY-NULL AARRAY))
	   (MARRAYSET-GENSUB  (APPLY #'MFUNCALL
					     (MGENARRAY-GENERATOR AARRAY)
					     ;; the first argument we pass the
					     ;; function is a SELF variable.
					     AARRAY
					     ;; extra consing here! LEXPR madness.
					     IND1
					     INDS)
			      (MGENARRAY-CONTENT AARRAY) IND1 INDS)
	   VALUE)))
    (T
     (MARRAY-TYPE-UNKNOWN AARRAY))))
	  
(defmfun $Make_art_q (&rest l)
    (make-array l))

(DEFUN MARRAYSET-GENSUB (VAL AARRAY IND1 INDS) 
  (CASE (MARRAY-TYPE AARRAY)
    #+cl
    ((t) (setf (apply #'aref aarray ind1 inds) val))
    (($HASHED)
     (APPLY #'MARRAYSET VAL (MGENARRAY-CONTENT AARRAY) IND1 INDS))
    (($ANY)
     #-cl(STORE (APPLY (MGENARRAY-CONTENT AARRAY) IND1 INDS) VAL)
     #+cl
     (setf (apply #'Aref (MGENARRAY-CONTENT AARRAY) IND1 INDS) val ))
     
    (($FLOAT $FIXNUM)
     #-cl(STORE (APPLY AARRAY IND1 INDS) VAL)
     #+cl     (setf  (apply #'Aref (MGENARRAY-CONTENT AARRAY) IND1 INDS) val ))
    (($FUNCTIONAL)
     (MARRAYSET-GENSUB VAL (MGENARRAY-CONTENT AARRAY) IND1 INDS))
    (T
      (MARRAY-TYPE-UNKNOWN AARRAY))))


;; Extensions to MEVAL.

(DEFMFUN MEVAL1-EXTEND (FORM)
  (LET ((L (MEVALARGS (CDR FORM))))
    (MARRAYREF-GENSUB (CAAR FORM) (CAR L) (CDR L))))

(DEFMFUN ARRSTORE-EXTEND (A L R)
  (MARRAYSET-GENSUB R A (CAR L) (CDR L)))


