[gforth] / gforth / objects.fs  

gforth: gforth/objects.fs


1 : anton 1.1 \ yet another Forth objects extension
2 :    
3 :     \ written by Anton Ertl 1996
4 :     \ public domain
5 :    
6 :     \ This is in ANS Forth (with an environmental dependence on case
7 :     \ insensitivity; convert everything to upper case for state sensitive
8 :     \ systems). It needs some non-core words (in particular, it uses the
9 :     \ memory allocation wordset), but I have not made a complete list.
10 :    
11 :     \ Manual:
12 :    
13 :     \ A class is defined like this:
14 :    
15 :     \ <parent> class
16 :     \ ... field <name>
17 :     \ ...
18 :    
19 :     \ ... inst-var <name>
20 :     \ ...
21 :    
22 :     \ selector <name>
23 :    
24 :     \ :noname ( ... object -- ... )
25 :     \ ... ;
26 :     \ method <name> \ new method
27 :     \ ...
28 :    
29 :     \ :noname ( ... object -- ... )
30 :     \ ... ;
31 :     \ overrides <name> \ existing method
32 :     \ ...
33 :    
34 :     \ end-class <name>
35 :    
36 :     \ you can write fields, inst-vars, selectors, methods and overrides in
37 :     \ any order.
38 :    
39 :     \ A call of a method looks like this:
40 :    
41 :     \ ... <object> <method>
42 :    
43 :     \ (<object> just needs to reside on the stack, there's no need to name it).
44 :    
45 :     \ Instead of defining a method with ':noname ... ;', you can define it
46 :     \ also with 'm: ... ;m'. The difference is that with ':noname' the
47 :     \ "self" object is on the top of stack; with 'm:' you can get it with
48 :     \ 'this'. You should use 'this' only in an 'm:' method even though the
49 :     \ sample implementation does not enforce this.
50 :    
51 :     \ The difference between a field and and inst-var is that the field
52 :     \ refers to an object at the top of data stack (i.e. a field has the
53 :     \ stack effect (object -- addr), whereas the inst-var refers to this
54 :     \ (i.e., it has the stack effect ( -- addr )); obviously, an inst-var
55 :     \ can only be used in an 'm:' method.
56 :    
57 :     \ 'method' defines a new method selector and binds a method to it.
58 :    
59 :     \ 'selector' defines a new method selector without binding a method to
60 :     \ it (you can use this to define abstract classes)
61 :    
62 :     \ 'overrides' binds a different method (than the parent class) to an
63 :     \ existing method selector.
64 :    
65 :     \ If you want to perform early binding, you can do it like this:
66 :    
67 :     \ ... <object> [bind] <class> <method> \ compilation
68 :     \ ... <object> bind <class> <method> \ interpretation
69 :    
70 :     \ You can get at the method from the method selector and the class like
71 :     \ this:
72 :    
73 :     \ bind' <class> <method>
74 :     \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
75 :    
76 :     \ needs struct.fs
77 :    
78 :     \ helper words
79 :    
80 :     : -rot ( a b c -- c a b )
81 :     rot rot ;
82 :    
83 :     : perform ( ... addr -- ... )
84 :     @ execute ;
85 :    
86 :     : save-mem ( addr1 u -- addr2 u ) \ gforth
87 :     \ copy a memory block into a newly allocated region in the heap
88 :     swap >r
89 :     dup allocate throw
90 :     swap 2dup r> -rot move ;
91 :    
92 :     : extend-mem ( addr1 u1 u -- addr addr2 u2 )
93 :     \ extend memory block allocated from the heap by u aus
94 :     \ the (possibly reallocated piece is addr2 u2, the extension is at addr )
95 :     over >r + dup >r resize throw
96 :     r> over r> + -rot ;
97 :    
98 :     : 2, ( w1 w2 -- ) \ gforth
99 :     here 2 cells allot 2! ;
100 :    
101 :     : const-field ( size1 align1 -- size2 align2 )
102 :     1 cells: field
103 :     does> ( addr -- w )
104 :     @ + @ ;
105 :    
106 :     struct
107 :     1 cells: field object-map
108 :     end-struct object-struct
109 :    
110 :     struct
111 :     2 cells: field class-map
112 :     const-field class-instance-size \ aus
113 :     const-field class-instance-align \ aus
114 :     end-struct class-struct
115 :    
116 :     2variable current-map \ address and size (in aus) of the current map
117 :    
118 :     : class ( class -- size align )
119 :     dup class-map 2@ save-mem current-map 2!
120 :     dup class-instance-size
121 :     swap class-instance-align ;
122 :    
123 :     : end-class ( size align "name" -- )
124 :     create
125 :     current-map 2@ 2,
126 :     swap , , ;
127 :    
128 :     : no-method ( -- )
129 :     abort" no method defined" ;
130 :    
131 :     : method ( xt "name" -- )
132 :     \ define method and selector
133 :     current-map 2@ ( xt map-addr map-size )
134 :     create dup ,
135 :     1 cells extend-mem current-map 2!
136 :     !
137 :     does> ( ... object -- ... )
138 :     ( object addr )
139 :     @ over ( object-map ) @ + ( object xtp ) perform ;
140 :    
141 :     : selector ( "name" -- )
142 :     \ define a method selector for later overriding in subclasses
143 :     ['] no-method method ;
144 :    
145 :     : override! ( xt method-xt -- )
146 :     >body @ current-map 2@ drop + ! ;
147 :    
148 :     : overrides ( xt "selector" -- )
149 :     \ replace default method "method" with xt
150 :     ' override! ;
151 :    
152 :     : alloc-instance ( class -- object )
153 :     \ make a new, (almost) uninitialized instance of a class
154 :     dup class-instance-size allocate throw
155 :     swap class-map 2@ drop over ( object-map ) ! ;
156 :    
157 :     \ this/self, instance variables etc.
158 :    
159 :     variable thisp
160 :     : this ( -- object )
161 :     \ rename this into self if you are a Smalltalk fiend
162 :     thisp @ ;
163 :    
164 :     : m: ( -- xt colon-sys ) ( run-time: object -- )
165 :     :noname
166 :     POSTPONE this
167 :     POSTPONE >r
168 :     POSTPONE thisp
169 :     POSTPONE ! ;
170 :    
171 :     : ;m ( colon-sys -- ) ( run-time: -- )
172 :     POSTPONE r>
173 :     POSTPONE thisp
174 :     POSTPONE !
175 :     POSTPONE ; ; immediate
176 :    
177 :     : catch ( ... xt -- ... n )
178 :     \ make it safe to call CATCH within a method.
179 :     \ should also be done with all words containing CATCH.
180 :     this >r catch r> thisp ! ;
181 :    
182 :     : inst-var ( size1 align1 size align -- size2 align2 )
183 :     field
184 :     does> ( -- addr )
185 :     ( addr1 ) @ this + ;
186 :    
187 :     \ early binding stuff
188 :    
189 :     \ this is not generally used, only where you want to do something like
190 :     \ superclass method invocation (so that you don't have to name your methods)
191 :    
192 :     : (bind) ( class method-xt -- xt )
193 :     >body @ swap class-map 2@ drop + @ ;
194 :    
195 :     : bind' ( "class" "method" -- xt )
196 :     ' >body ' (bind) ;
197 :    
198 :     : bind ( ... object "class" "method" -- ... )
199 :     bind' execute ;
200 :    
201 :     : [bind] ( compile-time: "class" "method" -- ; run-time: ... object -- ... )
202 :     bind' compile, ; immediate
203 :    
204 :     \ the object class
205 :    
206 :     0 0 save-mem current-map 2!
207 :     object-struct \ no class to inherit from, so we have to do this manually
208 :     :noname ( object -- )
209 :     ." object:" dup . ." class:" object-map @ . ;
210 :     method print
211 :     end-class object
212 :    
213 :     \ examples
214 :     true [if]
215 :     cr object alloc-instance print
216 :    
217 :     object class
218 :     :noname ( object -- )
219 :     drop ." undefined" ;
220 :     overrides print
221 :     end-class nothing
222 :    
223 :     nothing alloc-instance constant undefined
224 :    
225 :     cr undefined print
226 :    
227 :     \ instance variables and this
228 :     object class
229 :     1 cells: inst-var count-n
230 :     m: ( object -- )
231 :     count-n @ . ;m
232 :     overrides print
233 :     m: ( object -- )
234 :     0 count-n ! ;m
235 :     method init
236 :     m: ( object -- )
237 :     1 count-n +! ;m
238 :     method inc
239 :     end-class counter
240 :    
241 :     counter alloc-instance constant counter1
242 :    
243 :     cr
244 :     counter1 init
245 :     counter1 print
246 :     counter1 inc
247 :     counter1 print
248 :     counter1 inc
249 :     counter1 inc
250 :     counter1 inc
251 :     counter1 print
252 :     counter1 print
253 :    
254 :     \ examples of static binding
255 :    
256 :     cr undefined bind object print
257 :     : object-print ( object -- )
258 :     [bind] object print ;
259 :    
260 :     cr undefined object-print
261 :     [then]

CVS Admin

Powered by ViewCVS 1.0-dev
(Powered by ViewCVS)

ViewCVS and CVS Help