xref: /freebsd/stand/ficl/softwords/oo.fr (revision 26a58599a09a6181e0f5abe624021865a0c23186)
1*ca987d46SWarner Losh\ #if FICL_WANT_OOP
2*ca987d46SWarner Losh\ ** ficl/softwords/oo.fr
3*ca987d46SWarner Losh\ ** F I C L   O - O   E X T E N S I O N S
4*ca987d46SWarner Losh\ ** john sadler aug 1998
5*ca987d46SWarner Losh\
6*ca987d46SWarner Losh
7*ca987d46SWarner Losh17 ficl-vocabulary oop
8*ca987d46SWarner Loshalso oop definitions
9*ca987d46SWarner Losh
10*ca987d46SWarner Losh\ Design goals:
11*ca987d46SWarner Losh\ 0. Traditional OOP: late binding by default for safety.
12*ca987d46SWarner Losh\    Early binding if you ask for it.
13*ca987d46SWarner Losh\ 1. Single inheritance
14*ca987d46SWarner Losh\ 2. Object aggregation (has-a relationship)
15*ca987d46SWarner Losh\ 3. Support objects in the dictionary and as proxies for
16*ca987d46SWarner Losh\    existing structures (by reference):
17*ca987d46SWarner Losh\    *** A ficl object can wrap a C struct ***
18*ca987d46SWarner Losh\ 4. Separate name-spaces for methods - methods are
19*ca987d46SWarner Losh\    only visible in the context of a class / object
20*ca987d46SWarner Losh\ 5. Methods can be overridden, and subclasses can add methods.
21*ca987d46SWarner Losh\    No limit on number of methods.
22*ca987d46SWarner Losh
23*ca987d46SWarner Losh\ General info:
24*ca987d46SWarner Losh\ Classes are objects, too: all classes are instances of METACLASS
25*ca987d46SWarner Losh\ All classes are derived (by convention) from OBJECT. This
26*ca987d46SWarner Losh\ base class provides a default initializer and superclass
27*ca987d46SWarner Losh\ access method
28*ca987d46SWarner Losh
29*ca987d46SWarner Losh\ A ficl object binds instance storage (payload) to a class.
30*ca987d46SWarner Losh\ object  ( -- instance class )
31*ca987d46SWarner Losh\ All objects push their payload address and class address when
32*ca987d46SWarner Losh\ executed.
33*ca987d46SWarner Losh
34*ca987d46SWarner Losh\ A ficl class consists of a parent class pointer, a wordlist
35*ca987d46SWarner Losh\ ID for the methods of the class, and a size for the payload
36*ca987d46SWarner Losh\ of objects created by the class. A class is an object.
37*ca987d46SWarner Losh\ The NEW method creates and initializes an instance of a class.
38*ca987d46SWarner Losh\ Classes have this footprint:
39*ca987d46SWarner Losh\ cell 0: parent class address
40*ca987d46SWarner Losh\ cell 1: wordlist ID
41*ca987d46SWarner Losh\ cell 2: size of instance's payload
42*ca987d46SWarner Losh
43*ca987d46SWarner Losh\ Methods expect an object couple ( instance class )
44*ca987d46SWarner Losh\ on the stack. This is by convention - ficl has no way to
45*ca987d46SWarner Losh\ police your code to make sure this is always done, but it
46*ca987d46SWarner Losh\ happens naturally if you use the facilities presented here.
47*ca987d46SWarner Losh\
48*ca987d46SWarner Losh\ Overridden methods must maintain the same stack signature as
49*ca987d46SWarner Losh\ their predecessors. Ficl has no way of enforcing this, either.
50*ca987d46SWarner Losh\
51*ca987d46SWarner Losh\ Revised Apr 2001 - Added Guy Carver's vtable extensions. Class now
52*ca987d46SWarner Losh\ has an extra field for the vtable method count. Hasvtable declares
53*ca987d46SWarner Losh\ refs to vtable classes
54*ca987d46SWarner Losh\
55*ca987d46SWarner Losh\ Revised Nov 2001 - metaclass debug method now finds only metaclass methods
56*ca987d46SWarner Losh\
57*ca987d46SWarner Losh\ Planned: Ficl vtable support
58*ca987d46SWarner Losh\ Each class has a vtable size parameter
59*ca987d46SWarner Losh\ END-CLASS allocates and clears the vtable - then it walks class's method
60*ca987d46SWarner Losh\ list and inserts all new methods into table. For each method, if the table
61*ca987d46SWarner Losh\ slot is already nonzero, do nothing (overridden method). Otherwise fill
62*ca987d46SWarner Losh\ vtable slot. Now do same check for parent class vtable, filling only
63*ca987d46SWarner Losh\ empty slots in the new vtable.
64*ca987d46SWarner Losh\ Methods are now structured as follows:
65*ca987d46SWarner Losh\ - header
66*ca987d46SWarner Losh\ - vtable index
67*ca987d46SWarner Losh\ - xt
68*ca987d46SWarner Losh\ :noname definition for code
69*ca987d46SWarner Losh\
70*ca987d46SWarner Losh\ : is redefined to check for override, fill in vtable index, increment method
71*ca987d46SWarner Losh\ count if not an override, create header and fill in index. Allot code pointer
72*ca987d46SWarner Losh\ and run :noname
73*ca987d46SWarner Losh\ ; is overridden to fill in xt returned by :noname
74*ca987d46SWarner Losh\ --> compiles code to fetch vtable address, offset by index, and execute
75*ca987d46SWarner Losh\ => looks up xt in the vtable and compiles it directly
76*ca987d46SWarner Losh
77*ca987d46SWarner Losh
78*ca987d46SWarner Losh
79*ca987d46SWarner Loshuser current-class
80*ca987d46SWarner Losh0 current-class !
81*ca987d46SWarner Losh
82*ca987d46SWarner Losh\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
83*ca987d46SWarner Losh\ ** L A T E   B I N D I N G
84*ca987d46SWarner Losh\ Compile the method name, and code to find and
85*ca987d46SWarner Losh\ execute it at run-time...
86*ca987d46SWarner Losh\
87*ca987d46SWarner Losh
88*ca987d46SWarner Losh\ p a r s e - m e t h o d
89*ca987d46SWarner Losh\ compiles a method name so that it pushes
90*ca987d46SWarner Losh\ the string base address and count at run-time.
91*ca987d46SWarner Losh
92*ca987d46SWarner Losh: parse-method  \ name  run: ( -- c-addr u )
93*ca987d46SWarner Losh    parse-word
94*ca987d46SWarner Losh    postpone sliteral
95*ca987d46SWarner Losh; compile-only
96*ca987d46SWarner Losh
97*ca987d46SWarner Losh
98*ca987d46SWarner Losh
99*ca987d46SWarner Losh: (lookup-method)  { class 2:name -- class 0 | class xt 1 | class xt -1  }
100*ca987d46SWarner Losh    class  name class cell+ @  ( class c-addr u wid )
101*ca987d46SWarner Losh    search-wordlist
102*ca987d46SWarner Losh;
103*ca987d46SWarner Losh
104*ca987d46SWarner Losh\ l o o k u p - m e t h o d
105*ca987d46SWarner Losh\ takes a counted string method name from the stack (as compiled
106*ca987d46SWarner Losh\ by parse-method) and attempts to look this method up in the method list of
107*ca987d46SWarner Losh\ the class that's on the stack. If successful, it leaves the class on the stack
108*ca987d46SWarner Losh\ and pushes the xt of the method. If not, it aborts with an error message.
109*ca987d46SWarner Losh
110*ca987d46SWarner Losh: lookup-method  { class 2:name -- class xt }
111*ca987d46SWarner Losh    class name (lookup-method)    ( 0 | xt 1 | xt -1 )
112*ca987d46SWarner Losh    0= if
113*ca987d46SWarner Losh        name type ."  not found in "
114*ca987d46SWarner Losh        class body> >name type
115*ca987d46SWarner Losh        cr abort
116*ca987d46SWarner Losh    endif
117*ca987d46SWarner Losh;
118*ca987d46SWarner Losh
119*ca987d46SWarner Losh: find-method-xt   \ name ( class -- class xt )
120*ca987d46SWarner Losh    parse-word lookup-method
121*ca987d46SWarner Losh;
122*ca987d46SWarner Losh
123*ca987d46SWarner Losh: catch-method  ( instance class c-addr u -- <method-signature> exc-flag )
124*ca987d46SWarner Losh    lookup-method catch
125*ca987d46SWarner Losh;
126*ca987d46SWarner Losh
127*ca987d46SWarner Losh: exec-method  ( instance class c-addr u -- <method-signature> )
128*ca987d46SWarner Losh    lookup-method execute
129*ca987d46SWarner Losh;
130*ca987d46SWarner Losh
131*ca987d46SWarner Losh\ Method lookup operator takes a class-addr and instance-addr
132*ca987d46SWarner Losh\ and executes the method from the class's wordlist if
133*ca987d46SWarner Losh\ interpreting. If compiling, bind late.
134*ca987d46SWarner Losh\
135*ca987d46SWarner Losh: -->   ( instance class -- ??? )
136*ca987d46SWarner Losh    state @ 0= if
137*ca987d46SWarner Losh        find-method-xt execute
138*ca987d46SWarner Losh    else
139*ca987d46SWarner Losh        parse-method  postpone exec-method
140*ca987d46SWarner Losh    endif
141*ca987d46SWarner Losh; immediate
142*ca987d46SWarner Losh
143*ca987d46SWarner Losh\ Method lookup with CATCH in case of exceptions
144*ca987d46SWarner Losh: c->   ( instance class -- ?? exc-flag )
145*ca987d46SWarner Losh    state @ 0= if
146*ca987d46SWarner Losh        find-method-xt catch
147*ca987d46SWarner Losh    else
148*ca987d46SWarner Losh        parse-method  postpone catch-method
149*ca987d46SWarner Losh    endif
150*ca987d46SWarner Losh; immediate
151*ca987d46SWarner Losh
152*ca987d46SWarner Losh\ METHOD  makes global words that do method invocations by late binding
153*ca987d46SWarner Losh\ in case you prefer this style (no --> in your code)
154*ca987d46SWarner Losh\ Example: everything has next and prev for array access, so...
155*ca987d46SWarner Losh\ method next
156*ca987d46SWarner Losh\ method prev
157*ca987d46SWarner Losh\ my-instance next ( does whatever next does to my-instance by late binding )
158*ca987d46SWarner Losh
159*ca987d46SWarner Losh: method   create does> body> >name lookup-method execute ;
160*ca987d46SWarner Losh
161*ca987d46SWarner Losh
162*ca987d46SWarner Losh\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
163*ca987d46SWarner Losh\ ** E A R L Y   B I N D I N G
164*ca987d46SWarner Losh\ Early binding operator compiles code to execute a method
165*ca987d46SWarner Losh\ given its class at compile time. Classes are immediate,
166*ca987d46SWarner Losh\ so they leave their cell-pair on the stack when compiling.
167*ca987d46SWarner Losh\ Example:
168*ca987d46SWarner Losh\   : get-wid   metaclass => .wid @ ;
169*ca987d46SWarner Losh\ Usage
170*ca987d46SWarner Losh\   my-class get-wid  ( -- wid-of-my-class )
171*ca987d46SWarner Losh\
172*ca987d46SWarner Losh1 ficl-named-wordlist instance-vars
173*ca987d46SWarner Loshinstance-vars dup >search ficl-set-current
174*ca987d46SWarner Losh
175*ca987d46SWarner Losh: =>   \ c:( class meta -- ) run: ( -- ??? ) invokes compiled method
176*ca987d46SWarner Losh    drop find-method-xt compile, drop
177*ca987d46SWarner Losh; immediate compile-only
178*ca987d46SWarner Losh
179*ca987d46SWarner Losh: my=>   \ c:( -- ) run: ( -- ??? ) late bind compiled method of current-class
180*ca987d46SWarner Losh    current-class @ dup postpone =>
181*ca987d46SWarner Losh; immediate compile-only
182*ca987d46SWarner Losh
183*ca987d46SWarner Losh\ Problem: my=[ assumes that each method except the last is am obj: member
184*ca987d46SWarner Losh\ which contains its class as the first field of its parameter area. The code
185*ca987d46SWarner Losh\ detects non-obect members and assumes the class does not change in this case.
186*ca987d46SWarner Losh\ This handles methods like index, prev, and next correctly, but does not deal
187*ca987d46SWarner Losh\ correctly with CLASS.
188*ca987d46SWarner Losh: my=[   \ same as my=> , but binds a chain of methods
189*ca987d46SWarner Losh    current-class @
190*ca987d46SWarner Losh    begin
191*ca987d46SWarner Losh        parse-word 2dup             ( class c-addr u c-addr u )
192*ca987d46SWarner Losh        s" ]" compare while         ( class c-addr u )
193*ca987d46SWarner Losh        lookup-method               ( class xt )
194*ca987d46SWarner Losh        dup compile,                ( class xt )
195*ca987d46SWarner Losh        dup ?object if        \ If object member, get new class. Otherwise assume same class
196*ca987d46SWarner Losh           nip >body cell+ @        ( new-class )
197*ca987d46SWarner Losh        else
198*ca987d46SWarner Losh           drop                     ( class )
199*ca987d46SWarner Losh        endif
200*ca987d46SWarner Losh    repeat 2drop drop
201*ca987d46SWarner Losh; immediate compile-only
202*ca987d46SWarner Losh
203*ca987d46SWarner Losh
204*ca987d46SWarner Losh\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
205*ca987d46SWarner Losh\ ** I N S T A N C E   V A R I A B L E S
206*ca987d46SWarner Losh\ Instance variables (IV) are represented by words in the class's
207*ca987d46SWarner Losh\ private wordlist. Each IV word contains the offset
208*ca987d46SWarner Losh\ of the IV it represents, and runs code to add that offset
209*ca987d46SWarner Losh\ to the base address of an instance when executed.
210*ca987d46SWarner Losh\ The metaclass SUB method, defined below, leaves the address
211*ca987d46SWarner Losh\ of the new class's offset field and its initial size on the
212*ca987d46SWarner Losh\ stack for these words to update. When a class definition is
213*ca987d46SWarner Losh\ complete, END-CLASS saves the final size in the class's size
214*ca987d46SWarner Losh\ field, and restores the search order and compile wordlist to
215*ca987d46SWarner Losh\ prior state. Note that these words are hidden in their own
216*ca987d46SWarner Losh\ wordlist to prevent accidental use outside a SUB END-CLASS pair.
217*ca987d46SWarner Losh\
218*ca987d46SWarner Losh: do-instance-var
219*ca987d46SWarner Losh    does>   ( instance class addr[offset] -- addr[field] )
220*ca987d46SWarner Losh        nip @ +
221*ca987d46SWarner Losh;
222*ca987d46SWarner Losh
223*ca987d46SWarner Losh: addr-units:  ( offset size "name" -- offset' )
224*ca987d46SWarner Losh    create over , +
225*ca987d46SWarner Losh    do-instance-var
226*ca987d46SWarner Losh;
227*ca987d46SWarner Losh
228*ca987d46SWarner Losh: chars:    \ ( offset nCells "name" -- offset' ) Create n char member.
229*ca987d46SWarner Losh   chars addr-units: ;
230*ca987d46SWarner Losh
231*ca987d46SWarner Losh: char:     \ ( offset nCells "name" -- offset' ) Create 1 char member.
232*ca987d46SWarner Losh   1 chars: ;
233*ca987d46SWarner Losh
234*ca987d46SWarner Losh: cells:  ( offset nCells "name" -- offset' )
235*ca987d46SWarner Losh    cells >r aligned r> addr-units:
236*ca987d46SWarner Losh;
237*ca987d46SWarner Losh
238*ca987d46SWarner Losh: cell:   ( offset nCells "name" -- offset' )
239*ca987d46SWarner Losh    1 cells: ;
240*ca987d46SWarner Losh
241*ca987d46SWarner Losh\ Aggregate an object into the class...
242*ca987d46SWarner Losh\ Needs the class of the instance to create
243*ca987d46SWarner Losh\ Example: object obj: m_obj
244*ca987d46SWarner Losh\
245*ca987d46SWarner Losh: do-aggregate
246*ca987d46SWarner Losh    objectify
247*ca987d46SWarner Losh    does>   ( instance class pfa -- a-instance a-class )
248*ca987d46SWarner Losh    2@          ( inst class a-class a-offset )
249*ca987d46SWarner Losh    2swap drop  ( a-class a-offset inst )
250*ca987d46SWarner Losh    + swap      ( a-inst a-class )
251*ca987d46SWarner Losh;
252*ca987d46SWarner Losh
253*ca987d46SWarner Losh: obj:   { offset class meta -- offset' }  \ "name"
254*ca987d46SWarner Losh    create  offset , class ,
255*ca987d46SWarner Losh    class meta --> get-size  offset +
256*ca987d46SWarner Losh    do-aggregate
257*ca987d46SWarner Losh;
258*ca987d46SWarner Losh
259*ca987d46SWarner Losh\ Aggregate an array of objects into a class
260*ca987d46SWarner Losh\ Usage example:
261*ca987d46SWarner Losh\ 3 my-class array: my-array
262*ca987d46SWarner Losh\ Makes an instance variable array of 3 instances of my-class
263*ca987d46SWarner Losh\ named my-array.
264*ca987d46SWarner Losh\
265*ca987d46SWarner Losh: array:   ( offset n class meta "name" -- offset' )
266*ca987d46SWarner Losh    locals| meta class nobjs offset |
267*ca987d46SWarner Losh    create offset , class ,
268*ca987d46SWarner Losh    class meta --> get-size  nobjs * offset +
269*ca987d46SWarner Losh    do-aggregate
270*ca987d46SWarner Losh;
271*ca987d46SWarner Losh
272*ca987d46SWarner Losh\ Aggregate a pointer to an object: REF is a member variable
273*ca987d46SWarner Losh\ whose class is set at compile time. This is useful for wrapping
274*ca987d46SWarner Losh\ data structures in C, where there is only a pointer and the type
275*ca987d46SWarner Losh\ it refers to is known. If you want polymorphism, see c_ref
276*ca987d46SWarner Losh\ in classes.fr. REF is only useful for pre-initialized structures,
277*ca987d46SWarner Losh\ since there's no supported way to set one.
278*ca987d46SWarner Losh: ref:   ( offset class meta "name" -- offset' )
279*ca987d46SWarner Losh    locals| meta class offset |
280*ca987d46SWarner Losh    create offset , class ,
281*ca987d46SWarner Losh    offset cell+
282*ca987d46SWarner Losh    does>    ( inst class pfa -- ptr-inst ptr-class )
283*ca987d46SWarner Losh    2@       ( inst class ptr-class ptr-offset )
284*ca987d46SWarner Losh    2swap drop + @ swap
285*ca987d46SWarner Losh;
286*ca987d46SWarner Losh
287*ca987d46SWarner Losh\ #if FICL_WANT_VCALL
288*ca987d46SWarner Losh\ vcall extensions contributed by Guy Carver
289*ca987d46SWarner Losh: vcall:  ( paramcnt "name" -- )
290*ca987d46SWarner Losh    current-class @ 8 + dup @ dup 1+ rot !  \ Kludge fix to get to .vtCount before it's defined.
291*ca987d46SWarner Losh    create , ,                              \ ( paramcnt index -- )
292*ca987d46SWarner Losh    does>                                   \ ( inst class pfa -- ptr-inst ptr-class )
293*ca987d46SWarner Losh   nip 2@ vcall                             \ ( params offset inst class offset -- )
294*ca987d46SWarner Losh;
295*ca987d46SWarner Losh
296*ca987d46SWarner Losh: vcallr: 0x80000000 or vcall: ;            \ Call with return address desired.
297*ca987d46SWarner Losh
298*ca987d46SWarner Losh\ #if FICL_WANT_FLOAT
299*ca987d46SWarner Losh: vcallf:                                   \ ( paramcnt -<name>- f: r )
300*ca987d46SWarner Losh    0x80000000 or
301*ca987d46SWarner Losh    current-class @ 8 + dup @ dup 1+ rot !  \ Kludge fix to get to .vtCount before it's defined.
302*ca987d46SWarner Losh    create , ,                              \ ( paramcnt index -- )
303*ca987d46SWarner Losh    does>                                   \ ( inst class pfa -- ptr-inst ptr-class )
304*ca987d46SWarner Losh    nip 2@ vcall f>                         \ ( params offset inst class offset -- f: r )
305*ca987d46SWarner Losh;
306*ca987d46SWarner Losh\ #endif /* FLOAT */
307*ca987d46SWarner Losh\ #endif /* VCALL */
308*ca987d46SWarner Losh
309*ca987d46SWarner Losh\ END-CLASS terminates construction of a class by storing
310*ca987d46SWarner Losh\  the size of its instance variables in the class's size field
311*ca987d46SWarner Losh\ ( -- old-wid addr[size] 0 )
312*ca987d46SWarner Losh\
313*ca987d46SWarner Losh: end-class  ( old-wid addr[size] size -- )
314*ca987d46SWarner Losh    swap ! set-current
315*ca987d46SWarner Losh    search> drop        \ pop struct builder wordlist
316*ca987d46SWarner Losh;
317*ca987d46SWarner Losh
318*ca987d46SWarner Losh\ See resume-class (a metaclass method) below for usage
319*ca987d46SWarner Losh\ This is equivalent to end-class for now, but that will change
320*ca987d46SWarner Losh\ when we support vtable bindings.
321*ca987d46SWarner Losh: suspend-class  ( old-wid addr[size] size -- )   end-class ;
322*ca987d46SWarner Losh
323*ca987d46SWarner Loshset-current previous
324*ca987d46SWarner Losh\ E N D   I N S T A N C E   V A R I A B L E S
325*ca987d46SWarner Losh
326*ca987d46SWarner Losh
327*ca987d46SWarner Losh\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
328*ca987d46SWarner Losh\ D O - D O - I N S T A N C E
329*ca987d46SWarner Losh\ Makes a class method that contains the code for an
330*ca987d46SWarner Losh\ instance of the class. This word gets compiled into
331*ca987d46SWarner Losh\ the wordlist of every class by the SUB method.
332*ca987d46SWarner Losh\ PRECONDITION: current-class contains the class address
333*ca987d46SWarner Losh\ why use a state variable instead of the stack?
334*ca987d46SWarner Losh\ >> Stack state is not well-defined during compilation (there are
335*ca987d46SWarner Losh\ >> control structure match codes on the stack, of undefined size
336*ca987d46SWarner Losh\ >> easiest way around this is use of this thread-local variable
337*ca987d46SWarner Losh\
338*ca987d46SWarner Losh: do-do-instance  ( -- )
339*ca987d46SWarner Losh    s" : .do-instance does> [ current-class @ ] literal ;"
340*ca987d46SWarner Losh    evaluate
341*ca987d46SWarner Losh;
342*ca987d46SWarner Losh
343*ca987d46SWarner Losh\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
344*ca987d46SWarner Losh\ ** M E T A C L A S S
345*ca987d46SWarner Losh\ Every class is an instance of metaclass. This lets
346*ca987d46SWarner Losh\ classes have methods that are different from those
347*ca987d46SWarner Losh\ of their instances.
348*ca987d46SWarner Losh\ Classes are IMMEDIATE to make early binding simpler
349*ca987d46SWarner Losh\ See above...
350*ca987d46SWarner Losh\
351*ca987d46SWarner Losh:noname
352*ca987d46SWarner Losh    wordlist
353*ca987d46SWarner Losh    create
354*ca987d46SWarner Losh    immediate
355*ca987d46SWarner Losh    0       ,   \ NULL parent class
356*ca987d46SWarner Losh    dup     ,   \ wid
357*ca987d46SWarner Losh\ #if FICL_WANT_VCALL
358*ca987d46SWarner Losh    4 cells ,   \ instance size
359*ca987d46SWarner Losh\ #else
360*ca987d46SWarner Losh    3 cells ,   \ instance size
361*ca987d46SWarner Losh\ #endif
362*ca987d46SWarner Losh    ficl-set-current
363*ca987d46SWarner Losh    does> dup
364*ca987d46SWarner Losh;  execute metaclass
365*ca987d46SWarner Losh\ now brand OBJECT's wordlist (so that ORDER can display it by name)
366*ca987d46SWarner Loshmetaclass drop cell+ @ brand-wordlist
367*ca987d46SWarner Losh
368*ca987d46SWarner Loshmetaclass drop current-class !
369*ca987d46SWarner Loshdo-do-instance
370*ca987d46SWarner Losh
371*ca987d46SWarner Losh\
372*ca987d46SWarner Losh\ C L A S S   M E T H O D S
373*ca987d46SWarner Losh\
374*ca987d46SWarner Loshinstance-vars >search
375*ca987d46SWarner Losh
376*ca987d46SWarner Loshcreate .super  ( class metaclass -- parent-class )
377*ca987d46SWarner Losh    0 cells , do-instance-var
378*ca987d46SWarner Losh
379*ca987d46SWarner Loshcreate .wid    ( class metaclass -- wid ) \ return wid of class
380*ca987d46SWarner Losh    1 cells , do-instance-var
381*ca987d46SWarner Losh
382*ca987d46SWarner Losh\ #if FICL_WANT_VCALL
383*ca987d46SWarner Loshcreate .vtCount   \ Number of VTABLE methods, if any
384*ca987d46SWarner Losh    2 cells , do-instance-var
385*ca987d46SWarner Losh
386*ca987d46SWarner Loshcreate  .size  ( class metaclass -- size ) \ return class's payload size
387*ca987d46SWarner Losh    3 cells , do-instance-var
388*ca987d46SWarner Losh\ #else
389*ca987d46SWarner Loshcreate  .size  ( class metaclass -- size ) \ return class's payload size
390*ca987d46SWarner Losh    2 cells , do-instance-var
391*ca987d46SWarner Losh\ #endif
392*ca987d46SWarner Losh
393*ca987d46SWarner Losh: get-size    metaclass => .size  @ ;
394*ca987d46SWarner Losh: get-wid     metaclass => .wid   @ ;
395*ca987d46SWarner Losh: get-super   metaclass => .super @ ;
396*ca987d46SWarner Losh\ #if FICL_WANT_VCALL
397*ca987d46SWarner Losh: get-vtCount metaclass => .vtCount @ ;
398*ca987d46SWarner Losh: get-vtAdd   metaclass => .vtCount ;
399*ca987d46SWarner Losh\ #endif
400*ca987d46SWarner Losh
401*ca987d46SWarner Losh\ create an uninitialized instance of a class, leaving
402*ca987d46SWarner Losh\ the address of the new instance and its class
403*ca987d46SWarner Losh\
404*ca987d46SWarner Losh: instance   ( class metaclass "name" -- instance class )
405*ca987d46SWarner Losh    locals| meta parent |
406*ca987d46SWarner Losh    create
407*ca987d46SWarner Losh    here parent --> .do-instance \ ( inst class )
408*ca987d46SWarner Losh    parent meta metaclass => get-size
409*ca987d46SWarner Losh    allot                        \ allocate payload space
410*ca987d46SWarner Losh;
411*ca987d46SWarner Losh
412*ca987d46SWarner Losh\ create an uninitialized array
413*ca987d46SWarner Losh: array   ( n class metaclass "name" -- n instance class )
414*ca987d46SWarner Losh    locals| meta parent nobj |
415*ca987d46SWarner Losh    create  nobj
416*ca987d46SWarner Losh    here parent --> .do-instance \ ( nobj inst class )
417*ca987d46SWarner Losh    parent meta metaclass => get-size
418*ca987d46SWarner Losh    nobj *  allot           \ allocate payload space
419*ca987d46SWarner Losh;
420*ca987d46SWarner Losh
421*ca987d46SWarner Losh\ create an initialized instance
422*ca987d46SWarner Losh\
423*ca987d46SWarner Losh: new   \ ( class metaclass "name" -- )
424*ca987d46SWarner Losh    metaclass => instance --> init
425*ca987d46SWarner Losh;
426*ca987d46SWarner Losh
427*ca987d46SWarner Losh\ create an initialized array of instances
428*ca987d46SWarner Losh: new-array   ( n class metaclass "name" -- )
429*ca987d46SWarner Losh    metaclass => array
430*ca987d46SWarner Losh    --> array-init
431*ca987d46SWarner Losh;
432*ca987d46SWarner Losh
433*ca987d46SWarner Losh\ Create an anonymous initialized instance from the heap
434*ca987d46SWarner Losh: alloc   \ ( class metaclass -- instance class )
435*ca987d46SWarner Losh    locals| meta class |
436*ca987d46SWarner Losh    class meta metaclass => get-size allocate   ( -- addr fail-flag )
437*ca987d46SWarner Losh    abort" allocate failed "                    ( -- addr )
438*ca987d46SWarner Losh    class 2dup --> init
439*ca987d46SWarner Losh;
440*ca987d46SWarner Losh
441*ca987d46SWarner Losh\ Create an anonymous array of initialized instances from the heap
442*ca987d46SWarner Losh: alloc-array   \ ( n class metaclass -- instance class )
443*ca987d46SWarner Losh    locals| meta class nobj |
444*ca987d46SWarner Losh    class meta metaclass => get-size
445*ca987d46SWarner Losh    nobj * allocate                 ( -- addr fail-flag )
446*ca987d46SWarner Losh    abort" allocate failed "        ( -- addr )
447*ca987d46SWarner Losh    nobj over class --> array-init
448*ca987d46SWarner Losh    class
449*ca987d46SWarner Losh;
450*ca987d46SWarner Losh
451*ca987d46SWarner Losh\ Create an anonymous initialized instance from the dictionary
452*ca987d46SWarner Losh: allot   { 2:this -- 2:instance }
453*ca987d46SWarner Losh    here   ( instance-address )
454*ca987d46SWarner Losh    this my=> get-size  allot
455*ca987d46SWarner Losh    this drop 2dup --> init
456*ca987d46SWarner Losh;
457*ca987d46SWarner Losh
458*ca987d46SWarner Losh\ Create an anonymous array of initialized instances from the dictionary
459*ca987d46SWarner Losh: allot-array   { nobj 2:this -- 2:instance }
460*ca987d46SWarner Losh    here   ( instance-address )
461*ca987d46SWarner Losh    this my=> get-size  nobj * allot
462*ca987d46SWarner Losh    this drop 2dup     ( 2instance 2instance )
463*ca987d46SWarner Losh    nobj -rot --> array-init
464*ca987d46SWarner Losh;
465*ca987d46SWarner Losh
466*ca987d46SWarner Losh\ create a proxy object with initialized payload address given
467*ca987d46SWarner Losh: ref   ( instance-addr class metaclass "name" -- )
468*ca987d46SWarner Losh    drop create , ,
469*ca987d46SWarner Losh    does> 2@
470*ca987d46SWarner Losh;
471*ca987d46SWarner Losh
472*ca987d46SWarner Losh\ suspend-class and resume-class help to build mutually referent classes.
473*ca987d46SWarner Losh\ Example:
474*ca987d46SWarner Losh\ object subclass c-akbar
475*ca987d46SWarner Losh\ suspend-class   ( put akbar on hold while we define jeff )
476*ca987d46SWarner Losh\ object subclass c-jeff
477*ca987d46SWarner Losh\     c-akbar ref: .akbar
478*ca987d46SWarner Losh\     ( and whatever else comprises this class )
479*ca987d46SWarner Losh\ end-class    ( done with c-jeff )
480*ca987d46SWarner Losh\ c-akbar --> resume-class
481*ca987d46SWarner Losh\     c-jeff ref: .jeff
482*ca987d46SWarner Losh\     ( and whatever else goes in c-akbar )
483*ca987d46SWarner Losh\ end-class    ( done with c-akbar )
484*ca987d46SWarner Losh\
485*ca987d46SWarner Losh: resume-class   { 2:this -- old-wid addr[size] size }
486*ca987d46SWarner Losh    this --> .wid @ ficl-set-current  ( old-wid )
487*ca987d46SWarner Losh    this --> .size dup @   ( old-wid addr[size] size )
488*ca987d46SWarner Losh    instance-vars >search
489*ca987d46SWarner Losh;
490*ca987d46SWarner Losh
491*ca987d46SWarner Losh\ create a subclass
492*ca987d46SWarner Losh\ This method leaves the stack and search order ready for instance variable
493*ca987d46SWarner Losh\ building. Pushes the instance-vars wordlist onto the search order,
494*ca987d46SWarner Losh\ and sets the compilation wordlist to be the private wordlist of the
495*ca987d46SWarner Losh\ new class. The class's wordlist is deliberately NOT in the search order -
496*ca987d46SWarner Losh\ to prevent methods from getting used with wrong data.
497*ca987d46SWarner Losh\ Postcondition: leaves the address of the new class in current-class
498*ca987d46SWarner Losh: sub   ( class metaclass "name" -- old-wid addr[size] size )
499*ca987d46SWarner Losh    wordlist
500*ca987d46SWarner Losh    locals| wid meta parent |
501*ca987d46SWarner Losh    parent meta metaclass => get-wid
502*ca987d46SWarner Losh    wid wid-set-super       \ set superclass
503*ca987d46SWarner Losh    create  immediate       \ get the  subclass name
504*ca987d46SWarner Losh    wid brand-wordlist      \ label the subclass wordlist
505*ca987d46SWarner Losh    here current-class !    \ prep for do-do-instance
506*ca987d46SWarner Losh    parent ,                \ save parent class
507*ca987d46SWarner Losh    wid    ,                \ save wid
508*ca987d46SWarner Losh\ #if FICL_WANT_VCALL
509*ca987d46SWarner Losh    parent meta --> get-vtCount ,
510*ca987d46SWarner Losh\ #endif
511*ca987d46SWarner Losh    here parent meta --> get-size dup ,  ( addr[size] size )
512*ca987d46SWarner Losh    metaclass => .do-instance
513*ca987d46SWarner Losh    wid ficl-set-current -rot
514*ca987d46SWarner Losh    do-do-instance
515*ca987d46SWarner Losh    instance-vars >search \ push struct builder wordlist
516*ca987d46SWarner Losh;
517*ca987d46SWarner Losh
518*ca987d46SWarner Losh\ OFFSET-OF returns the offset of an instance variable
519*ca987d46SWarner Losh\ from the instance base address. If the next token is not
520*ca987d46SWarner Losh\ the name of in instance variable method, you get garbage
521*ca987d46SWarner Losh\ results -- there is no way at present to check for this error.
522*ca987d46SWarner Losh: offset-of   ( class metaclass "name" -- offset )
523*ca987d46SWarner Losh    drop find-method-xt nip >body @ ;
524*ca987d46SWarner Losh
525*ca987d46SWarner Losh\ ID returns the string name cell-pair of its class
526*ca987d46SWarner Losh: id   ( class metaclass -- c-addr u )
527*ca987d46SWarner Losh    drop body> >name  ;
528*ca987d46SWarner Losh
529*ca987d46SWarner Losh\ list methods of the class
530*ca987d46SWarner Losh: methods \ ( class meta -- )
531*ca987d46SWarner Losh    locals| meta class |
532*ca987d46SWarner Losh    begin
533*ca987d46SWarner Losh        class body> >name type ."  methods:" cr
534*ca987d46SWarner Losh        class meta --> get-wid >search words cr previous
535*ca987d46SWarner Losh        class meta metaclass => get-super
536*ca987d46SWarner Losh        dup to class
537*ca987d46SWarner Losh    0= until  cr
538*ca987d46SWarner Losh;
539*ca987d46SWarner Losh
540*ca987d46SWarner Losh\ list class's ancestors
541*ca987d46SWarner Losh: pedigree  ( class meta -- )
542*ca987d46SWarner Losh    locals| meta class |
543*ca987d46SWarner Losh    begin
544*ca987d46SWarner Losh        class body> >name type space
545*ca987d46SWarner Losh        class meta metaclass => get-super
546*ca987d46SWarner Losh        dup to class
547*ca987d46SWarner Losh    0= until  cr
548*ca987d46SWarner Losh;
549*ca987d46SWarner Losh
550*ca987d46SWarner Losh\ decompile an instance method
551*ca987d46SWarner Losh: see  ( class meta -- )
552*ca987d46SWarner Losh    metaclass => get-wid >search see previous ;
553*ca987d46SWarner Losh
554*ca987d46SWarner Losh\ debug a method of metaclass
555*ca987d46SWarner Losh\ Eg: my-class --> debug my-method
556*ca987d46SWarner Losh: debug  ( class meta -- )
557*ca987d46SWarner Losh	find-method-xt debug-xt ;
558*ca987d46SWarner Losh
559*ca987d46SWarner Loshprevious set-current
560*ca987d46SWarner Losh\ E N D   M E T A C L A S S
561*ca987d46SWarner Losh
562*ca987d46SWarner Losh\ ** META is a nickname for the address of METACLASS...
563*ca987d46SWarner Loshmetaclass drop
564*ca987d46SWarner Loshconstant meta
565*ca987d46SWarner Losh
566*ca987d46SWarner Losh\ ** SUBCLASS is a nickname for a class's SUB method...
567*ca987d46SWarner Losh\ Subclass compilation ends when you invoke end-class
568*ca987d46SWarner Losh\ This method is late bound for safety...
569*ca987d46SWarner Losh: subclass   --> sub ;
570*ca987d46SWarner Losh
571*ca987d46SWarner Losh\ #if FICL_WANT_VCALL
572*ca987d46SWarner Losh\ VTABLE Support extensions (Guy Carver)
573*ca987d46SWarner Losh\ object --> sub mine hasvtable
574*ca987d46SWarner Losh: hasvtable 4 + ; immediate
575*ca987d46SWarner Losh\ #endif
576*ca987d46SWarner Losh
577*ca987d46SWarner Losh
578*ca987d46SWarner Losh\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
579*ca987d46SWarner Losh\ ** O B J E C T
580*ca987d46SWarner Losh\ Root of all classes
581*ca987d46SWarner Losh:noname
582*ca987d46SWarner Losh    wordlist
583*ca987d46SWarner Losh    create  immediate
584*ca987d46SWarner Losh    0       ,   \ NULL parent class
585*ca987d46SWarner Losh    dup     ,   \ wid
586*ca987d46SWarner Losh    0       ,   \ instance size
587*ca987d46SWarner Losh    ficl-set-current
588*ca987d46SWarner Losh    does> meta
589*ca987d46SWarner Losh;  execute object
590*ca987d46SWarner Losh\ now brand OBJECT's wordlist (so that ORDER can display it by name)
591*ca987d46SWarner Loshobject drop cell+ @ brand-wordlist
592*ca987d46SWarner Losh
593*ca987d46SWarner Loshobject drop current-class !
594*ca987d46SWarner Loshdo-do-instance
595*ca987d46SWarner Loshinstance-vars >search
596*ca987d46SWarner Losh
597*ca987d46SWarner Losh\ O B J E C T   M E T H O D S
598*ca987d46SWarner Losh\ Convert instance cell-pair to class cell-pair
599*ca987d46SWarner Losh\ Useful for binding class methods from an instance
600*ca987d46SWarner Losh: class  ( instance class -- class metaclass )
601*ca987d46SWarner Losh    nip meta ;
602*ca987d46SWarner Losh
603*ca987d46SWarner Losh\ default INIT method zero fills an instance
604*ca987d46SWarner Losh: init   ( instance class -- )
605*ca987d46SWarner Losh    meta
606*ca987d46SWarner Losh    metaclass => get-size   ( inst size )
607*ca987d46SWarner Losh    erase ;
608*ca987d46SWarner Losh
609*ca987d46SWarner Losh\ Apply INIT to an array of NOBJ objects...
610*ca987d46SWarner Losh\
611*ca987d46SWarner Losh: array-init   ( nobj inst class -- )
612*ca987d46SWarner Losh    0 dup locals| &init &next class inst |
613*ca987d46SWarner Losh    \
614*ca987d46SWarner Losh    \ bind methods outside the loop to save time
615*ca987d46SWarner Losh    \
616*ca987d46SWarner Losh    class s" init" lookup-method to &init
617*ca987d46SWarner Losh          s" next" lookup-method to &next
618*ca987d46SWarner Losh    drop
619*ca987d46SWarner Losh    0 ?do
620*ca987d46SWarner Losh        inst class 2dup
621*ca987d46SWarner Losh        &init execute
622*ca987d46SWarner Losh        &next execute  drop to inst
623*ca987d46SWarner Losh    loop
624*ca987d46SWarner Losh;
625*ca987d46SWarner Losh
626*ca987d46SWarner Losh\ free storage allocated to a heap instance by alloc or alloc-array
627*ca987d46SWarner Losh\ NOTE: not protected against errors like FREEing something that's
628*ca987d46SWarner Losh\ really in the dictionary.
629*ca987d46SWarner Losh: free   \ ( instance class -- )
630*ca987d46SWarner Losh    drop free
631*ca987d46SWarner Losh    abort" free failed "
632*ca987d46SWarner Losh;
633*ca987d46SWarner Losh
634*ca987d46SWarner Losh\ Instance aliases for common class methods
635*ca987d46SWarner Losh\ Upcast to parent class
636*ca987d46SWarner Losh: super     ( instance class -- instance parent-class )
637*ca987d46SWarner Losh    meta  metaclass => get-super ;
638*ca987d46SWarner Losh
639*ca987d46SWarner Losh: pedigree  ( instance class -- )
640*ca987d46SWarner Losh    object => class
641*ca987d46SWarner Losh    metaclass => pedigree ;
642*ca987d46SWarner Losh
643*ca987d46SWarner Losh: size      ( instance class -- sizeof-instance )
644*ca987d46SWarner Losh    object => class
645*ca987d46SWarner Losh    metaclass => get-size ;
646*ca987d46SWarner Losh
647*ca987d46SWarner Losh: methods   ( instance class -- )
648*ca987d46SWarner Losh    object => class
649*ca987d46SWarner Losh    metaclass => methods ;
650*ca987d46SWarner Losh
651*ca987d46SWarner Losh\ Array indexing methods...
652*ca987d46SWarner Losh\ Usage examples:
653*ca987d46SWarner Losh\ 10 object-array --> index
654*ca987d46SWarner Losh\ obj --> next
655*ca987d46SWarner Losh\
656*ca987d46SWarner Losh: index   ( n instance class -- instance[n] class )
657*ca987d46SWarner Losh    locals| class inst |
658*ca987d46SWarner Losh    inst class
659*ca987d46SWarner Losh    object => class
660*ca987d46SWarner Losh    metaclass => get-size  *   ( n*size )
661*ca987d46SWarner Losh    inst +  class ;
662*ca987d46SWarner Losh
663*ca987d46SWarner Losh: next   ( instance[n] class -- instance[n+1] class )
664*ca987d46SWarner Losh    locals| class inst |
665*ca987d46SWarner Losh    inst class
666*ca987d46SWarner Losh    object => class
667*ca987d46SWarner Losh    metaclass => get-size
668*ca987d46SWarner Losh    inst +
669*ca987d46SWarner Losh    class ;
670*ca987d46SWarner Losh
671*ca987d46SWarner Losh: prev   ( instance[n] class -- instance[n-1] class )
672*ca987d46SWarner Losh    locals| class inst |
673*ca987d46SWarner Losh    inst class
674*ca987d46SWarner Losh    object => class
675*ca987d46SWarner Losh    metaclass => get-size
676*ca987d46SWarner Losh    inst swap -
677*ca987d46SWarner Losh    class ;
678*ca987d46SWarner Losh
679*ca987d46SWarner Losh: debug   ( 2this --  ?? )
680*ca987d46SWarner Losh    find-method-xt debug-xt ;
681*ca987d46SWarner Losh
682*ca987d46SWarner Loshprevious set-current
683*ca987d46SWarner Losh\ E N D   O B J E C T
684*ca987d46SWarner Losh
685*ca987d46SWarner Losh\ reset to default search order
686*ca987d46SWarner Loshonly definitions
687*ca987d46SWarner Losh
688*ca987d46SWarner Losh\ redefine oop in default search order to put OOP words in the search order and make them
689*ca987d46SWarner Losh\ the compiling wordlist...
690*ca987d46SWarner Losh
691*ca987d46SWarner Losh: oo   only also oop definitions ;
692*ca987d46SWarner Losh
693*ca987d46SWarner Losh\ #endif
694