"$Header: record.l,v 1.3 84/02/29 19:33:50 jkf Exp $")
;; -[Mon Feb 20 15:00:52 1984 by jkf]-
(or (get 'record 'version) (load 'record)))
(defvar record-pkg-indicator 'record-package-dr-record)
(defmacro dr-error (message &rest args)
;; print an error preceeded by 'defrecord'
`(error ',(concat "defrecord: " message) ,@args))
; storage ; 'list' or 'vector'
; options ; subset of 'named', 'access-check'
; fields ; list of dr-field records
(eval-when (compile eval)
'(dr-record list nil ((fields 3 nil)
(defmacro make-dr-record (&rest args) (record-pkg-construct 'dr-record args))
(defmacro dr-record-storage (arg) `(nth 1 ,arg))
(defmacro dr-record-options (arg) `(nth 2 ,arg))
(defmacro dr-record-fields (arg) `(nth 3 ,arg))
; ;; internal structure used to store info on fields
(eval-when (compile eval)
'(dr-field list nil ((defaultvalue 2 nil)
(defmacro make-dr-field (&rest args) (record-pkg-construct 'dr-field args))
(defmacro dr-field-name (arg) `(nth 0 ,arg))
(defmacro dr-field-offset (arg) `(nth 1 ,arg))
(defmacro dr-field-defaultvalue (arg) `(nth 2 ,arg))
;; internal functions (called by macros)
(defun record-pkg-construct (recname args)
;; called to expand a make- form.
;; recname is the name of a record
; convert to an assq list, verifing field names
(let* ((dr-record (get recname record-pkg-indicator))
(fields (dr-record-fields dr-record))
(do ((xx args (cddr xx)))
(if (assq (car xx) fields)
then (push (cons (car xx) (cadr xx)) given)
else (dr-error " for record " recname
", this field doesn't exist " (car xx))))
;; now build a list of values.
;; use the fact that the fields list is in the reverse order
(do ((xx fields (cdr xx))
;; now we have a list of values to compute to build this
(caseq (dr-record-storage dr-record)
(t (error "record package is confused about storage type "))))
(if (setq got (assq (dr-field-name (car xx)) given))
then (push (cdr got) res) ; given value
else (push (dr-field-defaultvalue (car xx))
(defun record-pkg-access (recname fieldname arg)
;; return code access the given field in the given record
(let ((dr-record (get recname record-pkg-indicator))
(setq fieldinfo (assq fieldname (dr-record-fields dr-record)))
(setq options (dr-record-options dr-record))
(setq storage (dr-record-storage dr-record))
then (dr-error "internal error: can't find field " fieldname
(if (memq 'access-check options)
then (setq recnamefield (assq '-record-field-name-
(dr-record-fields dr-record)))
`((lambda (defrecord-acma)
(cond ((not (eq ',recname
(record-pkg-illegal-access ',recname ',fieldname
(dr-field-offset fieldinfo)
else (dr-accessor storage (dr-field-offset fieldinfo) arg))))
(defun dr-accessor (class index obj)
;; determine the correct field accessor to get the index'th element
;; from obj, give the storage type class (either list or vector).
(list `(nth ,index ,obj))
(vector `(vref ,obj ,index))
(t (error "record package: illegal storage class " class))))
(defun record-pkg-illegal-access (recname fieldname value)
(error "Unable to access field " fieldname " of record " recname
" because this is not an instance of that record: "
(defun defrecord-name (form)
;; user callable function to return the record name of
(if (defrecord-namedp form)
then (if (dtpr form) then (cadr form)
else (error "record-name: this record doesn't have a name " form)))
(defun defrecord-namedp (form)
;; return t iff form is a named record
(and (or (and (dtpr form)
(progn (setq name (cadr form)) t)
(progn (setq name (vref form 1)) t)
(get name record-pkg-indicator)
;; The following functions are user callable
(defvar defrecord-default-flags nil) ; what is assumed in the flag field
(defmacro defrecord (&rest form)
;; user callable function
then (error "defrecord: missing record name in " form))
(givenoptions defrecord-default-flags)
(namedp)(access-checkp) (vectorp))
then (setq givenoptions (append givenoptions (cdr name))
then (dr-error "non symbol record name " name))
(do ((xx givenoptions (cdr xx)))
(access-check (setq access-checkp t))
(vector (setq vectorp t))
;; look for conflicting options
(if (and access-checkp (not namedp))
then (error "defrecord: Can't specify access-check without also specifying named " form))
(if namedp then (push 'named savedoptions))
(if access-checkp then (push 'access-check savedoptions))
then (let ((namefield `(-record-field-name- ',name)))
then (setq args (cons (car args)
else (setq args (list namefield)))))
then (push (make-dr-field
else (push (make-dr-field
; return a progn compile of an accessor and a collection
(eval-when (compile load eval)
(putprop ',name ',(make-dr-record
(defmacro ,(concat 'make- name) (&rest args)
(record-pkg-construct ',name args))
,@(mapcar '(lambda (dr-field)
(dr-field-name dr-field))
',(dr-field-name dr-field)
(putprop 'record t 'version)