aboutsummaryrefslogtreecommitdiff
path: root/softwords/oo.fr
blob: 31ab7e3d816d12466679580e1b2a41ce92ae8b1a (plain) (blame)
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
\ #if FICL_WANT_OOP
\ ** ficl/softwords/oo.fr
\ ** F I C L   O - O   E X T E N S I O N S
\ ** john sadler aug 1998

.( loading ficl O-O extensions ) cr
17 ficl-vocabulary oop
also oop definitions

\ Design goals:
\ 0. Traditional OOP: late binding by default for safety. 
\    Early binding if you ask for it.
\ 1. Single inheritance
\ 2. Object aggregation (has-a relationship)
\ 3. Support objects in the dictionary and as proxies for 
\    existing structures (by reference):
\    *** A ficl object can wrap a C struct ***
\ 4. Separate name-spaces for methods - methods are
\    only visible in the context of a class / object
\ 5. Methods can be overridden, and subclasses can add methods.
\    No limit on number of methods.

\ General info:
\ Classes are objects, too: all classes are instances of METACLASS
\ All classes are derived (by convention) from OBJECT. This
\ base class provides a default initializer and superclass 
\ access method

\ A ficl object binds instance storage (payload) to a class.
\ object  ( -- instance class )
\ All objects push their payload address and class address when
\ executed. 

\ A ficl class consists of a parent class pointer, a wordlist
\ ID for the methods of the class, and a size for the payload
\ of objects created by the class. A class is an object.
\ The NEW method creates and initializes an instance of a class.
\ Classes have this footprint:
\ cell 0: parent class address
\ cell 1: wordlist ID
\ cell 2: size of instance's payload

\ Methods expect an object couple ( instance class ) 
\ on the stack. This is by convention - ficl has no way to 
\ police your code to make sure this is always done, but it 
\ happens naturally if you use the facilities presented here.
\
\ Overridden methods must maintain the same stack signature as
\ their predecessors. Ficl has no way of enforcing this, either.
\
\ Revised Apr 2001 - Added Guy Carver's vtable extensions. Class now
\ has an extra field for the vtable method count. Hasvtable declares
\ refs to vtable classes
\
\ Revised Nov 2001 - metaclass debug method now finds only metaclass methods
\
\ Planned: Ficl vtable support
\ Each class has a vtable size parameter
\ END-CLASS allocates and clears the vtable - then it walks class's method 
\ list and inserts all new methods into table. For each method, if the table
\ slot is already nonzero, do nothing (overridden method). Otherwise fill
\ vtable slot. Now do same check for parent class vtable, filling only
\ empty slots in the new vtable.
\ Methods are now structured as follows:
\ - header
\ - vtable index
\ - xt
\ :noname definition for code
\
\ : is redefined to check for override, fill in vtable index, increment method
\ count if not an override, create header and fill in index. Allot code pointer
\ and run :noname
\ ; is overridden to fill in xt returned by :noname
\ --> compiles code to fetch vtable address, offset by index, and execute
\ => looks up xt in the vtable and compiles it directly



user current-class
0 current-class !

\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\ ** L A T E   B I N D I N G
\ Compile the method name, and code to find and
\ execute it at run-time...
\

\ p a r s e - m e t h o d
\ compiles a method name so that it pushes
\ the string base address and count at run-time.

: parse-method  \ name  run: ( -- c-addr u )
    parse-word
    postpone sliteral
; compile-only



: (lookup-method)  { class 2:name -- class 0 | class xt 1 | class xt -1  }
    class  name class cell+ @  ( class c-addr u wid )
    search-wordlist
;

\ l o o k u p - m e t h o d
\ takes a counted string method name from the stack (as compiled
\ by parse-method) and attempts to look this method up in the method list of 
\ the class that's on the stack. If successful, it leaves the class on the stack
\ and pushes the xt of the method. If not, it aborts with an error message.

: lookup-method  { class 2:name -- class xt }
    class name (lookup-method)    ( 0 | xt 1 | xt -1 )
    0= if
        name type ."  not found in " 
        class body> >name type
        cr abort 
    endif 
;

: find-method-xt   \ name ( class -- class xt )
    parse-word lookup-method
;

: catch-method  ( instance class c-addr u -- <method-signature> exc-flag )
    lookup-method catch
