;;; -*-  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                                            ;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;            Please do not modify this file.         See GJC           ;;;
;;;       (c) Copyright 1980 Massachusetts Institute of Technology       ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(in-package :maxima)

;;; TRANSLATION PROPERTIES FOR MACSYMA OPERATORS AND FUNCTIONS.

;;; This file is for list and array manipulation optimizations.

(macsyma-module trans2)


(transl-module trans2)

(def%tr $random (form) `($fixnum . ($random ,@(tr-args (cdr form)))))

(def%tr mequal (form)
  `($any . (simplify (list '(mequal) ,@(tr-args (cdr form))))))

(def%tr mcall (form)
  (setq form (cdr form))
  (let ((mode (cond ((atom (car form))
		     (function-mode (car form)))
		    (t '$any))))
    (setq form (tr-args form))
    (let ((op (car form)))
      (call-and-simp mode 'mcall `(,op . ,(cdr form))))))

;;; Meaning of the mode properties: most names are historical.
;;; (GETL X '(ARRAY-MODE)) means it is an array callable by the
;;; old maclisp style. This is unfortunately still useful to
;;; avoid indirection through the property list to get to the
;;; array.

(defvar $translate_fast_arrays t )
;;When $translate_fast_arrays and $use_fast_arrays are true
;;there should only be two types of arrays and they should be stored on
;;the value cell of the symbol.  These should be the equivalent of the
;;zetalisp art-q and the si:equal-hash-table. Note that maxima lists
;;and maxima $matrices are also allowed for setting.  Note also that
;;because of some hokey things like mqapply etc, if you want
;;fast referenceing use a[i], or b[i]:..., ie use variables,
;;since if you try something complicated it may not translate as
;;simply.
;;Idea of these is for the lispm to store the array in the value cell
;;to use equal-hash-tables, and to clean up the local variable
;;in translated code for an array.
;;txx(i,j):=block([hl],hl[i]:j,hl[i]); should leave hl unbound, after creating
;;a  hash table for hl, There should be a resource of these.


;;acceptable arguments to ar[i] or ar[i]:val

(defun lispm-marray-type (ar)
  (cond ((arrayp ar) 'array)
	( (hash-table-p ar) 'hash-table)
	(($listp ar) '$list)
	(($matrixp ar) '$matrix)
	((symbolp ar) 'symbol)
	(t nil)))

(defun tr-maset (ar val  inds)
  ;; Top-level forms need to define the variable first.
  (if *macexpr-top-level-form-p* 
      `(nil progn (defvar ,ar ',ar) (maset ,val ,ar  ,@ inds))
      `(nil maset ,val ,ar  ,@ inds)))

(defun maset1 ( val ar  &rest inds &aux  )
  (cond
    ((and (typep ar 'cl:array)
	  (= (length inds) (cl:array-rank ar)))
     (setf (apply #'aref ar inds)  val))
    ((typep ar 'cl:hash-table)
     (setf (gethash (if (cdr inds) (copy-list inds) (car inds))
		    ar)
	   val))
    ((symbolp ar)
     (error "must set the hash table outside"))
    ((and (= (length inds) 1)
	  (or ($listp ar) ($matrixp ar)))
     (setf (nth (car inds) ar) val) val)
    ((and ($matrixp ar)
	  (= (length inds) 2))
     (setf (nth (second inds) (nth  (car inds) ar)) val) val)
    (t (error "not a valid array reference to ~A" ar))))


;;apply is too expensive for a simple array reference.  The time
;;is increased by a factor of 6.  Note we use the locf form to get at
;;the local variable of the function calling maset in order to be able
;;to store a hash-table there in the case that the variable was not an
;;array

;;COULD USE THE FOLLOWING TO handle fast_arrays:true.
;;(defun set-up-hash-table (&optional val key &aux tab)
;;  (setq tab (make-hash-table :test 'equal)) ;alike?
;;  (setf (gethash key tab) val) tab)
;;
;;(defun maset-help1 ( val ar  &rest inds &aux  )
;;  "returns t if it set and nil if what went in could not be set but is a variable that
;;    should be set to hash array"
;;  (cond ((hash-table-p ar)
;;	 (setf (gethash (car inds) ar) val))
;;	((symbolp ar) nil)
;;	(($listp ar)
;;	 (setf (nth (car inds) ar) val)  t)
;;	(($matrixp ar) (setf (nth (second inds) (nth  (car inds) ar)) val) t)
;;	(t (error "not valid place ~A to put an array" ar))))
;;
;;
;;;;doesn't prevent multiple evaluation of inds val and ar.. but doesn't use locf
;;(defmacro maset (val ar &rest  inds )
;;  `(cond
;;     ((arrayp ar) (setf (aref ar ,@ inds) ,val))
;;     ((maset-help1 ,val ,ar ,@ inds) ,val)
;;      (t (setf ,ar (set-up-hash-table ,val (car ,ind))),val)))
;;
;;(defmacro maref ( ar &rest inds)
;;  `(cond ((arrayp ,ar) (aref ,ar ,@ inds))
;;	 ((hash-table-p ,ar) (gethash ,ar (car ,inds)))
;;	 ((symbolp ,ar)`((,ar ,@ (copy-list ,inds))))))

;;in maref in transl now

(defun tr-maref (ar inds)
  `(nil maref , ar ,@ (copy-list inds)))

(defun maref1 (ar  &rest inds &aux )
  (cond
    ((and (typep ar 'cl:array)
	  (= (length inds) (cl:array-rank ar)))
     (apply #'aref ar inds))
    ((typep ar 'cl:hash-table)
     (gethash (if (cdr inds) inds (car inds)) ar))
    ((symbolp ar)
     (cond ((mget ar 'hashar)
	    (harrfind `((,ar array) ,@(copy-list inds))))
	   (t
	    `((,ar array) ,@(copy-list inds)))))
    ((and (= (length inds) 1)
	  (or ($listp ar) ($matrixp ar)))
     (nth (first inds) ar))
    ((and ($matrixp ar) (= (length inds) 2))
     (nth (second inds) (nth (first inds) ar)))
    (t
     (merror "Wrong number of indices:~%~M" (cons '(mlist) inds)))))



(defun tr-arraycall (form &aux all-inds)
  (cond ((get (caar form) 'array-mode)
	 (pushnew (caar form) arrays :test #'eq)
	 `(,(array-mode (caar form))
	   . (,(caar form) ,@(tr-args (cdr form)))))
	($translate_fast_arrays (setq all-inds (mapcar 'dtranslate (cdr form)))
				;;not apply changed 'tr-maref
				(funcall 'tr-maref (cdr (translate (caar form)))   all-inds))
	(t
	 (translate `((marrayref)
		      ,(if $tr_array_as_ref (caar form)
			   `((mquote) ,(caar form)))     
		      ,@(cdr form))))))



(defun tr-arraysetq (array-ref value)
  ;; actually an array SETF, but it comes from A[X]:FOO
  ;; which is ((MSETQ) ... ...)
  (cond ((getl (caar array-ref) '(array-mode))
	 (let ((t-ref (translate array-ref))
	       (t-value (translate value))
	       (mode))
	   (warn-mode array-ref (car t-ref) (car t-value))
	   (setq mode (car t-ref))	; ooh, could be bad.
	   `(,mode
	     . (store ,(cdr t-ref) ,(cdr t-value)))))
	($translate_fast_arrays 
	 (funcall 'tr-maset (caar array-ref) (dtranslate value)
		  (mapcar 'dtranslate (copy-list (cdr array-ref)))))
	(t
	 ;; oops. Hey, I switch around order of evaluation
	 ;; here. no need to either man. gee.
	 (translate `((marrayset) ,value
		      ,(if $tr_array_as_ref (caar array-ref)
			   `((mquote) ,(caar array-ref)))
		      ,@(cdr array-ref))))))
 

(def%tr marrayref (form)
  (setq form (cdr form))
  (let ((mode (cond ((atom (car form))
		     (mget (car form) 'array-mode)))))
    (cond ((null mode) (setq mode '$any)))
    (setq form (tr-args form))
    (let ((op (car form)))
      `(,mode . (,(if (and (= (length form) 2)
			   (eq mode '$float))
		      (progn (push-autoload-def 'marrayref '(marrayref1$))
			     'marrayref1$)
		      'marrayref)
		 ,op . ,(cdr form))))))

(def%tr marrayset (form)
  (setq form (cdr form))
  (let ((mode (cond ((atom (cadr form))
		     (mget (cadr form) 'array-mode)))))
    (when (null mode) (setq mode '$any))
    (setq form (tr-args form))
    (destructuring-let (((val aarray . inds) form))
      `(,mode . (,(if (and (= (length inds) 1)
			   (eq mode '$float))
		      (progn
			(push-autoload-def 'marrayset '(marrayset1$))
			'marrayset1$)
		      'marrayset)
		  ,val ,aarray . ,inds)))))

(def%tr mlist (form)
  (if (null (cdr form)) ;;; []
      '($any . '((mlist)))
      `($any . (list '(mlist) . ,(tr-args (cdr form))))))

(def%tr $first (form)
  (setq form (translate (cadr form)))
  (call-and-simp '$any (if (eq '$list (car form))
			   'cadr
			   '$first)
		 (list (cdr form))))

;; Local Modes:
;; Mode: LISP
;; Comment Col: 40
;; END:
