|
|
1.1 root 1: ;;; -*- Mode:Lisp; Package:SI; Lowercase:True; Base:8 -*-
2: ;;; ** (c) Copyright 1980 Massachusetts Institute of Technology **
3: (setq rcs-struct-
4: "$Header: /usr/lib/lisp/RCS/struct.l,v 1.2 83/08/06 08:41:10 jkf Exp $")
5:
6: ;The master copy of this file is in MC:ALAN;NSTRUCT >
7: ;The current Lisp machine copy is in AI:LISPM2;STRUCT >
8: ;The current Multics copy is in >udd>Mathlab>Bawden>defstruct.lisp
9:
10: ;***** READ THIS PLEASE! *****
11: ;If you are thinking of munging anything in this file you might want
12: ;to consider finding me (ALAN) and asking me to mung it for you.
13: ;There is more than one copy of this file in the world (it runs in PDP10
14: ;and Multics MacLisp and on LispMachines) and whatever amazing
15: ;features you are considering adding might be usefull to those people
16: ;as well. If you still cannot contain yourself long enough to find
17: ;me, AT LEAST send me a piece of mail describing what you did and why.
18: ;Thanks for reading this flame.
19: ; Alan Bawden (ALAN@MC)
20:
21: ;Things to fix:
22:
23: ;For LispMachine:
24: ; :%P-LDB type (this is hard to do, punt for now.)
25:
26: ;For Multics:
27: ; displacement is a problem (no displace)
28: ; nth, nthcdr don't exist there
29: ; ldb, dpb don't exist, so byte fields don't work without Mathlab macros
30: ; callable accessors don't work
31: ; dpb is needed at the user's compile time if he is using byte fields.
32:
33: #+Franz (environment-maclisp)
34:
35: (eval-when (compile)
36: (cond ((status feature ITS)
37: (load '|alan;lspenv init|))
38: ((status feature Multics)
39: (load '|>udd>Mathlab>Bawden>lspenv.lisp|))))
40:
41: #+PDP10
42: (cond ((status nofeature noldmsg)
43: (terpri msgfiles)
44: (princ '#.(and (status feature PDP10)
45: (maknam (nconc (exploden ";Loading DEFSTRUCT ")
46: (exploden (caddr (truename infile))))))
47: msgfiles)))
48:
49: #+Multics
50: (declare (genprefix defstruct-internal-)
51: (macros t))
52:
53: #+Franz
54: (declare (macros t))
55:
56: #M
57: (eval-when (eval compile)
58: (setsyntax #/: (ascii #\space) nil))
59:
60: ;; #+Franz
61: ;; (eval-when (eval compile)
62: ;; (setsyntax #/: 'vseparator)) ; make :'s go away
63:
64: (eval-when (eval)
65: ;;So we may run the thing interpreted we need the simple
66: ;;defstruct that lives here:
67: (cond ((status feature ITS)
68: (load '|alan;struct initial|))
69: ((status feature Multics)
70: (load '|>udd>Mathlab>Bawden>initial_defstruct|))
71: ((status feature Franz)
72: (load 'structini.l))))
73:
74: (eval-when (compile)
75: ;;To compile the thing this probably is an old fasl: (!)
76: (cond ((status feature ITS)
77: (load '|alan;struct boot|))
78: ((status feature Multics)
79: (load '|>udd>Mathlab>Bawden>boot_defstruct|))
80: ((status feature Franz) ; This is only needed for bootstrapping
81: (cond ((and (null (getd 'defstruct))
82: (not (probef
83: (concat lisp-library-directory "//struct.o"))))
84: (load 'structini))))
85: ))
86:
87: #+Multics
88: (defun nth (n l)
89: (do ((n n (1- n))
90: (l l (cdr l)))
91: ((zerop n) (car l))))
92:
93: #+Multics
94: (defun nthcdr (n l)
95: (do ((n n (1- n))
96: (l l (cdr l)))
97: ((zerop n) l)))
98:
99: #+(or Franz Multics)
100: (defun displace (x y)
101: (cond ((atom y)
102: (rplaca x 'progn)
103: (rplacd x (list y)))
104: (t
105: (rplaca x (car y))
106: (rplacd x (cdr y))))
107: x)
108:
109: ;;; You might think you could use progn for this, but you can't!
110: (defun defstruct-dont-displace (x y)
111: x ;ignored
112: y)
113:
114: ;;; Eval this before attempting incremental compilation
115: (eval-when (eval compile)
116:
117: #+PDP10
118: (defmacro append-symbols args
119: (do ((l (reverse args) (cdr l))
120: (x)
121: (a nil (if (or (atom x)
122: (not (eq (car x) 'quote)))
123: (if (null a)
124: `(exploden ,x)
125: `(nconc (exploden ,x) ,a))
126: (let ((l (exploden (cadr x))))
127: (cond ((null a) `',l)
128: ((= 1 (length l)) `(cons ,(car l) ,a))
129: (t `(append ',l ,a)))))))
130:
131: ((null l) `(implode ,a))
132: (setq x (car l))))
133:
134: #+Multics
135: (defmacro append-symbols args
136: `(make_atom (catenate . ,args)))
137:
138: #+LispM
139: (defmacro append-symbols args
140: `(intern (string-append . ,args)))
141:
142: #+Franz
143: (defmacro append-symbols (&rest args)
144: `(concat . ,args))
145:
146: (defmacro defstruct-putprop (sym val ind)
147: `(push `(defprop ,,sym ,,val ,,ind) returns))
148:
149: (defmacro defstruct-put-macro (sym fcn)
150: #M `(defstruct-putprop ,sym ,fcn 'macro)
151: #+lispm
152: (setq fcn (if (and (not (atom fcn))
153: (eq (car fcn) 'quote))
154: `'(macro . ,(cadr fcn))
155: `(cons 'macro ,fcn)))
156: #+Franz
157: (setq fcn (if (and (not (atom fcn))
158: (eq (car fcn) 'quote))
159: `'(macro (macroarg) (,(cadr fcn) macroarg))
160: `(cons 'macro ,fcn))) ;; probably incorrect
161:
162: #Q `(push `(fdefine ',,sym ',,fcn t) returns)
163: #+Franz `(push `(def ,,sym ,,fcn) returns)
164: )
165:
166: (defmacro make-empty () `'%%defstruct-empty%%)
167:
168: (defmacro emptyp (x) `(eq ,x '%%defstruct-empty%%))
169:
170: ;;;Here we must deal with the fact that error reporting works
171: ;;;differently everywhere!
172:
173: #+(or Franz PDP10)
174: ;;;first arg is ALWAYS a symbol or a quoted symbol:
175: (defmacro defstruct-error (message &rest args)
176: (let* ((chars (nconc (exploden (if (atom message)
177: message
178: (cadr message)))
179: '(#/.))) ;"Bad frob" => "Bad frob."
180: (new-message
181: (maknam (if (null args)
182: chars
183: (let ((c (car chars))) ;"Bad frob." => "-- bad frob."
184: (or (< c #/A)
185: (> c #/Z)
186: (rplaca chars (+ c #o40)))
187: (append '(#/- #/- #\space) chars))))))
188: `(error ',new-message
189: ,@(cond ((null args) `())
190: ((null (cdr args)) `(,(car args)))
191: (t `((list ,@args)))))))
192:
193: #+Multics
194: ;;;first arg is ALWAYS a string:
195: (defmacro defstruct-error (message &rest args)
196: `(error ,(catenate "defstruct: "
197: message
198: (if (null args)
199: "."
200: ": "))
201: ,@(cond ((null args) `())
202: ((null (cdr args)) `(,(car args)))
203: (t `((list ,@args))))))
204:
205: #+LispM
206: ;;;first arg is ALWAYS a string:
207: (defmacro defstruct-error (message &rest args)
208: `(ferror nil
209: ,(string-append message
210: (if (null args)
211: "."
212: ":~@{ ~S~}"))
213: ,@args))
214:
215: );End of eval-when (eval compile)
216:
217: ;;;If you mung the the ordering af any of the slots in this structure,
218: ;;;be sure to change the version slot and the definition of the function
219: ;;;get-defstruct-description. Munging the defstruct-slot-description
220: ;;;structure should also cause you to change the version "number" in this manner.
221: (defstruct (defstruct-description
222: (:type :list)
223: (:default-pointer description)
224: (:conc-name defstruct-description-)
225: (:alterant nil))
226: (version 'one)
227: type
228: (displace 'defstruct-dont-displace)
229: slot-alist
230: named-p
231: constructors
232: (default-pointer nil)
233: (but-first nil)
234: size
235: (property-alist nil)
236: ;;end of "expand-time" slots
237: name
238: include
239: (initial-offset 0)
240: (eval-when '(eval compile load))
241: alterant
242: (conc-name nil)
243: (callable-accessors #M nil #Q t)
244: (size-macro nil)
245: (size-symbol nil)
246: )
247:
248: (defun get-defstruct-description (name)
249: (let ((description (get name 'defstruct-description)))
250: (cond ((null description)
251: (defstruct-error
252: "A structure with this name has not been defined" name))
253: ((not (eq (defstruct-description-version) 'one))
254: (defstruct-error "The description of this structure is out of date,
255: it should be recompiled using the current version of defstruct"
256: name))
257: (t description))))
258:
259: ;;;See note above defstruct-description structure before munging this one.
260: (defstruct (defstruct-slot-description
261: (:type :list)
262: (:default-pointer slot-description)
263: (:conc-name defstruct-slot-description-)
264: (:alterant nil))
265: number
266: (ppss nil)
267: init-code
268: (type 'notype)
269: (property-alist nil)
270: ref-macro-name
271: )
272:
273: ;;;Perhaps this structure wants a version slot too?
274: (defstruct (defstruct-type-description
275: (:type :list)
276: (:default-pointer type-description)
277: (:conc-name defstruct-type-description-)
278: (:alterant nil))
279: ref-expander
280: ref-no-args
281: cons-expander
282: cons-flavor
283: (cons-keywords nil)
284: (named-type nil)
285: (overhead 0)
286: (defstruct-expander nil)
287: )
288:
289: ;; (DEFSTRUCT (<name> . <options>) . <slots>) or (DEFSTRUCT <name> . <slots>)
290: ;;
291: ;; <options> is of the form (<option> <option> (<option> <val>) ...)
292: ;;
293: ;; <slots> is of the form (<slot> (<slot> <initial-value>) ...)
294: ;;
295: ;; Options:
296: ;; :TYPE defaults to HUNK
297: ;; :CONSTRUCTOR defaults to "MAKE-<name>"
298: ;; :DEFAULT-POINTER defaults to empty (if no <val> given defaults to "<name>")
299: ;; :CONC-NAME defaults to empty (if no <val> given defaults to "<name>-")
300: ;; :SIZE-SYMBOL defaults to empty (if no <val> given defaults to "<name>-SIZE")
301: ;; :SIZE-MACRO defaults to empty (if no <val> given defaults to "<name>-SIZE")
302: ;; :ALTERANT defaults to "ALTER-<name>"
303: ;; :BUT-FIRST must have a <val> given
304: ;; :INCLUDE must have a <val> given
305: ;; :PROPERTY (:property foo bar) gives the structure a foo property of bar.
306: ;; :INITIAL-OFFSET can cause defstruct to skip over that many slots.
307: ;; :NAMED takes no value. Tries to make the structure a named type.
308: ;; :CALLABLE-ACCESSORS defaults to T on the LispMachine, NIL elsewhere.
309: ;; <type> any type name can be used without a <val> instead of saying (TYPE <type>)
310: ;; <other> any symbol with a non-nil :defstruct-option property. You say
311: ;; (<other> <val>) and the effect is that of (:property <other> <val>)
312: ;;
313: ;; Properties used:
314: ;; DEFSTRUCT-TYPE-DESCRIPTION each type has one, it is a type-description.
315: ;; DEFSTRUCT-NAME each constructor, alterant and size macro has one, it is a name.
316: ;; DEFSTRUCT-DESCRIPTION each name has one, it is a description (see below).
317: ;; DEFSTRUCT-SLOT each accesor has one, it is of the form: (<name> . <slot>)
318: ;; :DEFSTRUCT-OPTION if a symbol FOO has this property then it can be used as an
319: ;; option giving the structure a FOO property of the value (which must be given).
320:
321: (defmacro defstruct (options &body items)
322: (let* ((description (defstruct-parse-options options))
323: (type-description (get (defstruct-description-type)
324: 'defstruct-type-description))
325: (name (defstruct-description-name))
326: (new-slots (defstruct-parse-items items description))
327: (returns nil))
328: (push `',name returns)
329: (or (null (defstruct-type-description-defstruct-expander))
330: (setq returns (append (funcall (defstruct-type-description-defstruct-expander)
331: description)
332: returns)))
333: #Q (push `(record-source-file-name ',name) returns)
334: (defstruct-putprop name description 'defstruct-description)
335: (let ((alterant (defstruct-description-alterant))
336: (size-macro (defstruct-description-size-macro))
337: (size-symbol (defstruct-description-size-symbol)))
338: (cond (alterant
339: (defstruct-put-macro alterant 'defstruct-expand-alter-macro)
340: (defstruct-putprop alterant name 'defstruct-name)))
341: (cond (size-macro
342: (defstruct-put-macro size-macro 'defstruct-expand-size-macro)
343: (defstruct-putprop size-macro name 'defstruct-name)))
344: (cond (size-symbol
345: (push `(#M defvar #Q defconst #F setq ,size-symbol
346: ,(+ (defstruct-description-size)
347: (defstruct-type-description-overhead)))
348: returns))))
349: (do cs (defstruct-description-constructors) (cdr cs) (null cs)
350: (defstruct-put-macro (caar cs) 'defstruct-expand-cons-macro)
351: (defstruct-putprop (caar cs) name 'defstruct-name))
352: `(eval-when ,(defstruct-description-eval-when)
353: ,.(defstruct-define-ref-macros new-slots description)
354: . ,returns)))
355:
356: (defun defstruct-parse-options (options)
357: (let ((name (if (atom options) options (car options)))
358: (type nil)
359: (constructors (make-empty))
360: (alterant (make-empty))
361: (included nil)
362: (named-p nil)
363: (description (make-defstruct-description)))
364: (setf (defstruct-description-name) name)
365: (do ((op) (val) (vals)
366: (options (if (atom options) nil (cdr options))
367: (cdr options)))
368: ((null options))
369: (if (atom (setq op (car options)))
370: (setq vals nil)
371: (setq op (prog1 (car op) (setq vals (cdr op)))))
372: (setq val (if (null vals) (make-empty) (car vals)))
373: #Q AGAIN
374: (selectq op
375: (:type
376: (if (emptyp val)
377: (defstruct-error
378: "The type option to defstruct must have a value given"
379: name))
380: (setq type val))
381: (:default-pointer
382: (setf (defstruct-description-default-pointer)
383: (if (emptyp val) name val)))
384: (:but-first
385: (if (emptyp val)
386: (defstruct-error
387: "The but-first option to defstruct must have a value given"
388: name))
389: (setf (defstruct-description-but-first) val))
390: (:conc-name
391: (setf (defstruct-description-conc-name)
392: (if (emptyp val)
393: (append-symbols name '-)
394: val)))
395: (:callable-accessors
396: (setf (defstruct-description-callable-accessors)
397: (if (emptyp val) t val)))
398: (:displace
399: (setf (defstruct-description-displace)
400: (cond ((or (emptyp val)
401: (eq val 't))
402: 'displace)
403: ((null val) 'defstruct-dont-displace)
404: (t val))))
405: (:constructor
406: (cond ((null val)
407: (setq constructors nil))
408: (t
409: (and (emptyp val)
410: (setq val (append-symbols 'make- name)))
411: (setq val (cons val (cdr vals)))
412: (if (emptyp constructors)
413: (setq constructors (list val))
414: (push val constructors)))))
415: (:alterant
416: (setq alterant val))
417: (:size-macro
418: (setf (defstruct-description-size-macro)
419: (if (emptyp val)
420: (append-symbols name '-size)
421: val)))
422: (:size-symbol
423: (setf (defstruct-description-size-symbol)
424: (if (emptyp val)
425: (append-symbols name '-size)
426: val)))
427: (:include
428: (and (emptyp val)
429: (defstruct-error
430: "The include option to defstruct requires a value"
431: name))
432: (setq included val)
433: (setf (defstruct-description-include) vals))
434: (:property
435: (push (cons (car vals) (if (null (cdr vals)) t (cadr vals)))
436: (defstruct-description-property-alist)))
437: (:named
438: (or (emptyp val)
439: (defstruct-error
440: "The named option to defstruct doesn't take a value" name))
441: (setq named-p t))
442: (:eval-when
443: (and (emptyp val)
444: (defstruct-error
445: "The eval-when option to defstruct requires a value"
446: name))
447: (setf (defstruct-description-eval-when) val))
448: (:initial-offset
449: (and (or (emptyp val)
450: (not (fixp val)))
451: (defstruct-error
452: "The initial-offset option to defstruct requires a fixnum"
453: name))
454: (setf (defstruct-description-initial-offset) val))
455: (otherwise
456: (cond ((get op 'defstruct-type-description)
457: (or (emptyp val)
458: (defstruct-error
459: "defstruct type used as an option with a value"
460: op 'in name))
461: (setq type op))
462: ((get op ':defstruct-option)
463: (push (cons op (if (emptyp val) t val))
464: (defstruct-description-property-alist)))
465: (t
466: #Q (multiple-value-bind (new foundp)
467: (intern-soft op si:pkg-user-package)
468: (or (not foundp)
469: (eq op new)
470: (progn (setq op new) (go AGAIN))))
471: (defstruct-error
472: "defstruct doesn't understand this option"
473: op 'in name))))))
474: (cond ((emptyp constructors)
475: (setq constructors
476: (list (cons (append-symbols 'make- name)
477: nil)))))
478: (setf (defstruct-description-constructors) constructors)
479: (cond ((emptyp alterant)
480: (setq alterant
481: (append-symbols 'alter- name))))
482: (setf (defstruct-description-alterant) alterant)
483: (cond ((not (null type))
484: (let ((type-description
485: (or (get type 'defstruct-type-description)
486: #Q (multiple-value-bind
487: (new foundp)
488: (intern-soft type si:pkg-user-package)
489: (and foundp
490: (not (eq type new))
491: (progn (setq type new)
492: (get type 'defstruct-type-description))))
493: (defstruct-error
494: "Unknown type in defstruct"
495: type 'in name))))
496: (if named-p
497: (setq type
498: (or (defstruct-type-description-named-type)
499: (defstruct-error
500: "There is no way to make this defstruct type named"
501: type 'in name)))))))
502: (cond (included
503: (let ((d (get-defstruct-description included)))
504: (if (null type)
505: (setq type (defstruct-description-type d))
506: (or (eq type (defstruct-description-type d))
507: (defstruct-error
508: "defstruct types must agree for include option"
509: included 'included-by name)))
510: (and named-p
511: (not (eq type (defstruct-type-description-named-type
512: (or (get type 'defstruct-type-description)
513: (defstruct-error
514: "Unknown type in defstruct"
515: type 'in name 'including included)))))
516: (defstruct-error
517: "Included defstruct's type isn't a named type"
518: included 'included-by name))))
519: ((null type)
520: (setq type
521: (cond (named-p
522: #+PDP10 ':named-hunk
523: #+Franz ':named-vector
524: #+Multics ':named-list
525: #+LispM ':named-array)
526: (t
527: #+PDP10 ':hunk
528: #+Franz ':named-vector
529: #+Multics ':list
530: #+LispM ':array)))))
531: (let ((type-description (or (get type 'defstruct-type-description)
532: (defstruct-error
533: "Undefined defstruct type"
534: type 'in name))))
535: (setf (defstruct-description-type) type)
536: (setf (defstruct-description-named-p)
537: (eq (defstruct-type-description-named-type) type)))
538: description))
539:
540: (defun defstruct-parse-items (items description)
541: (let ((name (defstruct-description-name))
542: (offset (defstruct-description-initial-offset))
543: (include (defstruct-description-include))
544: (o-slot-alist nil)
545: (conc-name (defstruct-description-conc-name)))
546: (or (null include)
547: (let ((d (get (car include) 'defstruct-description)))
548: (setq offset (+ offset (defstruct-description-size d)))
549: (setq o-slot-alist
550: (subst nil nil (defstruct-description-slot-alist d)))
551: (do ((l (cdr include) (cdr l))
552: (it) (val))
553: ((null l))
554: (cond ((atom (setq it (car l)))
555: (setq val (make-empty)))
556: (t
557: (setq val (cadr it))
558: (setq it (car it))))
559: (let ((slot-description (cdr (assq it o-slot-alist))))
560: (and (null slot-description)
561: (defstruct-error
562: "Unknown slot in included defstruct"
563: it 'in include 'included-by name))
564: (setf (defstruct-slot-description-init-code) val)))))
565: (do ((i offset (1+ i))
566: (l items (cdr l))
567: (slot-alist nil)
568: #+PDP10 (chars (exploden conc-name)))
569: ((null l)
570: (setq slot-alist (nreverse slot-alist))
571: (setf (defstruct-description-size) i)
572: (setf (defstruct-description-slot-alist)
573: (nconc o-slot-alist slot-alist))
574: slot-alist)
575: (cond ((atom (car l))
576: (push (defstruct-parse-one-field
577: (car l) i nil nil conc-name #+PDP10 chars)
578: slot-alist))
579: ((atom (caar l))
580: (push (defstruct-parse-one-field
581: (caar l) i nil (cdar l) conc-name #+PDP10 chars)
582: slot-alist))
583: (t
584: (do ll (car l) (cdr ll) (null ll)
585: (push (defstruct-parse-one-field
586: (caar ll) i (cadar ll)
587: (cddar ll) conc-name #+PDP10 chars)
588: slot-alist)))))))
589:
590: (defun defstruct-parse-one-field (it number ppss rest conc-name #+PDP10 chars)
591: (let ((mname (if conc-name #+PDP10 (implode (append chars (exploden it)))
592: #+Multics (make_atom (catenate conc-name it))
593: #+Franz (concat conc-name it)
594: #+LispM (intern (string-append conc-name it))
595: it)))
596: (cons it (make-defstruct-slot-description
597: number number
598: ppss ppss
599: init-code (if (null rest) (make-empty) (car rest))
600: ref-macro-name mname))))
601:
602: (defun defstruct-define-ref-macros (new-slots description)
603: (let ((name (defstruct-description-name))
604: (returns nil))
605: (if (not (defstruct-description-callable-accessors))
606: (do ((l new-slots (cdr l))
607: (mname))
608: ((null l))
609: (setq mname (defstruct-slot-description-ref-macro-name (cdar l)))
610: (defstruct-put-macro mname 'defstruct-expand-ref-macro)
611: (defstruct-putprop mname (cons name (caar l)) 'defstruct-slot))
612: (let ((type-description
613: (get (defstruct-description-type)
614: 'defstruct-type-description)))
615: (let ((code (defstruct-type-description-ref-expander))
616: (n (defstruct-type-description-ref-no-args))
617: (but-first (defstruct-description-but-first))
618: (default-pointer (defstruct-description-default-pointer)))
619: (do ((args nil (cons (gensym) args))
620: (i n (1- i)))
621: ((< i 2)
622: ;;Last arg (if it exists) is name of structure,
623: ;; for documentation purposes.
624: (and (= i 1)
625: (setq args (cons name args)))
626: (let ((body (cons (if but-first
627: `(,but-first ,(car args))
628: (car args))
629: (cdr args))))
630: (and default-pointer
631: (setq args `((,(car args) ,default-pointer)
632: &optional . ,(cdr args))))
633: (setq args (reverse args))
634: (setq body (reverse body))
635: (do ((l new-slots (cdr l))
636: (mname))
637: ((null l))
638: (setq mname (defstruct-slot-description-ref-macro-name
639: (cdar l)))
640: #M ;;This must come BEFORE the defun. THINK!
641: (defstruct-put-macro mname 'defstruct-expand-ref-macro)
642: (let ((ref (lexpr-funcall
643: code
644: (defstruct-slot-description-number (cdar l))
645: description
646: body))
647: (ppss (defstruct-slot-description-ppss (cdar l))))
648: (push `(#+(or Franz Maclisp)
649: defun #Q defsubst ,mname ,args
650: ,(if (null ppss) ref `(ldb ,ppss ,ref)))
651: returns))
652: (defstruct-putprop mname
653: (cons name (caar l))
654: 'defstruct-slot))))))))
655: returns))
656:
657: (defun defstruct-expand-size-macro (x)
658: (let ((description (get-defstruct-description (get (car x) 'defstruct-name))))
659: (let ((type-description (get (defstruct-description-type)
660: 'defstruct-type-description)))
661: (funcall (defstruct-description-displace)
662: x
663: (+ (defstruct-description-size)
664: (defstruct-type-description-overhead))))))
665:
666: (defun defstruct-expand-ref-macro (x)
667: (let* ((pair (get (car x) 'defstruct-slot))
668: (description (get-defstruct-description (car pair)))
669: (type-description
670: (get (defstruct-description-type) 'defstruct-type-description))
671: (code (defstruct-type-description-ref-expander))
672: (n (defstruct-type-description-ref-no-args))
673: (args (reverse (cdr x)))
674: (nargs (length args))
675: (default (defstruct-description-default-pointer))
676: (but-first (defstruct-description-but-first)))
677: (cond ((= n nargs)
678: (and but-first
679: (rplaca args `(,but-first ,(car args)))))
680: ((and (= n (1+ nargs)) default)
681: (setq args (cons (if but-first
682: `(,but-first ,default)
683: default)
684: args)))
685: (t
686: (defstruct-error
687: "Wrong number of args to an accessor macro" x)))
688: (let* ((slot-description
689: (cdr (or (assq (cdr pair)
690: (defstruct-description-slot-alist))
691: (defstruct-error
692: "This slot no longer exists in this structure"
693: (cdr pair) 'in (car pair)))))
694: (ref (lexpr-funcall
695: code
696: (defstruct-slot-description-number)
697: description
698: (nreverse args)))
699: (ppss (defstruct-slot-description-ppss)))
700: (funcall (defstruct-description-displace)
701: x
702: (if (null ppss)
703: ref
704: `(ldb ,ppss ,ref))))))
705:
706: (defun defstruct-parse-setq-style-slots (l slots others x)
707: (do ((l l (cddr l))
708: (kludge (cons nil nil)))
709: ((null l) kludge)
710: (or (and (cdr l)
711: (symbolp (car l)))
712: (defstruct-error
713: "Bad argument list to constructor or alterant macro" x))
714: (defstruct-make-init-dsc kludge (car l) (cadr l) slots others x)))
715:
716: (defun defstruct-make-init-dsc (kludge name code slots others x)
717: (let ((p (assq name slots)))
718: (if (null p)
719: (if (memq name others)
720: (push (cons name code) (cdr kludge))
721: (defstruct-error
722: "Unknown slot to constructor or alterant macro" x))
723: (let* ((slot-description (cdr p))
724: (number (defstruct-slot-description-number))
725: (ppss (defstruct-slot-description-ppss))
726: (dsc (assoc number (car kludge))))
727: (cond ((null dsc)
728: (setq dsc (list* number nil (make-empty) 0 0 nil))
729: (push dsc (car kludge))))
730: (cond ((null ppss)
731: (setf (car (cddr dsc)) code)
732: (setf (cadr dsc) t))
733: (t (cond #-Franz
734: ((and (numberp ppss) (numberp code))
735: (setf (ldb ppss (cadr (cddr dsc))) -1)
736: (setf (ldb ppss (caddr (cddr dsc))) code))
737: (t
738: (push (cons ppss code) (cdddr (cddr dsc)))))
739: (or (eq t (cadr dsc))
740: (push name (cadr dsc)))))))))
741:
742: (defun defstruct-code-from-dsc (dsc)
743: (let ((code (car (cddr dsc)))
744: (mask (cadr (cddr dsc)))
745: (bits (caddr (cddr dsc))))
746: (if (emptyp code)
747: (setq code bits)
748: (or (zerop mask)
749: (setq code (if (numberp code)
750: (boole 7 bits (boole 2 mask code))
751: (if (zerop (logand mask
752: (1+ (logior mask (1- mask)))))
753: (let ((ss (haulong (boole 2 mask (1- mask)))))
754: `(dpb ,(lsh bits (- ss))
755: ,(logior (lsh ss 6)
756: (logand #o77
757: (- (haulong mask) ss)))
758: ,code))
759: `(boole 7 ,bits (boole 2 ,mask ,code)))))))
760: (do l (cdddr (cddr dsc)) (cdr l) (null l)
761: (setq code `(dpb ,(cdar l) ,(caar l) ,code)))
762: code))
763:
764: (defun defstruct-expand-cons-macro (x)
765: (let* ((description (get-defstruct-description (get (car x) 'defstruct-name)))
766: (type-description (get (defstruct-description-type)
767: 'defstruct-type-description))
768: (slot-alist (defstruct-description-slot-alist))
769: (cons-keywords (defstruct-type-description-cons-keywords))
770: inits kludge
771: (constructor-description
772: (cdr (or (assq (car x) (defstruct-description-constructors))
773: (defstruct-error
774: "This constructor is no longer defined for this structure"
775: (car x) 'in (defstruct-description-name)))))
776: (aux nil)
777: (aux-init nil))
778: (if (null constructor-description)
779: (setq kludge (defstruct-parse-setq-style-slots (cdr x)
780: slot-alist
781: cons-keywords
782: x))
783: (prog (args l)
784: (setq kludge (cons nil nil))
785: (setq args (cdr x))
786: (setq l (car constructor-description))
787: R (cond ((null l)
788: (if (null args)
789: (return nil)
790: (go barf-tma)))
791: ((atom l) (go barf))
792: ((eq (car l) '&optional) (go O))
793: ((eq (car l) '&rest) (go S))
794: ((eq (car l) '&aux) (go A))
795: ((null args) (go barf-tfa)))
796: (defstruct-make-init-dsc kludge
797: (pop l)
798: (pop args)
799: slot-alist
800: cons-keywords
801: x)
802: (go R)
803: O (and (null args) (go OD))
804: (pop l)
805: (cond ((null l) (go barf-tma))
806: ((atom l) (go barf))
807: ((eq (car l) '&optional) (go barf))
808: ((eq (car l) '&rest) (go S))
809: ((eq (car l) '&aux) (go barf-tma)))
810: (defstruct-make-init-dsc kludge
811: (if (atom (car l)) (car l) (caar l))
812: (pop args)
813: slot-alist
814: cons-keywords
815: x)
816: (go O)
817: OD (pop l)
818: (cond ((null l) (return nil))
819: ((atom l) (go barf))
820: ((eq (car l) '&optional) (go barf))
821: ((eq (car l) '&rest) (go S))
822: ((eq (car l) '&aux) (go A)))
823: (or (atom (car l))
824: (defstruct-make-init-dsc kludge
825: (caar l)
826: (cadar l)
827: slot-alist
828: cons-keywords
829: x))
830: (go OD)
831: S (and (atom (cdr l)) (go barf))
832: (defstruct-make-init-dsc kludge
833: (cadr l)
834: `(list . ,args)
835: slot-alist
836: cons-keywords
837: x)
838: (setq l (cddr l))
839: (and (null l) (return nil))
840: (and (atom l) (go barf))
841: (or (eq (car l) '&aux) (go barf))
842: A (pop l)
843: (cond ((null l) (return nil))
844: ((atom l) (go barf))
845: ((atom (car l))
846: (push (car l) aux)
847: (push (make-empty) aux-init))
848: (t
849: (push (caar l) aux)
850: (push (cadar l) aux-init)))
851: (go A)
852: barf (defstruct-error
853: "Bad format for defstruct constructor arglist"
854: `(,(car x) . ,(car constructor-description)))
855: barf-tfa (defstruct-error "Too few arguments to constructor macro" x)
856: barf-tma (defstruct-error "Too many arguments to constructor macro" x)))
857: (do l slot-alist (cdr l) (null l)
858: (let* ((name (caar l))
859: (slot-description (cdar l))
860: (code (do ((aux aux (cdr aux))
861: (aux-init aux-init (cdr aux-init)))
862: ((null aux) (defstruct-slot-description-init-code))
863: (and (eq name (car aux)) (return (car aux-init)))))
864: (ppss (defstruct-slot-description-ppss)))
865: (or (and (emptyp code) (null ppss))
866: (let* ((number (defstruct-slot-description-number))
867: (dsc (assoc number (car kludge))))
868: (cond ((null dsc)
869: (setq dsc (list* number nil (make-empty) 0 0 nil))
870: (push dsc (car kludge))))
871: (cond ((emptyp code))
872: ((eq t (cadr dsc)))
873: ((null ppss)
874: (and (emptyp (car (cddr dsc)))
875: (setf (car (cddr dsc)) code)))
876: ((memq name (cadr dsc)))
877: #-Franz
878: ((and (numberp ppss) (numberp code))
879: (setf (ldb ppss (cadr (cddr dsc))) -1)
880: (setf (ldb ppss (caddr (cddr dsc))) code))
881: (t
882: (push (cons ppss code) (cdddr (cddr dsc)))))))))
883: (selectq (defstruct-type-description-cons-flavor)
884: (:list
885: (do ((l nil (cons nil l))
886: (i (defstruct-description-size) (1- i)))
887: ((= i 0) (setq inits l)))
888: (do l (car kludge) (cdr l) (null l)
889: (setf (nth (caar l) inits)
890: (defstruct-code-from-dsc (car l)))))
891: (:alist
892: (setq inits (car kludge))
893: (do l inits (cdr l) (null l)
894: (rplacd (car l) (defstruct-code-from-dsc (car l)))))
895: (otherwise
896: (defstruct-error
897: "Unknown flavor to constructor macro expander"
898: (defstruct-description-type))))
899: (funcall (defstruct-description-displace)
900: x (funcall (defstruct-type-description-cons-expander)
901: inits description (cdr kludge)))))
902:
903: (defun defstruct-expand-alter-macro (x)
904: (let* ((description (get-defstruct-description (get (car x) 'defstruct-name)))
905: (type-description (get (defstruct-description-type)
906: 'defstruct-type-description))
907: (ref-code (defstruct-type-description-ref-expander)))
908: (or (= 1 (defstruct-type-description-ref-no-args))
909: (defstruct-error
910: "Alterant macros cannot handle this defstruct type"
911: (defstruct-description-type)))
912: (do ((l (car (defstruct-parse-setq-style-slots
913: (cddr x)
914: (defstruct-description-slot-alist)
915: nil
916: x))
917: (cdr l))
918: (but-first (defstruct-description-but-first))
919: (body nil)
920: (var (gensym))
921: (vars nil)
922: (vals nil))
923: ((null l)
924: (funcall (defstruct-description-displace)
925: x
926: `((lambda (,var)
927: . ,(if (null vars)
928: body
929: `(((lambda ,vars . ,body) . ,vals))))
930: ,(if but-first
931: `(,but-first ,(cadr x))
932: (cadr x)))))
933: (let ((ref (funcall ref-code (caar l) description var)))
934: (and (emptyp (car (cddr (car l))))
935: (setf (car (cddr (car l))) ref))
936: (let ((code (defstruct-code-from-dsc (car l))))
937: (if (null (cdr l))
938: (push `(setf ,ref ,code) body)
939: (let ((sym (gensym)))
940: (push `(setf ,ref ,sym) body)
941: (push sym vars)
942: (push code vals))))))))
943:
944: (defmacro defstruct-define-type (type . options)
945: (do ((options options (cdr options))
946: (op) (args)
947: (type-description (make-defstruct-type-description))
948: (cons-expander nil)
949: (ref-expander nil)
950: (defstruct-expander nil))
951: ((null options)
952: (or cons-expander
953: (defstruct-error "No cons option in defstruct-define-type" type))
954: (or ref-expander
955: (defstruct-error "No ref option in defstruct-define-type" type))
956: `(progn 'compile
957: ,cons-expander
958: ,ref-expander
959: ,@(and defstruct-expander (list defstruct-expander))
960: (defprop ,type ,type-description defstruct-type-description)))
961: (cond ((atom (setq op (car options)))
962: (setq args nil))
963: (t
964: (setq args (cdr op))
965: (setq op (car op))))
966: #Q AGAIN
967: (selectq op
968: (:cons
969: (or (> (length args) 2)
970: (defstruct-error
971: "Bad cons option in defstruct-define-type"
972: (car options) 'in type))
973: (let ((n (length (car args)))
974: (name (append-symbols type '-defstruct-cons)))
975: (or (= n 3)
976: (defstruct-error
977: "Bad cons option in defstruct-define-type"
978: (car options) 'in type))
979: (setf (defstruct-type-description-cons-flavor)
980: #-LispM (cadr args)
981: #+LispM (intern (string (cadr args)) si:pkg-user-package))
982: (setf (defstruct-type-description-cons-expander) name)
983: (setq cons-expander `(defun ,name ,(car args)
984: . ,(cddr args)))))
985: (:ref
986: (or (> (length args) 1)
987: (defstruct-error
988: "Bad ref option in defstruct-define-type"
989: (car options) 'in type))
990: (let ((n (length (car args)))
991: (name (append-symbols type '-defstruct-ref)))
992: (or (> n 2)
993: (defstruct-error
994: "Bad ref option in defstruct-define-type"
995: (car options) 'in type))
996: (setf (defstruct-type-description-ref-no-args) (- n 2))
997: (setf (defstruct-type-description-ref-expander) name)
998: (setq ref-expander `(defun ,name ,(car args)
999: . ,(cdr args)))))
1000: (:overhead
1001: (setf (defstruct-type-description-overhead)
1002: (if (null args)
1003: (defstruct-error
1004: "Bad option to defstruct-define-type"
1005: (car options) 'in type)
1006: (car args))))
1007: (:named
1008: (setf (defstruct-type-description-named-type)
1009: (if (null args)
1010: type
1011: (car args))))
1012: (:keywords
1013: (setf (defstruct-type-description-cons-keywords) args))
1014: (:defstruct
1015: (or (> (length args) 1)
1016: (defstruct-error
1017: "Bad defstruct option in defstruct-define-type"
1018: (car options) 'in type))
1019: (let ((name (append-symbols type '-defstruct-expand)))
1020: (setf (defstruct-type-description-defstruct-expander) name)
1021: (setq defstruct-expander `(defun ,name . ,args))))
1022: (otherwise
1023: #Q (multiple-value-bind (new foundp)
1024: (intern-soft op si:pkg-user-package)
1025: (or (not foundp)
1026: (eq op new)
1027: (progn (setq op new) (go AGAIN))))
1028: (defstruct-error
1029: "Unknown option to defstruct-define-type"
1030: (car options) 'in type)))))
1031:
1032: #Q
1033: (defprop :make-array t :defstruct-option)
1034:
1035: (defstruct-define-type :array
1036: #Q (:named :named-array)
1037: #Q (:keywords :make-array)
1038: (:cons
1039: (arg description etc) :alist
1040: #M etc ;ignored in MacLisp
1041: #F etc ;ignored in MacLisp
1042: #Q (lispm-array-for-defstruct arg #'(lambda (v a i) `(aset ,v ,a ,i))
1043: description etc nil nil nil 1)
1044: #M (maclisp-array-for-defstruct arg description 't)
1045: #F (maclisp-array-for-defstruct arg description 't))
1046: (:ref
1047: (n description arg)
1048: description ;ignored
1049: #M `(arraycall t ,arg ,n)
1050: #F `(arraycall t ,arg ,n)
1051: #Q `(aref ,arg ,n)))
1052:
1053: #Q
1054: (defstruct-define-type :named-array
1055: (:keywords :make-array)
1056: :named (:overhead 1)
1057: (:cons
1058: (arg description etc) :alist
1059: (lispm-array-for-defstruct arg #'(lambda (v a i) `(aset ,v ,a ,(1+ i)))
1060: description etc nil t nil 1))
1061: (:ref (n description arg)
1062: description ;ignored
1063: `(aref ,arg ,(1+ n))))
1064:
1065: (defstruct-define-type :fixnum-array
1066: #Q (:keywords :make-array)
1067: (:cons
1068: (arg description etc) :alist
1069: #M etc ;ignored in MacLisp
1070: #F etc ;ignored in MacLisp
1071: #Q (lispm-array-for-defstruct arg #'(lambda (v a i) `(aset ,v ,a ,i))
1072: description etc 'art-32b nil nil 1)
1073: #M (maclisp-array-for-defstruct arg description 'fixnum)
1074: #F (maclisp-array-for-defstruct arg description 'fixnum))
1075: (:ref
1076: (n description arg)
1077: description ;ignored
1078: #M `(arraycall fixnum ,arg ,n)
1079: #F `(arraycall fixnum ,arg ,n)
1080: #Q `(aref ,arg ,n)))
1081:
1082: (defstruct-define-type :flonum-array
1083: #Q (:keywords :make-array)
1084: (:cons
1085: (arg description etc) :alist
1086: #M etc ;ignored in MacLisp
1087: #F etc ;ignored in MacLisp
1088: #Q (lispm-array-for-defstruct arg #'(lambda (v a i) `(aset ,v ,a ,i))
1089: description etc 'art-float nil nil 1)
1090: #M (maclisp-array-for-defstruct arg description 'flonum)
1091: #F (maclisp-array-for-defstruct arg description 'flonum))
1092: (:ref
1093: (n description arg)
1094: description ;ignored
1095: #M `(arraycall flonum ,arg ,n)
1096: #F `(arraycall flonum ,arg ,n)
1097: #Q `(aref ,arg ,n)))
1098:
1099: #M
1100: (defstruct-define-type :un-gc-array
1101: (:cons
1102: (arg description etc) :alist
1103: etc ;ignored
1104: (maclisp-array-for-defstruct arg description 'nil))
1105: (:ref
1106: (n description arg)
1107: description ;ignored
1108: `(arraycall nil ,arg ,n)))
1109:
1110: #Q
1111: (defstruct-define-type :array-leader
1112: (:named :named-array-leader)
1113: (:keywords :make-array)
1114: (:cons
1115: (arg description etc) :alist
1116: (lispm-array-for-defstruct arg #'(lambda (v a i)
1117: `(store-array-leader ,v ,a ,i))
1118: description etc nil nil t 1))
1119: (:ref
1120: (n description arg)
1121: description ;ignored
1122: `(array-leader ,arg ,n)))
1123:
1124: #Q
1125: (defstruct-define-type :named-array-leader
1126: (:keywords :make-array)
1127: :named (:overhead 1)
1128: (:cons
1129: (arg description etc) :alist
1130: (lispm-array-for-defstruct
1131: arg
1132: #'(lambda (v a i)
1133: `(store-array-leader ,v ,a ,(if (zerop i)
1134: 0
1135: (1+ i))))
1136: description etc nil t t 1))
1137: (:ref
1138: (n description arg)
1139: description ;ignored
1140: (if (zerop n)
1141: `(array-leader ,arg 0)
1142: `(array-leader ,arg ,(1+ n)))))
1143:
1144: #Q
1145: (defprop :times t :defstruct-option)
1146:
1147: #Q
1148: (defstruct-define-type :grouped-array
1149: (:keywords :make-array :times)
1150: (:cons
1151: (arg description etc) :alist
1152: (lispm-array-for-defstruct
1153: arg
1154: #'(lambda (v a i) `(aset ,v ,a ,i))
1155: description etc nil nil nil
1156: (or (cdr (or (assq ':times etc)
1157: (assq ':times (defstruct-description-property-alist))))
1158: 1)))
1159: (:ref
1160: (n description index arg)
1161: description ;ignored
1162: (cond ((numberp index)
1163: `(aref ,arg ,(+ n index)))
1164: ((zerop n)
1165: `(aref ,arg ,index))
1166: (t `(aref ,arg (+ ,n ,index))))))
1167:
1168: #Q
1169: (defun lispm-array-for-defstruct (arg cons-init description etc type named-p leader-p times)
1170: (let ((p (cons nil nil))
1171: (no-op 'nil))
1172: (defstruct-grok-make-array-args
1173: (cdr (assq ':make-array (defstruct-description-property-alist)))
1174: p)
1175: (defstruct-grok-make-array-args
1176: (cdr (assq ':make-array etc))
1177: p)
1178: (and type (putprop p type ':type))
1179: (and named-p (putprop p `',(defstruct-description-name) ':named-structure-symbol))
1180: (putprop p
1181: (let ((size (if named-p
1182: (1+ (defstruct-description-size))
1183: (defstruct-description-size))))
1184: (if (numberp times)
1185: (* size times)
1186: `(* ,size ,times)))
1187: (if leader-p ':leader-length ':dimensions))
1188: (or leader-p
1189: (let ((type (get p ':type)))
1190: (or (atom type)
1191: (not (eq (car type) 'quote))
1192: (setq type (cadr type)))
1193: (caseq type
1194: ((nil art-q art-q-list))
1195: ((art-32b art-16b art-8b art-4b art-2b art-1b art-string) (setq no-op '0))
1196: ((art-float) (setq no-op '0.0))
1197: (t (setq no-op (make-empty))))))
1198: (do ((creator
1199: (let ((dims (remprop p ':dimensions)))
1200: (do l (cdr p) (cddr l) (null l)
1201: (rplaca l `',(car l)))
1202: `(make-array ,(if (null dims) 0 (car dims)) ,@(cdr p))))
1203: (var (gensym))
1204: (set-ups nil (if (equal (cdar l) no-op)
1205: set-ups
1206: (cons (funcall cons-init (cdar l) var (caar l))
1207: set-ups)))
1208: (l arg (cdr l)))
1209: ((null l)
1210: (if set-ups
1211: `((lambda (,var)
1212: ,@(nreverse set-ups)
1213: ,var)
1214: ,creator)
1215: creator)))))
1216:
1217: #Q
1218: (defun defstruct-grok-make-array-args (args p)
1219: (let ((nargs (length args)))
1220: (if (and (not (> nargs 7))
1221: (or (oddp nargs)
1222: (do ((l args (cddr l)))
1223: ((null l) nil)
1224: (or (memq (car l) '(:area :type :displaced-to :leader-list
1225: :leader-length :displaced-index-offset
1226: :named-structure-symbol :dimensions
1227: :length))
1228: (return t)))))
1229: (do ((l args (cdr l))
1230: (keylist '(:area :type :dimensions :displaced-to :old-leader-length-or-list
1231: :displaced-index-offset :named-structure-symbol)
1232: (cdr keylist)))
1233: ((null l)
1234: (and (boundp 'compiler:compiler-warnings-context)
1235: (boundp 'compiler:last-error-function)
1236: (not (null compiler:compiler-warnings-context))
1237: (compiler:barf args '|-- old style :MAKE-ARRAY constructor keyword argument|
1238: 'compiler:warn))
1239: p)
1240: (putprop p (car l) (car keylist)))
1241: (do ((l args (cddr l)))
1242: ((null l) p)
1243: (if (or (null (cdr l))
1244: (not (memq (car l) '(:area :type :displaced-to :leader-list
1245: :leader-length :displaced-index-offset
1246: :named-structure-symbol :dimensions
1247: :length))))
1248: (defstruct-error
1249: "defstruct can't grok these make-array arguments"
1250: args))
1251: (putprop p
1252: (cadr l)
1253: (if (eq (car l) ':length)
1254: ':dimensions
1255: (car l)))))))
1256:
1257: #+(or Franz Maclisp)
1258: (defun maclisp-array-for-defstruct (arg description type)
1259: (do ((creator `(array nil ,type ,(defstruct-description-size)))
1260: (var (gensym))
1261: (no-op (caseq type
1262: (fixnum 0)
1263: (flonum 0.0)
1264: ((t nil) nil)))
1265: (set-ups nil (if (equal (cdar l) no-op)
1266: set-ups
1267: (cons `(store (arraycall ,type ,var ,(caar l))
1268: ,(cdar l))
1269: set-ups)))
1270: (l arg (cdr l)))
1271: ((null l)
1272: (if set-ups
1273: `((lambda (,var)
1274: ,@(nreverse set-ups)
1275: ,var)
1276: ,creator)
1277: creator))))
1278:
1279: #+PDP10
1280: (defprop :sfa-function t :defstruct-option)
1281:
1282: #+PDP10
1283: (defprop :sfa-name t :defstruct-option)
1284:
1285: #+PDP10
1286: (defstruct-define-type :sfa
1287: (:keywords :sfa-function :sfa-name)
1288: (:cons
1289: (arg description etc) :alist
1290: (do ((creator `(sfa-create ,(or (cdr (or (assq ':sfa-function etc)
1291: (assq ':sfa-function (defstruct-description-property-alist))))
1292: `',(defstruct-description-name))
1293: ,(defstruct-description-size)
1294: ,(or (cdr (or (assq ':sfa-name etc)
1295: (assq ':sfa-name (defstruct-description-property-alist))))
1296: `',(defstruct-description-name))))
1297: (l arg (cdr l))
1298: (var (gensym))
1299: (set-ups nil (if (null (cdar l))
1300: set-ups
1301: (cons `(sfa-store ,var ,(caar l)
1302: ,(cdar l))
1303: set-ups))))
1304: ((null l)
1305: (if set-ups
1306: `((lambda (,var)
1307: ,@(nreverse set-ups)
1308: ,var)
1309: ,creator)
1310: creator))))
1311: (:ref
1312: (n description arg)
1313: description ;ignored
1314: `(sfa-get ,arg ,n)))
1315:
1316: #+(or Franz PDP10)
1317: (defstruct-define-type :hunk
1318: (:named :named-hunk)
1319: (:cons
1320: (arg description etc) :list
1321: description ;ignored
1322: etc ;ignored
1323: (if arg
1324: #+PDP-10 `(hunk . ,(nconc (cdr arg) (ncons (car arg))))
1325: #+Franz `(hunk . ,arg)
1326: (defstruct-error "No slots in hunk type defstruct")))
1327: (:ref
1328: (n description arg)
1329: description ;ignored
1330: `(cxr ,n ,arg)))
1331:
1332: #+(or Franz PDP10)
1333: (defstruct-define-type :named-hunk
1334: :named (:overhead 1)
1335: (:cons
1336: (arg description etc) :list
1337: etc ;ignored
1338: (if arg
1339: #+PDP-10 `(hunk ',(defstruct-description-name)
1340: . ,(nconc (cdr arg) (ncons (car arg))))
1341: #+Franz `(hunk ',(defstruct-description-name)
1342: . ,arg)
1343: `(hunk ',(defstruct-description-name) nil)))
1344: (:ref
1345: (n description arg)
1346: description ;ignored
1347: (cond #+PDP-10 ((= n 0) `(cxr 0 ,arg))
1348: (t `(cxr ,(1+ n) ,arg)))))
1349:
1350: #+(or Franz PDP10 NIL )
1351: (defstruct-define-type :vector
1352: #+Franz
1353: (:named :named-vector)
1354: (:cons
1355: (arg description etc) :list
1356: description ;ignored
1357: etc ;ignored
1358: `(vector ,@arg))
1359: (:ref
1360: (n description arg)
1361: description ;ignored
1362: `(vref ,arg ,n)))
1363:
1364: #+Franz
1365: (defstruct-define-type :named-vector
1366: :named
1367: (:cons
1368: (arg description etc) :list
1369: description ;ignored
1370: etc ;ignored
1371: `(let ((nv (vector ,@arg)))
1372: (vsetprop nv ',(defstruct-description-name))
1373: nv))
1374: (:ref
1375: (n description arg)
1376: description ;ignored
1377: `(vref ,arg ,n)))
1378:
1379: (defstruct-define-type :list
1380: (:named :named-list)
1381: (:cons
1382: (arg description etc) :list
1383: description ;ignored
1384: etc ;ignored
1385: `(list . ,arg))
1386: (:ref
1387: (n description arg)
1388: description ;ignored
1389: #+Multics `(,(let ((i (\ n 4)))
1390: (cond ((= i 0) 'car)
1391: ((= i 1) 'cadr)
1392: ((= i 2) 'caddr)
1393: (t 'cadddr)))
1394: ,(do ((a arg `(cddddr ,a))
1395: (i (// n 4) (1- i)))
1396: ((= i 0) a)))
1397: #-Multics `(nth ,n ,arg)))
1398:
1399: (defstruct-define-type :named-list
1400: :named (:overhead 1)
1401: (:cons
1402: (arg description etc) :list
1403: etc ;ignored
1404: `(list ',(defstruct-description-name) . ,arg))
1405: (:ref
1406: (n description arg)
1407: description ;ignored
1408: #+Multics `(,(let ((i (\ (1+ n) 4)))
1409: (cond ((= i 0) 'car)
1410: ((= i 1) 'cadr)
1411: ((= i 2) 'caddr)
1412: (t 'cadddr)))
1413: ,(do ((a arg `(cddddr ,a))
1414: (i (// (1+ n) 4) (1- i)))
1415: ((= i 0) a)))
1416: #-Multics `(nth ,(1+ n) ,arg)))
1417:
1418: (defstruct-define-type :list*
1419: (:cons
1420: (arg description etc) :list
1421: description ;ignored
1422: etc ;ignored
1423: `(list* . ,arg))
1424: (:ref
1425: (n description arg)
1426: (let ((size (1- (defstruct-description-size))))
1427: #+Multics (do ((a arg `(cddddr ,a))
1428: (i (// n 4) (1- i)))
1429: ((= i 0)
1430: (let* ((i (\ n 4))
1431: (a (cond ((= i 0) a)
1432: ((= i 1) `(cdr ,a))
1433: ((= i 2) `(cddr ,a))
1434: (t `(cdddr ,a)))))
1435: (if (< n size) `(car ,a) a))))
1436: #-Multics (if (< n size)
1437: `(nth ,n ,arg)
1438: `(nthcdr ,n ,arg))))
1439: (:defstruct (description)
1440: (and (defstruct-description-include)
1441: (defstruct-error
1442: "Structure of type list* cannot include another"
1443: (defstruct-description-name)))
1444: nil))
1445:
1446: (defstruct-define-type :tree
1447: (:cons
1448: (arg description etc) :list
1449: etc ;ignored
1450: (if (null arg) (defstruct-error
1451: "defstruct cannot make an empty tree"
1452: (defstruct-description-name)))
1453: (make-tree-for-defstruct arg (defstruct-description-size)))
1454: (:ref
1455: (n description arg)
1456: (do ((size (defstruct-description-size))
1457: (a arg)
1458: (tem))
1459: (())
1460: (cond ((= size 1) (return a))
1461: ((< n (setq tem (// size 2)))
1462: (setq a `(car ,a))
1463: (setq size tem))
1464: (t (setq a `(cdr ,a))
1465: (setq size (- size tem))
1466: (setq n (- n tem))))))
1467: (:defstruct (description)
1468: (and (defstruct-description-include)
1469: (defstruct-error
1470: "Structure of type tree cannot include another"
1471: (defstruct-description-name)))
1472: nil))
1473:
1474: (defun make-tree-for-defstruct (arg size)
1475: (cond ((= size 1) (car arg))
1476: ((= size 2) `(cons ,(car arg) ,(cadr arg)))
1477: (t (do ((a (cdr arg) (cdr a))
1478: (m (// size 2))
1479: (n (1- (// size 2)) (1- n)))
1480: ((zerop n)
1481: `(cons ,(make-tree-for-defstruct arg m)
1482: ,(make-tree-for-defstruct a (- size m))))))))
1483:
1484: (defstruct-define-type :fixnum
1485: (:cons
1486: (arg description etc) :list
1487: etc ;ignored
1488: (and (or (null arg)
1489: (not (null (cdr arg))))
1490: (defstruct-error
1491: "Structure of type fixnum must have exactly 1 slot to be constructable"
1492: (defstruct-description-name)))
1493: (car arg))
1494: (:ref
1495: (n description arg)
1496: n ;ignored
1497: description ;ignored
1498: arg))
1499:
1500: #+Multics
1501: (defprop :external-ptr t :defstruct-option)
1502:
1503: #+Multics
1504: (defstruct-define-type :external
1505: (:keywords :external-ptr)
1506: (:cons (arg description etc) :alist
1507: (let ((ptr (cdr (or (assq ':external-ptr etc)
1508: (assq ':external-ptr
1509: (defstruct-description-property-alist))
1510: (defstruct-error
1511: "No pointer given for external array"
1512: (defstruct-description-name))))))
1513: (do ((creator `(array nil external ,ptr ,(defstruct-description-size)))
1514: (var (gensym))
1515: (alist arg (cdr alist))
1516: (inits nil (cons `(store (arraycall fixnum ,var ,(caar alist))
1517: ,(cdar alist))
1518: inits)))
1519: ((null alist)
1520: (if (null inits)
1521: creator
1522: `((lambda (,var) ,.inits ,var)
1523: ,creator))))))
1524: (:ref (n description arg)
1525: description ;ignored
1526: `(arraycall fixnum ,arg ,n)))
1527:
1528: (defvar *defstruct-examine&deposit-arg*)
1529:
1530: (defun defstruct-examine (*defstruct-examine&deposit-arg*
1531: name slot-name)
1532: (eval (list (defstruct-slot-description-ref-macro-name
1533: (defstruct-examine&deposit-find-slot-description
1534: name slot-name))
1535: '*defstruct-examine&deposit-arg*)))
1536:
1537: (defvar *defstruct-examine&deposit-val*)
1538:
1539: (defun defstruct-deposit (*defstruct-examine&deposit-val*
1540: *defstruct-examine&deposit-arg*
1541: name slot-name)
1542: (eval (list 'setf
1543: (list (defstruct-slot-description-ref-macro-name
1544: (defstruct-examine&deposit-find-slot-description
1545: name slot-name))
1546: '*defstruct-examine&deposit-arg*)
1547: '*defstruct-examine&deposit-val*)))
1548:
1549: #Q
1550: (defun defstruct-get-locative (*defstruct-examine&deposit-arg*
1551: name slot-name)
1552: (let ((slot-description (defstruct-examine&deposit-find-slot-description
1553: name slot-name)))
1554: (or (null (defstruct-slot-description-ppss))
1555: (defstruct-error
1556: "You cannot get a locative to a byte field"
1557: slot-name 'in name))
1558: (eval (list 'locf
1559: (list (defstruct-slot-description-ref-macro-name)
1560: '*defstruct-examine&deposit-arg*)))))
1561:
1562: (defun defstruct-examine&deposit-find-slot-description (name slot-name)
1563: (let ((description (get-defstruct-description name)))
1564: (let ((slot-description
1565: (cdr (or (assq slot-name (defstruct-description-slot-alist))
1566: (defstruct-error
1567: "No such slot in this structure"
1568: slot-name 'in name))))
1569: (type-description
1570: (or (get (defstruct-description-type) 'defstruct-type-description)
1571: (defstruct-error
1572: "Undefined defstruct type"
1573: (defstruct-description-type)))))
1574: (or (= (defstruct-type-description-ref-no-args) 1)
1575: (defstruct-error
1576: "defstruct-examine and defstruct-deposit cannot handle structures of this type"
1577: (defstruct-description-type)))
1578: slot-description)))
1579:
1580: #+PDP10
1581: (defprop defstruct
1582: #.(and (status feature PDP10)
1583: (caddr (truename infile)))
1584: version)
1585:
1586: (sstatus feature defstruct)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.