;

: exec-method  ( instance class c-addr u -- <method-signature> )
    lookup-method execute
;

\ Method lookup operator takes a class-addr and instance-addr
\ and executes the method from the class's wordlist if
\ interpreting. If compiling, bind late.
\
: -->   ( instance class -- ??? )
    state @ 0= if
        find-method-xt execute 
    else  
        parse-method  postpone exec-method
    endif
; immediate

\ Method lookup with CATCH in case of exceptions
: c->   ( instance class -- ?? exc-flag )
    state @ 0= if
        find-method-xt catch  
    else  
        parse-method  postpone catch-method
    endif
; immediate

\ METHOD  makes global words that do method invocations by late binding
\ in case you prefer this style (no --> in your code)
\ Example: everything has next and prev for array access, so...
\ method next
\ method prev
\ my-instance next ( does whatever next does to my-instance by late binding )

: method   create does> body> >name lookup-method execute ;


\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\ ** E A R L Y   B I N D I N G
\ Early binding operator compiles code to execute a method
\ given its class at compile time. Classes are immediate,
\ so they leave their cell-pair on the stack when compiling.
\ Example: 
\   : get-wid   metaclass => .wid @ ;
\ Usage
\   my-class get-wid  ( -- wid-of-my-class )
\
1 ficl-named-wordlist instance-vars
instance-vars dup >search ficl-set-current

: =>   \ c:( class meta -- ) run: ( -- ??? ) invokes compiled method
    drop find-method-xt compile, drop
; immediate compile-only

: my=>   \ c:( -- ) run: ( -- ??? ) late bind compiled method of current-class
    current-class @ dup postpone =>
; immediate compile-only

