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