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