\ Problem: my=[ assumes that each method except the last is am obj: member
\ which contains its class as the first field of its parameter area. The code
\ detects non-obect members and assumes the class does not change in this case.
\ This handles methods like index, prev, and next correctly, but does not deal
\ correctly with CLASS.
: my=[   \ same as my=> , but binds a chain of methods
    current-class @  
    begin 
        parse-word 2dup             ( class c-addr u c-addr u )
        s" ]" compare while         ( class c-addr u )
        lookup-method               ( class xt )
        dup compile,                ( class xt )
        dup ?object if        \ If object member, get new class. Otherwise assume same class
           nip >body cell+ @        ( new-class )
        else 
           drop                     ( class )
        endif
    repeat 2drop drop 
; immediate compile-only


\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\ ** I N S T A N C E   V A R I A B L E S
\ Instance variables (IV) are represented by words in the class's
\ private wordlist. Each IV word contains the offset
\ of the IV it represents, and runs code to add that offset
\ to the base address of an instance when executed.
\ The metaclass SUB method, defined below, leaves the address
\ of the new class's offset field and its initial size on the
\ stack for these words to update. When a class definition is
\ complete, END-CLASS saves the final size in the class's size
\ field, and restores the search order and compile wordlist to
\ prior state. Note that these words are hidden in their own
\ wordlist to prevent accidental use outside a SUB END-CLASS pair.
\
: do-instance-var
    does>   ( instance class addr[offset] -- addr[field] )
        nip @ +
;

: addr-units:  ( offset size "name" -- offset' )
    create over , + 
    do-instance-var
;

: chars:    \ ( offset nCells "name" -- offset' ) Create n char member.
   chars addr-units: ;

: char:     \ ( offset nCells "name" -- offset' ) Create 1 char member.
   1 chars: ;

: cells:  ( offset nCells "name" -- offset' )
    cells >r aligned r> addr-units:
;

: cell:   ( offset nCells "name" -- offset' )
    1 cells: ;

\ Aggregate an object into the class...
\ Needs the class of the instance to create
\ Example: object obj: m_obj
\
: do-aggregate
    objectify
    does>   ( instance class pfa -- a-instance a-class )
    2@          ( inst class a-class a-offset )
    2swap drop  ( a-class a-offset inst )
    + swap      ( a-inst a-class )
;

: obj:   { offset class meta -- offset' }  \ "name" 
    create  offset , class , 
    class meta --> get-size  offset +
    do-aggregate
;

\ Aggregate an array of objects into a class
\ Usage example:
\ 3 my-class array: my-array
\ Makes an instance variable array of 3 instances of my-class
\ named my-array.
\
: array:   ( offset n class meta "name" -- offset' )
    locals| meta class nobjs offset |
    create offset , class , 
    class meta --> get-size  nobjs * offset + 
    do-aggregate
;

\ Aggregate a pointer to an object: REF is a member variable
\ whose class is set at compile time. This is useful for wrapping
\ data structures in C, where there is only a pointer and the type
\ it refers to is known. If you want polymorphism, see c_ref
\ in classes.fr. REF is only useful for pre-initialized structures,
\ since there's no supported way to set one.
: ref:   ( offset class meta "name" -- offset' )
    locals| meta class offset |
    create offset , class ,
    offset cell+
    does>    ( inst class pfa -- ptr-inst ptr-class )
    2@       ( inst class ptr-class ptr-offset )
    2swap drop + @ swap
;

\ #if FICL_WANT_VCALL
\ vcall extensions contributed by Guy Carver
: vcall:  ( paramcnt "name" -- )   
    current-class @ 8 + dup @ dup 1+ rot !  \ Kludge fix to get to .vtCount before it's defined.
    create , ,                              \ ( paramcnt index -- )
    does>                                   \ ( inst class pfa -- ptr-inst ptr-class )
   nip 2@ vcall                             \ ( params offset inst class offset -- )
;

: vcallr: 0x80000000 or vcall: ;            \ Call with return address desired.

\ #if FICL_WANT_FLOAT
: vcallf:                                   \ ( paramcnt -<name>- f: r )
    0x80000000 or 
    current-class @ 8 + dup @ dup 1+ rot !  \ Kludge fix to get to .vtCount before it's defined.
    create , ,                              \ ( paramcnt index -- )
    does>                                   \ ( inst class pfa -- ptr-inst ptr-class )
    nip 2@ vcall f>                         \ ( params offset inst class offset -- f: r )
;
\ #endif /* FLOAT */
\ #endif /* VCALL */

\ END-CLASS terminates construction of a class by storing
\  the size of its instance variables in the class's size field
\ ( -- old-wid addr[size] 0 )
\
: end-class  ( old-wid addr[size] size -- )
    swap ! set-current 
    search> drop        \ pop struct builder wordlist
;

\ See resume-class (a metaclass method) below for usage
\ This is equivalent to end-class for now, but that will change
\ when we support vtable bindings.
: suspend-class  ( old-wid addr[size] size -- )   end-class ;

set-current previous
\ E N D   I N S T A N C E   V A R I A B L E S


\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\ D O - D O - I N S T A N C E
\ Makes a class method that contains the code for an 
\ instance of the class. This word gets compiled into
\ the wordlist of every class by the SUB method.
\ PRECONDITION: current-class contains the class address
\ why use a state variable instead of the stack?
\ >> Stack state is not well-defined during compilation (there are
\ >> control structure match codes on the stack, of undefined size
\ >> easiest way around this is use of this thread-local variable
\
: do-do-instance  ( -- )
    s" : .do-instance does> [ current-class @ ] literal ;" 
    evaluate 
;

\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\ ** M E T A C L A S S 
\ Every class is an instance of metaclass. This lets
\ classes have methods that are different from those
\ of their instances.
\ Classes are IMMEDIATE to make early binding simpler
\ See above...
\
:noname
    wordlist
    create  
    immediate
    0       ,   \ NULL parent class
    dup     ,   \ wid
\ #if FICL_WANT_VCALL
    4 cells ,   \ instance size 
\ #else
    3 cells ,   \ instance size 
\ #endif
    ficl-set-current
    does> dup
;  execute metaclass 
\ now brand OBJECT's wordlist (so that ORDER can display it by name)
metaclass drop cell+ @ brand-wordlist

metaclass drop current-class !
do-do-instance

\
\ C L A S S   M E T H O D S
\
instance-vars >search

create .super  ( class metaclass -- parent-class )
    0 cells , do-instance-var 

create .wid    ( class metaclass -- wid ) \ return wid of class
    1 cells , do-instance-var 

\ #if FICL_WANT_VCALL
create .vtCount   \ Number of VTABLE methods, if any
    2 cells , do-instance-var 

create  .size  ( class metaclass -- size ) \ return class's payload size 
    3 cells , do-instance-var 
\ #else
create  .size  ( class metaclass -- size ) \ return class's payload size 
    2 cells , do-instance-var 
\ #endif

: get-size    metaclass => .size  @ ;
: get-wid     metaclass => .wid   @ ;
: get-super   metaclass => .super @ ;
\ #if FICL_WANT_VCALL
: get-vtCount metaclass => .vtCount @ ;
: get-vtAdd   metaclass => .vtCount ;
\ #endif

\ create an uninitialized instance of a class, leaving
\ the address of the new instance and its class
\
: instance   ( class metaclass "name" -- instance class )
    locals| meta parent |
    create
    here parent --> .do-instance \ ( inst class )
    parent meta metaclass => get-size 
    allot                        \ allocate payload space
;

\ create an uninitialized array
: array   ( n class metaclass "name" -- n instance class ) 
    locals| meta parent nobj |
    create  nobj
    here parent --> .do-instance \ ( nobj inst class )
    parent meta metaclass => get-size
    nobj *  allot           \ allocate payload space
;

\ create an initialized instance
\
: new   \ ( class metaclass "name" -- ) 
    metaclass => instance --> init
;

\ create an initialized array of instances
: new-array   ( n class metaclass "name" -- ) 
    metaclass => array 
    --> array-init
;

\ Create an anonymous initialized instance from the heap
: alloc   \ ( class metaclass -- instance class )
    locals| meta class |
    class meta metaclass => get-size allocate   ( -- addr fail-flag )
    abort" allocate failed "                    ( -- addr )
    class 2dup --> init
;

\ Create an anonymous array of initialized instances from the heap
: alloc-array   \ ( n class metaclass -- instance class )
    locals| meta class nobj |
    class meta metaclass => get-size 
    nobj * allocate                 ( -- addr fail-flag )
    abort" allocate failed "        ( -- addr )
    nobj over class --> array-init
    class 
;

\ Create an anonymous initialized instance from the dictionary
: allot   { 2:this -- 2:instance }
    here   ( instance-address )
    this my=> get-size  allot
    this drop 2dup --> init
;

\ Create an anonymous array of initialized instances from the dictionary
: allot-array   { nobj 2:this -- 2:instance }
    here   ( instance-address )
    this my=> get-size  nobj * allot
    this drop 2dup     ( 2instance 2instance )
    nobj -rot --> array-init
;

\ create a proxy object with initialized payload address given
: ref   ( instance-addr class metaclass "name" -- )
    drop create , ,
    does> 2@ 
;

\ suspend-class and resume-class help to build mutually referent classes.
\ Example: 
\ object subclass c-akbar
\ suspend-class   ( put akbar on hold while we define jeff )
\ object subclass c-jeff
\     c-akbar ref: .akbar
\     ( and whatever else comprises this class )
\ end-class    ( done with c-jeff )
\ c-akbar --> resume-class
\     c-jeff ref: .jeff
\     ( and whatever else goes in c-akbar )
\ end-class    ( done with c-akbar )
\
: resume-class   { 2:this -- old-wid addr[size] size }
    this --> .wid @ ficl-set-current  ( old-wid )
    this --> .size dup @   ( old-wid addr[size] size )
    instance-vars >search
;

\ create a subclass
\ This method leaves the stack and search order ready for instance variable
\ building. Pushes the instance-vars wordlist onto the search order,
\ and sets the compilation wordlist to be the private wordlist of the
\ new class. The class's wordlist is deliberately NOT in the search order -
\ to prevent methods from getting used with wrong data.
\ Postcondition: leaves the address of the new class in current-class
: sub   ( class metaclass "name" -- old-wid addr[size] size )
    wordlist
    locals| wid meta parent |
    parent meta metaclass => get-wid
    wid wid-set-super       \ set superclass
    create  immediate       \ get the  subclass name
    wid brand-wordlist      \ label the subclass wordlist
    here current-class !    \ prep for do-do-instance
    parent ,                \ save parent class
    wid    ,                \ save wid
\ #if FICL_WANT_VCALL
    parent meta --> get-vtCount , 
\ #endif
    here parent meta --> get-size dup ,  ( addr[size] size )
    metaclass => .do-instance
    wid ficl-set-current -rot
    do-do-instance
    instance-vars >search \ push struct builder wordlist
;

\ OFFSET-OF returns the offset of an instance variable
\ from the instance base address. If the next token is not
\ the name of in instance variable method, you get garbage
\ results -- there is no way at present to check for this error.
: offset-of   ( class metaclass "name" -- offset )
    drop find-method-xt nip >body @ ;

\ ID returns the string name cell-pair of its class
: id   ( class metaclass -- c-addr u )
    drop body> >name  ;

\ list methods of the class
: methods \ ( class meta -- ) 
    locals| meta class |
    begin
        class body> >name type ."  methods:" cr 
        class meta --> get-wid >search words cr previous 
        class meta metaclass => get-super
        dup to class
    0= until  cr
;

\ list class's ancestors
: pedigree  ( class meta -- )
    locals| meta class |
    begin
        class body> >name type space
        class meta metaclass => get-super
        dup to class
    0= until  cr
;

\ decompile an instance method
: see  ( class meta -- )   
    metaclass => get-wid >search see previous ;

\ debug a method of metaclass
\ Eg: my-class --> debug my-method
: debug  ( class meta -- )
	find-method-xt debug-xt ;

previous set-current    
\ E N D   M E T A C L A S S

\ ** META is a nickname for the address of METACLASS...
metaclass drop  
constant meta

\ ** SUBCLASS is a nickname for a class's SUB method...
\ Subclass compilation ends when you invoke end-class
\ This method is late bound for safety...
: subclass   --> sub ;

\ #if FICL_WANT_VCALL
\ VTABLE Support extensions (Guy Carver)
\ object --> sub mine hasvtable
: hasvtable 4 + ; immediate
\ #endif


\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\ ** O B J E C T
\ Root of all classes
:noname
    wordlist
    create  immediate
    0       ,   \ NULL parent class
    dup     ,   \ wid
    0       ,   \ instance size 
    ficl-set-current
    does> meta
;  execute object
\ now brand OBJECT's wordlist (so that ORDER can display it by name)
object drop cell+ @ brand-wordlist

object drop current-class ! 
do-do-instance
instance-vars >search

\ O B J E C T   M E T H O D S
\ Convert instance cell-pair to class cell-pair
\ Useful for binding class methods from an instance
: class  ( instance class -- class metaclass )
    nip meta ;

\ default INIT method zero fills an instance
: init   ( instance class -- )
    meta 
    metaclass => get-size   ( inst size )
    erase ;

\ Apply INIT to an array of NOBJ objects...
\
: array-init   ( nobj inst class -- )
    0 dup locals| &init &next class inst |
    \
    \ bind methods outside the loop to save time
    \
    class s" init" lookup-method to &init
          s" next" lookup-method to &next
    drop
    0 ?do 
        inst class 2dup 
        &init execute
        &next execute  drop to inst
    loop
;

\ free storage allocated to a heap instance by alloc or alloc-array
\ NOTE: not protected against errors like FREEing something that's
\ really in the dictionary.
: free   \ ( instance class -- )
    drop free 
    abort" free failed "
;

\ Instance aliases for common class methods
\ Upcast to parent class
: super     ( instance class -- instance parent-class )
    meta  metaclass => get-super ;

: pedigree  ( instance class -- )
    object => class 
    metaclass => pedigree ;

: size      ( instance class -- sizeof-instance )
    object => class 
    metaclass => get-size ;

: methods   ( instance class -- )
    object => class 
    metaclass => methods ;

\ Array indexing methods...
\ Usage examples:
\ 10 object-array --> index
\ obj --> next
\
: index   ( n instance class -- instance[n] class )
    locals| class inst |
    inst class 
    object => class
    metaclass => get-size  *   ( n*size )
    inst +  class ;

: next   ( instance[n] class -- instance[n+1] class )
    locals| class inst |
    inst class 
    object => class
    metaclass => get-size 
    inst +
    class ;

: prev   ( instance[n] class -- instance[n-1] class )
    locals| class inst |
    inst class 
    object => class
    metaclass => get-size
    inst swap -
    class ;

: debug   ( 2this --  ?? )
    find-method-xt debug-xt ;

previous set-current
\ E N D   O B J E C T

\ reset to default search order
only definitions

\ redefine oop in default search order to put OOP words in the search order and make them
\ the compiling wordlist...

: oo   only also oop definitions ;

\ #endif