(setq rcs-vector-
   "$Header:vector.l 12.0$")
   "$ACIS:vector.l 12.0$")

;; vector handling functions	-[Sun Jun 19 15:09:14 1983 by jkf]-
;; [also contains closure functions]
;;
;; preliminary.  this is subject to change at any moment.
;; Don't use the functions in this file!!	--jkf
;;
;; contains functions:
;;  vector{,i-byte,i-word,i-long}   : create and initialize
;;  vref{,i-byte,i-word,i-long}	 : reference
;;  vset{,i-byte,i-word,i-long}	 : set
;;  vsize	-- must write
;;  vsize-word
;;  vsize-byte 
;;
;; references external functions
;;  new-vector{,i-byte,i-word,i-long
;;
;; references internal functions:
;;  int:vref 'vect 'index 'class
;;  int:vset 'vect 'index 'value 'class
;;  int:vsize 'vect

;--- vector
;  call is (vector elmt0 elmt1 ... elmtn)
; creates an n-1 size vector and initializes
;
(defmacro vector-macro (create class)
   `(let ((vec (,create n)))
      (do ((from n to)
	   (to (1- n) (1- to)))
	  ((< to 0))
	  (int:vset vec to (arg from) ,class))
      vec))

(defun vector n (vector-macro new-vector 3))
(defun vectori-byte n (vector-macro new-vectori-byte 0))
(defun vectori-word n (vector-macro new-vectori-word 1))
(defun vectori-long n (vector-macro new-vectori-long 2))

;--- vref
; refernces an element of a vector
;   (vref 'vect 'index)
;
(defmacro vref-macro (vector index predicate limit class)
   `(cond ((not (,predicate ,vector))
	  ,(cond ((eq predicate 'vector)
		  `(error "vref: non vector argument " ,vector))
		 (t `(error "vref: non vectori argument " ,vector))))
	 ((not (fixp ,index))
	  (error "vref: non fixnum index " ,index))
	 ((or (< ,index 0) (not (< ,index ,limit)))
	  (error "vref: index out of range " ,index ,vector))
	 (t (int:vref ,vector ,index ,class))))

(defun vref (vect ind)
   (vref-macro vect ind vectorp (vsize vect) 3))

(defun vrefi-byte (vect ind)
   (vref-macro vect ind vectorip (vsize-byte vect) 0))
(defun vrefi-word (vect ind)
   (vref-macro vect ind vectorip (vsize-word vect) 1))
(defun vrefi-long (vect ind)
   (vref-macro vect ind vectorip (vsize vect) 2))


;--- vset
; use:
;	(vset 'vector 'index 'value)
;
(defmacro vset-macro (vector index value predicate limit class)
   `(cond ((not (,predicate ,vector))
	  ,(cond ((eq predicate 'vector)
		  `(error "vset: non vector argument " ,vector))
		 (t `(error "vset: non vectori argument " ,vector))))
	 ((not (fixp ,index))
	  (error "vset: non fixnum index " ,index))
	 ((or (<& ,index 0) (not (<& ,index ,limit)))
	  (error "vset: index out of range " ,index ,vector))
	 (t (int:vset ,vector ,index ,value ,class))))

(defun vset (vect ind val)
   (vset-macro vect ind val vectorp (vsize vect) 3))

(defun vseti-byte (vect ind val)
   (vset-macro vect ind val vectorip (vsize-byte vect) 0))

(defun vseti-word (vect ind val)
   (vset-macro vect ind val vectorip (vsize-word vect) 1))

(defun vseti-long (vect ind val)
   (vset-macro vect ind val vectorip  (vsize vect) 2))


;;; vector sizes

;--- vsize :: size of vector viewed as vector of longwords
;
(defun vsize (vector)
   (if (or (vectorp vector) (vectorip vector))
      then (int:vsize vector 2)
      else (error "vsize: non vector argument " vector)))

(defun vsize-word (vectori)
   (if (vectorip vectori)
      then (int:vsize vectori 1)
      else (error "vsize-word: non vectori argument " vectori)))

(defun vsize-byte (vectori)
   (if (vectorip vectori)
      then (int:vsize vectori 0)
      else (error "vsize-byte: non vectori argument " vectori)))

;; vector property list functions
;;
(defun vget (vector ind)
   (let ((x (vprop vector)))
      (if (dtpr x)
	 then (get x ind))))

;--- vputprop :: store value, indicator pair on property list
; if a non-dtpr is already there,  make it the car of the list
;
(defun vputprop (vector value ind)
   (let ((x (vprop vector)))
      (if (not (dtpr x))	
	 then (setq x (ncons x))
	      (vsetprop vector x))
      (putprop x value ind)))

	     
;; closures
;
;- closures are implemented in terms of vectors so we'll store the
; code here for now
;  a closure is a vector with leader field eq to 'closure'
; the 0th element of a closure vector is the functional form
; to funcall
; then the elements go in triplets
;			1 is the symbol name
;			    either
;	2 is nil 			2 is a pointer to a vector
;	3 is the saved value		3 is a fixnum index into the vector
;	 ^				   ^
;	 |---- the simple case		   |-- when we are sharing a value
;					       slot, this points to the
;					       value slot
;
; the size of the vector tells the number of variables.
;

;--- closure :: make a closure
; form (closure 'l_vars 'g_fcn)
; l_vars is a list of symbols
; g_fcn is a functional form, either a symbol or a lambda expression
; alist is a list of what has been already stored so far.
;   it will always be non nil, so we can nconc to it to return values.
;
(defun make-fclosure-with-alist (vars fcn alist)
   (cond ((not (or (null vars) (dtpr vars)))
	  (error "fclosure: vars list has a bad form " vars)))
   
   (let ((vect (new-vector (1+ (length vars)) nil 'fclosure)))
      (do ((xx vars (cdr xx))
	   (val)
	   (sym)
	   (i 1 (1+ i)))
	  ((null xx)
	   (setf (vref vect 0) fcn)	; store the function to call
	   vect)
	  (setq sym (car xx))
	  (cond ((not (symbolp sym))
		 (error "fclosure: non symbol in var list " sym)))

	  ; don't allow the variable nil to be closed over
	  (cond ((null sym)
		 (error "fclosure: you can't close over nil " vars)))

	  ; if the fclosure variable has already been given slot, use
	  ; it, else make a new one
	  (cond ((null (setq val (assq sym alist)))
		   ; if the variable is bound use it's current value,
		   ; else use nil
		   (cond ((setq val (boundp sym))
			  (setq val (cdr val))))
		   ; generate a new closure variable object
		   (setq val (cons sym (cons val (copyint* 0))))
		   ; remember this value for later fclosures
		   (nconc alist (list val))))
	  (setf (vref vect i) val))))
   


;--- fclosure :: generate a simple fclosure
; 
(defun fclosure (vars func)
   (make-fclosure-with-alist vars func (list nil)))

(defun fclosure-list n
   (cond ((not (evenp n))
	  (error "fclosure-alist: not given an even number of arguments: "
		 (listify n))))
   (do ((i 1 (+ i 2))
	(alist (list nil))
	(res))
       ((> i n) (nreverse res))
       (push (make-fclosure-with-alist (arg i) (arg (1+ i)) alist) res)))

(defun fclosurep (fclosure)
   (and (vectorp fclosure)
	(eq 'fclosure (vprop fclosure))))
(defun fclosure-alist (fclosure)
   (cond ((fclosurep fclosure)
	  (do ((xx 1 (1+ xx))
	       (lim  (vsize fclosure))
	       (val)
	       (res))
	      ((not (< xx lim))
	       res)
	      (setq val (vref fclosure xx))
	      (push (cons (car val) (cadr val)) res)))
	 (t (error "fclosure-alist: non fclosure argument: " fclosure))))



(defun fclosure-function (fclosure)
   (and (fclosurep fclosure)
	(vref fclosure 0)))

(defun vector-dump (vect)
   (let (size)
      (msg "size = " (setq size (vsize vect)) ", prop= " (vprop vect) N)
      (do ((ii 0 (1+ ii)))
	  ((not (< ii size)))
	  (msg ii ": " (vref vect ii) N ))))
   
	
;--- symeval-in-fclosure :: determine the value of a symbol
;   with respect to an fclosure.
;
(defun symeval-in-fclosure (fclosure symbol)
  (cond ((not (fclosurep fclosure))
	 (error "set-in-fclosure: non fclosure first argument: " fclosure))
	(t (do ((xx 1 (1+ xx))
		(val)
		(lim (vsize fclosure)))
	       ((not (< xx lim))
		(error "symeval-in-fclosure: variable not found" symbol))
	       (setq val (vref fclosure xx))
	       (cond ((eq symbol (car val))
		      (return (int:fclosure-stack-stuff val))))))))

;--- set-in-fclosure :: set the value of a symbol in an fclosure
;
(defun set-in-fclosure (fclosure symbol value)
  (cond ((not (fclosurep fclosure))
	 (error "set-in-fclosure: non fclosure first argument: " fclosure))
	(t (do ((xx 1 (1+ xx))
		(val)
		(lim (vsize fclosure)))
	       ((not (< xx lim))
		(error "set-in-fclosure: variable not found" symbol))
	       (setq val (vref fclosure xx))
	       (cond ((eq symbol (car val))
		      (return (int:fclosure-stack-stuff val value))))))))

(defmacro let-fclosed (vars function)
  `(let ,vars (fclosure ',(mapcar #'(lambda (x) (if (atom x) x (car x))) vars)
			,function)))
		

