\ http://home.netsurf.de/helge.horch/hype.html
\ upgrade by:
\ (c) Dmitry Yakimov 2006, support@activekitten.com
REQUIRE WL-MODULES ~day\lib\includemodule.f
NEEDED: [IF] lib\include\tools.f
NEEDS lib\ext\vocs.f
MODULE: HYPE
0
CELL -- .self
CELL -- .size
CELL -- .wl
CELL -- .super
CELL -- .nfa
CELL -- .objchain
CONSTANT /class
USER-VALUE SELF
\ For nested objects
USER ALLOC-XT
USER FREE-XT
: SELF+ ( n - a) SELF + ;
: (SEND) ( a xt) SELF >R SWAP TO SELF EXECUTE R> TO SELF ;
VARIABLE CLS ( contains ta -> |size|wid|super|)
VARIABLE PREVIOUS-CURRENT
: CLASS@ ( - aa) CLS @ ?DUP 0= ABORT" Use in CLASS ;CLASS statements" ;
: OBJ-SIZE CLASS@ .size @ ;
: MFIND ( ta c-addr u - ta c-addr u 0 | xt 1 | xt -1 )
ROT DUP >R
ROT ROT 2>R
BEGIN
DUP
WHILE
DUP .wl @ 2R@
ROT SEARCH-WORDLIST ?DUP IF ROT 2R> R> 2DROP 2DROP EXIT THEN
.super @
REPEAT
DROP 2R> R> ROT ROT 0
;
: SEND ( a ta addr u )
MFIND
IF (SEND)
ELSE 2SWAP S" unknown" RECURSE
THEN
;
: MFIND-ERR ( ta c-addr u - xt 1 | xt -1 | abort )
MFIND ?DUP 0=
IF
ROT DUP S" unknown" SEND
THEN
;
: SEND, ( a ta addr u )
MFIND-ERR DROP SWAP LIT, LIT, POSTPONE (SEND)
;
: ALIGN-CUSTOM ( n -- )
\ выравивает CLASS@ на n
OBJ-SIZE SWAP 2DUP MOD
DUP IF - + CLASS@ .size ! ELSE 2DROP DROP THEN
;
VARIABLE AlignFields?
: AlignDefs ( n -- )
AlignFields? @ 0= IF DROP EXIT THEN
DUP 1 = OVER 2 = OR IF DROP 2 ALIGN-CUSTOM EXIT THEN
DUP 4 = SWAP 7 > OR IF 4 ALIGN-CUSTOM EXIT THEN
;
: AddOp
HOLDS DROP R> DROP
;
: CompileOp ( n )
DUP 8 = IF S" 2" AddOp THEN
DUP 4 = IF DROP EXIT THEN
DUP 2 = IF S" W" AddOp THEN
DUP 1 = IF S" C" AddOp THEN
-1 ABORT" wrong size"
;
: CHOLD:
CREATE
C,
DOES> C@ HOLD
;
CHAR ! CHOLD: !#
CHAR @ CHOLD: @#
BL CHOLD: BL#
: CompileProperty ( n addr u )
ROT >R
<#
S" ;" HOLDS
@# R@ CompileOp
BL#
2DUP HOLDS BL#
@# 2DUP HOLDS
S" : " HOLDS
BL#
S" ;" HOLDS
!# R@ CompileOp
BL#
2DUP HOLDS BL#
!# HOLDS
S" : " HOLDS
0.
#> EVALUATE
R> DROP
;
: TO-CONTEXT ( wl ) >R GET-ORDER R> SWAP 1+ SET-ORDER ;
: GET-CONTEXT ( -- wl ) GET-ORDER SWAP >R 1- 0 ?DO DROP LOOP R> ;
: METHODS ( ta)
DUP CLS ! .wl @ DUP SET-CURRENT
TO-CONTEXT ;
CREATE FIRST-OBJCHAIN
0 ,
0 ,
0 ,
: (CLASS) ( n "c ")
GET-CURRENT PREVIOUS-CURRENT !
-1 AlignFields? !
CREATE HERE
SWAP ALLOT
DUP DUP .self !
CELL OVER .size ! \ pointer to class
WORDLIST OVER .wl !
\ make this wordlist named for better debug output
LATEST OVER .wl @ CELL+ !
0 OVER .super !
LATEST OVER .nfa !
FIRST-OBJCHAIN OVER .objchain !
METHODS
;
: CLASS /class (CLASS) ;
: ;CLASS ( )
CLASS@ DROP PREVIOUS PREVIOUS-CURRENT @ SET-CURRENT
4 ALIGN-CUSTOM \ for array of objects on data-align aware platforms
0 CLS !
;
: ^ ( obj "word" )
STATE @
IF
POSTPONE DUP
POSTPONE @
PARSE-NAME
POSTPONE SLITERAL
POSTPONE SEND
ELSE DUP @ PARSE-NAME SEND
THEN
; IMMEDIATE
: (') ( a addr u -- xt )
2>R @ 2R>
MFIND-ERR ( xt n )
DROP
;
: ^' ( obj "word" )
BL PARSE
STATE @
IF
POSTPONE SLITERAL
POSTPONE (')
ELSE (')
THEN
; IMMEDIATE
: CLASS-HAS-NESTED-OBJECTS ( ta )
.objchain @ FIRST-OBJCHAIN = 0=
;
\ For static objects we use only ^ dispose
: FreeNestedObjects ( obj ta )
DUP CLASS-HAS-NESTED-OBJECTS
IF
OVER >R DUP .objchain
BEGIN
@ DUP @
WHILE
DUP CELL+ CELL+ @ ( size ) R@ +
DUP @ FREE-XT @ EXECUTE THROW 0!
REPEAT R> 2DROP
.super @ DUP
IF
RECURSE
ELSE 2DROP
THEN
ELSE 2DROP
THEN
;
: FreeObjWith ( obj xt )
DUP FREE-XT !
OVER ^ dispose
OVER DUP @ FreeNestedObjects
EXECUTE THROW
;
: AllocObjWith ( ta xt -- addr )
OVER .size @ TUCK SWAP EXECUTE THROW ( ta size addr )
TUCK SWAP ERASE
TUCK !
;
: NewObjWith ( ta xt )
DUP ALLOC-XT !
AllocObjWith
DUP ^ init
;
\ We can safely combine initializing and allocating steps
: INIT-OBJ-CHAIN ( a-chain )
BEGIN
@ DUP @
WHILE
DUP CELL+ @ ALLOC-XT @ NewObjWith ( obj )
OVER CELL+ CELL+ @ SELF+ !
REPEAT DROP
;
: OBJ@ ( obj-data -- obj )
2 CELLS + @ SELF+ @
;
: DISPOSE-OBJ-CHAIN ( a-chain )
BEGIN
@ DUP @
WHILE
DUP OBJ@ ^ dispose
REPEAT DROP
;
: INIT-SUBOBJECTS
CLASS@ CLASS-HAS-NESTED-OBJECTS
IF
CLASS@ .objchain
POSTPONE LITERAL
['] INIT-OBJ-CHAIN COMPILE,
THEN
; IMMEDIATE
: DISPOSE-SUBOBJECTS
CLASS@ CLASS-HAS-NESTED-OBJECTS
IF
CLASS@ .objchain
POSTPONE LITERAL
['] DISPOSE-OBJ-CHAIN COMPILE,
THEN
; IMMEDIATE
: SUPER ( "m ")
CLASS@ .super @ BL WORD COUNT MFIND-ERR 0<
IF COMPILE, ELSE EXECUTE THEN ; IMMEDIATE
: init: S" : init HYPE::INIT-SUBOBJECTS SUPER init" EVALUATE ;
\ destructors are called in inverse order
VOCABULARY HypeDisposeVoc
GET-CURRENT ALSO HypeDisposeVoc DEFINITIONS
: ; S" HYPE::DISPOSE-SUBOBJECTS SUPER dispose " EVALUATE PREVIOUS S" ;" EVAL-WORD ; IMMEDIATE
PREVIOUS SET-CURRENT
: dispose: S" : dispose [ ALSO HypeDisposeVoc ] " EVALUATE ;
CLASS MetaClass
: this SELF ( -- obj ) ;
: class ( -- ta ) SELF @ ;
: isClass ( -- f ) class SELF = ;
: also ( -- ) SELF @ .wl @ TO-CONTEXT ;
\ save\load objects
: name ( -- addr u ) SELF @ .nfa @ COUNT ;
: size ( -- u ) SELF @ .size @ ;
: methods.
SELF
BEGIN
@ DUP
WHILE
DUP ^ name <# [CHAR] : HOLD HOLDS S" Methods of " HOLDS 0. #> TYPE CR
DUP .wl @ NLIST CR
.super
REPEAT DROP
;
: returnStack. ( n )
\ n cells to skip
3 +
." OBJECTS RETURN STACK:" CR
12 0 DO
DUP I + CELLS RP+ @
DUP NEAR_NFA DROP VocByNFA ?DUP
IF VOC-NAME. ." ::" THEN
WordByAddr TYPE CR
LOOP DROP
;
: abort ( f addr u )
ROT
IF
1 returnStack.
<# R@ WordByAddr HOLDS [CHAR] . HOLD name HOLDS S" in " HOLDS HOLDS 0. #>
TUCK PAD SWAP CMOVE
PAD SWAP
ER-U ! ER-A ! -2 THROW
ELSE 2DROP
THEN
;
: unknown ( addr u )
<# name HOLDS S" in class " HOLDS HOLDS S" can't find method " HOLDS 0. #>
TUCK PAD SWAP CMOVE PAD SWAP ER-U ! ER-A !
-2 THROW
;
;CLASS
: (SUBCLASS)
CLASS@ ( ta ca )
OVER .size @ OVER .size !
.super !
;
: SUBCLASS ( ta "c ")
CLASS (SUBCLASS)
;
MetaClass SUBCLASS ProtoObj
: init ;
: dispose ;
: freenested
\ FREE-XT should be set
SELF DUP @ FreeNestedObjects
;
;CLASS
: DEFINED-IN-CLASS ( addr u ta )
.wl @ SEARCH-WORDLIST DUP
IF NIP THEN
;
: ZALLOT ( n -- addr ior )
HERE OVER ALLOT ( n addr )
TUCK SWAP ERASE 0
;
: CLASS-EMPTY-DISPOSE? ( ta -- f )
S" dispose" MFIND-ERR DROP
ProtoObj S" dispose" MFIND-ERR DROP =
;
EXPORT
: CLASS ProtoObj SUBCLASS ;
: SUBCLASS SUBCLASS ;
: DEFS ( n "f ")
CREATE DUP AlignDefs OBJ-SIZE , CLASS@ .size +!
DOES> @ SELF+
;
: PROPERTY ( n "f ")
DUP >IN @ >R
DEFS R> >IN !
BL PARSE CompileProperty
;
: (send-obj) ( xt shift )
SELF+ @ SWAP (SEND)
;
: (enter-subobject) ( shift -- R: prev-self )
SELF SWAP SELF+ @ TO SELF
R> SWAP >R >R
;
: (enter-subobject0) ( obj -- R: prev-self )
SELF SWAP TO SELF
R> SWAP >R >R
;
: (exit-subobject)
R> R> TO SELF >R
;
\ with support of syntax: var var var prop
: OBJ-SEND, ( class shift addr u )
2>R SWAP 2R> MFIND-ERR
STATE @
IF \ compilation
-1 = ( shift xt )
IF \ nonimmediate
LIT, LIT,
['] (send-obj) COMPILE,
ELSE \ again object
( shift xt )
SWAP LIT,
['] (enter-subobject) COMPILE,
EXECUTE
['] (exit-subobject) COMPILE,
THEN
ELSE
DROP SWAP (send-obj)
THEN
;
: OBJ ( ta "f" )
CREATE HERE IMMEDIATE
CLASS@ .objchain @ , ( prev obj in chain )
CLASS@ .objchain !
, CELL AlignDefs OBJ-SIZE ,
CELL CLASS@ .size +!
DOES> DUP CELL+ @ ( chain class )
SWAP CELL+ CELL+ @ ( shift )
PARSE-NAME OBJ-SEND,
;
: VAR 1 CELLS DEFS ;
: ;CLASS
\ default constructor and destructor to initialize
\ and destroy objects-attributes
CLASS@ CLASS-HAS-NESTED-OBJECTS
IF
S" init" CLASS@ DEFINED-IN-CLASS 0=
IF
S" init: ; " EVALUATE
THEN
S" dispose" CLASS@ DEFINED-IN-CLASS 0=
IF
S" dispose: ; " EVALUATE
THEN
THEN
;CLASS
;
: CompileDeferredStatic ( a ta "name" )
PARSE-NAME MFIND-ERR
STATE @ 0=
IF
DROP (SEND)
ELSE
-1 = \ var or method
IF
LIT, POSTPONE (SEND)
ELSE \ [obj] var-xt
\ owner.child method
>BODY CELL+ DUP @ ( class ) SWAP CELL+ @ LIT, ( shift )
POSTPONE +
POSTPONE @
RECURSE
THEN
THEN
;
: :: ( obj "word" )
[CHAR] . WORD FIND 0= IF ABORT" can't find class name!" THEN
EXECUTE ( ta )
CompileDeferredStatic
; IMMEDIATE
VOCABULARY HypeSupport
GET-CURRENT
ALSO HypeSupport DEFINITIONS
: }} PREVIOUS PREVIOUS ; IMMEDIATE
SET-CURRENT PREVIOUS
\ с with{ не работает subclassing !!!
: with{ ( " class" -- )
' EXECUTE .wl @
ALSO HYPE
TO-CONTEXT
; IMMEDIATE
\ Export some needed words
: OBJ-SIZE OBJ-SIZE ;
: ^ POSTPONE ^ ; IMMEDIATE
\ ^ is used in SPF4 locals
: => POSTPONE ^ ; IMMEDIATE
: SUPER POSTPONE SUPER ; IMMEDIATE
: init: init: ;
: dispose: dispose: ;
: SELF POSTPONE SELF ; IMMEDIATE
: NewObj ( ta -- addr )
['] ALLOCATE NewObjWith
;
: FreeObj ( obj )
['] FREE FreeObjWith
;
: NEW ( ta "name ")
CREATE ['] ZALLOT NewObjWith DROP IMMEDIATE
DOES> DUP @ ( fetch class )
STATE @ 0= INVERT
IF SWAP LIT,
THEN
CompileDeferredStatic
;
: HypeDisposeVoc HypeDisposeVoc ;
\ Methods inheritance
: INHERIT ( -- )
SMUDGE
LATEST COUNT
CLASS@ .super @
ROT ROT MFIND-ERR DROP COMPILE,
SMUDGE
; IMMEDIATE
: DoNotAlign
0 AlignFields? !
;
;MODULE