1 | ;;; defstruct.lisp |
---|
2 | ;;; |
---|
3 | ;;; Copyright (C) 2003 Peter Graves |
---|
4 | ;;; $Id: defstruct.lisp,v 1.20 2003-09-22 17:46:26 piso Exp $ |
---|
5 | ;;; |
---|
6 | ;;; This program is free software; you can redistribute it and/or |
---|
7 | ;;; modify it under the terms of the GNU General Public License |
---|
8 | ;;; as published by the Free Software Foundation; either version 2 |
---|
9 | ;;; of the License, or (at your option) any later version. |
---|
10 | ;;; |
---|
11 | ;;; This program is distributed in the hope that it will be useful, |
---|
12 | ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
14 | ;;; GNU General Public License for more details. |
---|
15 | ;;; |
---|
16 | ;;; You should have received a copy of the GNU General Public License |
---|
17 | ;;; along with this program; if not, write to the Free Software |
---|
18 | ;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
---|
19 | |
---|
20 | (in-package "SYSTEM") |
---|
21 | |
---|
22 | (defvar *ds-name*) |
---|
23 | (defvar *ds-conc-name*) |
---|
24 | (defvar *ds-constructor*) |
---|
25 | (defvar *ds-copier*) |
---|
26 | (defvar *ds-named*) |
---|
27 | (defvar *ds-predicate*) |
---|
28 | (defvar *ds-print-function*) |
---|
29 | |
---|
30 | (defun define-constructor (slots) |
---|
31 | (when *ds-constructor* |
---|
32 | (let* ((constructor (intern *ds-constructor*)) |
---|
33 | (slot-names (mapcar #'(lambda (x) (if (atom x) x (car x))) slots)) |
---|
34 | (inits (mapcar #'(lambda (x) (if (atom x) nil (cadr x))) slots)) |
---|
35 | (slot-descriptions (mapcar #'(lambda (x y) (list x y)) slot-names inits)) |
---|
36 | (keys (cons '&key slot-descriptions))) |
---|
37 | `((defun ,constructor ,keys |
---|
38 | (%make-structure ',*ds-name* (list ,@slot-names))))))) |
---|
39 | |
---|
40 | (defun define-predicate () |
---|
41 | (let ((pred (intern (concatenate 'string (symbol-name *ds-name*) "-P")))) |
---|
42 | `((defun ,pred (object) |
---|
43 | (typep object ',*ds-name*))))) |
---|
44 | |
---|
45 | (defmacro get-slot-accessor (slot) |
---|
46 | (case slot |
---|
47 | (0 #'%structure-ref-0) |
---|
48 | (1 #'%structure-ref-1) |
---|
49 | (2 #'%structure-ref-2) |
---|
50 | (t |
---|
51 | `(lambda (instance) (%structure-ref instance ,slot))))) |
---|
52 | |
---|
53 | (defmacro get-slot-mutator (slot) |
---|
54 | (case slot |
---|
55 | (0 #'%structure-set-0) |
---|
56 | (1 #'%structure-set-1) |
---|
57 | (2 #'%structure-set-2) |
---|
58 | (t |
---|
59 | `(lambda (instance value) (%structure-set instance ,slot value))))) |
---|
60 | |
---|
61 | (defun define-access-function (slot-name index) |
---|
62 | (let ((accessor |
---|
63 | (if *ds-conc-name* |
---|
64 | (intern (concatenate 'string (symbol-name *ds-conc-name*) (symbol-name slot-name))) |
---|
65 | slot-name)) |
---|
66 | (setf-expander (gensym))) |
---|
67 | `((setf (symbol-function ',accessor) (get-slot-accessor ,index)) |
---|
68 | (%put ',accessor *setf-expander* (get-slot-mutator ,index))))) |
---|
69 | |
---|
70 | (defun define-access-functions (slots) |
---|
71 | (let ((index 0) |
---|
72 | (result ())) |
---|
73 | (dolist (slot slots) |
---|
74 | (let ((slot-name (if (atom slot) slot (car slot)))) |
---|
75 | (setq result (append result (define-access-function slot-name index)))) |
---|
76 | (incf index)) |
---|
77 | result)) |
---|
78 | |
---|
79 | (defun define-copier () |
---|
80 | (let ((copier (intern (concatenate 'string "COPY-" (symbol-name *ds-name*))))) |
---|
81 | `((setf (fdefinition ',copier) #'copy-structure)))) |
---|
82 | |
---|
83 | (defun parse-1-option (option) |
---|
84 | (case (car option) |
---|
85 | (:conc-name |
---|
86 | (setf *ds-conc-name* (if (symbolp (cadr option)) |
---|
87 | (cadr option) |
---|
88 | (make-symbol (string (cadr option)))))) |
---|
89 | (:constructor |
---|
90 | (when (= (length (cdr option)) 1) |
---|
91 | (if (null (cadr option)) |
---|
92 | (setf *ds-constructor* nil) |
---|
93 | (setf *ds-constructor* (symbol-name (cadr option)))))))) |
---|
94 | |
---|
95 | (defun parse-name-and-options (name-and-options) |
---|
96 | (setf *ds-name* (car name-and-options)) |
---|
97 | (setf *ds-conc-name* (make-symbol (concatenate 'string (symbol-name *ds-name*) "-"))) |
---|
98 | (setf *ds-constructor* (concatenate 'string "MAKE-" (symbol-name *ds-name*))) |
---|
99 | (let ((options (cdr name-and-options))) |
---|
100 | (dolist (option options) |
---|
101 | (cond ((consp option) |
---|
102 | (parse-1-option option)) |
---|
103 | ((eq option :named) |
---|
104 | (setf *ds-named* t)) |
---|
105 | ((member option '(:constructor :copier :predicate :named |
---|
106 | :conc-name)) |
---|
107 | (parse-1-option (list option))) |
---|
108 | (t |
---|
109 | (error "unrecognized DEFSTRUCT option: ~S" option)))))) |
---|
110 | |
---|
111 | (defmacro defstruct (name-and-options &rest slots) |
---|
112 | (let ((*ds-name* nil) |
---|
113 | (*ds-conc-name* nil) |
---|
114 | (*ds-constructor* nil) |
---|
115 | (*ds-copier* nil) |
---|
116 | (*ds-predicate* nil) |
---|
117 | (*ds-print-function* nil)) |
---|
118 | (parse-name-and-options (if (atom name-and-options) |
---|
119 | (list name-and-options) |
---|
120 | name-and-options)) |
---|
121 | `(progn |
---|
122 | (make-structure-class ',*ds-name*) |
---|
123 | ,@(define-constructor slots) |
---|
124 | ,@(define-predicate) |
---|
125 | ,@(define-access-functions slots) |
---|
126 | ,@(define-copier) |
---|
127 | ',*ds-name*))) |
---|
128 | |
---|
129 | (provide 'defstruct) |
---|