;;; -*- Mode:LISP; Package:LISP-INTERNALS; Base:10; Readtable:ZL -*-

;;;; Structures

(defun MAKE-STRUCTURE (length)
  (cons:allocate-structure
    (1+ length)
    0
    vinc:$$dtp-structure
    (cons:make-header vinc:$$dtp-structure-header length)))

;(defun structure-ref (name index struct)
;  (let ((length (li:read-struct-header struct))
;	(struct-name (cons:contents-offset struct 1)))
;    (if (or (eq struct-name
;		name)
;	    (and (consp struct-name)
;		 (member name struct-name :test #'eq)))
;	(if (< index length)
;	    (cons:contents-offset struct index)
;	  (error "Structure too short"))
;      (error "Structure of wrong type"))))

;;; Structure Ref
;;;  Takes: 
;;;    A0 NAME:   a symbol, which should match the type slot
;;;    A1 INDEX:  an integer, the type slot is 0
;;;    A2 STRUCT: the structure object
;;;  Checks:
;;;    1. If it's a structure
;;;    2. If it's big enough
;;;    3. If it has the right name
(defafun STRUCTURE-REF (name index struct)
  ;; Read header and check data type of struct
  (alu setl (vma-start-read boxed-vma boxed-md) a2 gr:*random-array* dt-right-array-and-left-structure)
  ;; Check data type of index
  (alu setr a1 a1 a1 dt-both-fixnum boxed-right)
  ;; Check bounds of index
  (alu l-r nop a1 md bw-24)
  ;; Read structure name
  (alu l+r (vma-start-read unboxed-vma boxed-md) a2 gr:*one* br-not-less-than)
  (branch too-short ())
  (move a3 md)
  ;; start read of slot
  (alu l+r+c (vma-start-read unboxed-vma boxed-md) a1 a2 carry-1 bw-24)
  ;; test type
  (alu l-r nop a0 a3 bw-32)
  (test br-not-equal)
  (branch wrong-type ())
  ;; type ok, return slot
  (return md boxed-right)
 wrong-type
  (move o0 a0 ch-tail-open)
  (move o1 a1)
  (move o2 a2)
  (tail-call (structure-ref-wrong-type 4) (o3 a3))
 too-short
  (movei o0 '"The structure ~a does not have a slot ~a" boxed ch-tail-open)
  (move  o1 a2)
  (tail-call (error 3) (o2 a1)))
  

(defun structure-ref-wrong-type (name index struct type)
  (if (and (consp type)
	   (member-eq name type))
      (cons:contents-offset struct (1+ index))
    (error "The structure ~a is not of type ~a" struct name)))


(defafun STRUCTURE-SET (name index struct value)
  ;; Read header and check data type of struct
  (alu setl (vma-start-read boxed-vma boxed-md) a2 gr:*random-array* dt-right-array-and-left-structure)
  ;; Check data type of index
  (alu setr a1 a1 a1 dt-both-fixnum boxed-right)
  (alu l-r nop a1 md bw-24)
  (alu l+r (vma-start-read unboxed-vma boxed-md) a2 gr:*one* br-not-less-than)
  (branch too-short ())
  (move a4 md)
  ;; start read of slot
  (alu l+r+c vma-start-read-will-write a1 a2 bw-24 carry-1 boxed-vma boxed-md)
  (nop)
  (move nop md)
  (move md-start-write a3 boxed-md)
  (return a3 boxed-right)
  ;; test type
  (alu l-r nop a0 a3 bw-32)
  (test br-not-equal)
  (branch wrong-type ())
  ;; type ok, return slot
  (return md boxed-right)
 wrong-type
  (move o0 a0 ch-tail-open)
  (move o1 a1)
  (move o2 a2)
  (move o3 a3)
  (tail-call (structure-set-wrong-type 5) (o4 a4))
 too-short
  (movei o0 '"The structure ~a does not have a slot ~a" boxed ch-tail-open)
  (move  o1 a2)
  (tail-call (error 3) (o2 a1)))
      
(defun structure-set-wrong-type (name index struct value type)
  (if (and (consp type)
	   (member name type :test #'eq))
      (cons:store-contents-offset struct (1+ index) value)
    (error "The structure ~a is not of type ~a" struct name)))

    
(defmacro MAKE-STRUCTURE-OBJECT (name &rest slot-values)
  (let ((struct-var (gensym 'struct)))
    `(LET ((,struct-var (MAKE-STRUCTURE ,(1+ (length slot-values)))))
       (cons:store-contents-offset ,struct-var 1 ,name)
       ,@(let ((n 1))
	   (mapcar #'(lambda (slot-val)
		       `(CONS:STORE-CONTENTS-OFFSET ,struct-var ,(incf n) ,slot-val))
		   slot-values))
       ,struct-var)))


(defun TYPEP-STRUCTURE (thing type)
  (and (vinc:structure-p thing)
       (let ((stypes (cons:contents-offset thing 1)))
	 (or (eq stypes type)
	     (and (consp stypes)
		  (member type stypes :test #'eq))))))
       
  
  
  