forked from dbetz/xlisp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
objects.lsp
executable file
·132 lines (110 loc) · 3.77 KB
/
objects.lsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#| macro to send a message to the superclass |#
(define-macro (super selector &rest args)
`(%send-super %%class ,selector self ,@args))
(define-macro (apply-super selector &rest args)
`(apply %send-super %%class ,selector self ,@args))
#|
(define-class foo
(superclass bar)
(instance-variables a b)
(class-variables ((c 1)(d 2)))
|#
(define-macro (define-class class-name &body body)
(let ((super '())
(ivars '())
(cvars '()))
(let loop ((body body))
(if body
(let* ((form (car body))
(keyword (car form))
(args (cdr form)))
(cond ((or (eq? keyword 'superclass)
(eq? keyword 'super-class)
(eq? keyword 'super))
(set! super (append super args)))
((or (eq? keyword 'instance-variables)
(eq? keyword 'ivars))
(set! ivars (append ivars args)))
((or (eq? keyword 'class-variables)
(eq? keyword 'cvars))
(set! cvars (append cvars args)))
(else (error "unexpected define-class clause ~S" form)))
(loop (cdr body)))))
(let ((super-class (if super (car super) 'object)))
(list 'begin
(list 'let (list (list 'meta-class
(list 'class ''new
'()
'()
'class
''class)))
(list 'set! class-name (list 'meta-class ''new
(list 'quote ivars)
(list 'quasiquote
(destructure-cvars cvars))
super-class
(list 'quote class-name)))
(list 'meta-class ''%set-cvars! (list class-name ''%cvars))
class-name)))))
(define (destructure-cvars forms)
(let ((cvars '()))
(let loop ((forms forms))
(if forms
(let ((form (car forms)))
(if (pair? form)
(set! cvars (append cvars (list (list (car form)
(list 'unquote (cadr form))))))
(set! cvars (append cvars `(,form))))
(loop (cdr forms)))))
cvars))
#|
(define-method (foo 'do-something a b) ; foo is a class
(list self a b))
|#
(define-macro (define-method proto &body body)
(let ((class (car proto))
(selector (cadr proto))
(args (cddr proto))
(body (%expand-list (convert-internal-definitions body)))
(sel (gensym)))
`(let ((,sel ,selector))
(,class 'answer ,sel ',args ',body)
,sel)))
#|
(define-class-method (foo 'do-something a b) ; foo is a class
(list self a b))
|#
(define-macro (define-class-method proto &body body)
(let ((class (car proto))
(selector (cadr proto))
(args (cddr proto)))
`(define-method ((,class 'class) ,selector ,@args)
,@body)))
(define-method (class '%cvars) cvars)
(define-method (class '%set-cvars! vars) (set! cvars vars))
#| some useful class methods |#
(define-method (class 'name) name)
(define-method (class 'ivars) ivars)
#| a method to show the class variables of a class |#
(define-method (class 'superclass)
superclass)
(define-method (class 'show-cvars)
(when cvars
(let loop ((names (cdr (%vector-ref cvars 1)))
(i 3))
(if names
(begin (fresh-line)
(write (car names))
(display " = ")
(write (%vector-ref cvars i))
(loop (cdr names) (+ i 1))))))
self)
(define-method (class 'decompile sel)
(let ((binding (assoc sel messages)))
(if binding
(decompile (cdr binding)))))
(define-method (class 'print &optional (stream *standard-output*))
(let ((name (self 'name)))
(if name
(format stream "#<Class:~S #x~A>" name (%format-address class))
(super 'print stream))))