282 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Factor
		
	
	
			
		
		
	
	
			282 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Factor
		
	
	
! Copyright (C) 2004, 2007 Slava Pestov.
 | 
						|
! See http://factorcode.org/license.txt for BSD license.
 | 
						|
IN: classes
 | 
						|
USING: arrays definitions assocs kernel
 | 
						|
kernel.private slots.private namespaces sequences strings words
 | 
						|
vectors math quotations combinators sorting effects graphs ;
 | 
						|
 | 
						|
PREDICATE: word class ( obj -- ? ) "class" word-prop ;
 | 
						|
 | 
						|
SYMBOL: typemap
 | 
						|
SYMBOL: class<map
 | 
						|
SYMBOL: update-map
 | 
						|
SYMBOL: builtins
 | 
						|
 | 
						|
PREDICATE: word builtin-class
 | 
						|
    "metaclass" word-prop builtin-class eq? ;
 | 
						|
 | 
						|
PREDICATE: class tuple-class
 | 
						|
    "metaclass" word-prop tuple-class eq? ;
 | 
						|
 | 
						|
: classes ( -- seq ) class<map get keys ;
 | 
						|
 | 
						|
: type>class ( n -- class ) builtins get nth ;
 | 
						|
 | 
						|
: predicate-word ( word -- predicate )
 | 
						|
    [ word-name "?" append ] keep word-vocabulary create ;
 | 
						|
 | 
						|
: predicate-effect 1 { "?" } <effect> ;
 | 
						|
 | 
						|
PREDICATE: compound predicate
 | 
						|
    "predicating" word-prop >boolean ;
 | 
						|
 | 
						|
: define-predicate ( class predicate quot -- )
 | 
						|
    over [
 | 
						|
        dupd predicate-effect define-declared
 | 
						|
        2dup 1quotation "predicate" set-word-prop
 | 
						|
        swap "predicating" set-word-prop
 | 
						|
    ] [
 | 
						|
        3drop
 | 
						|
    ] if ;
 | 
						|
 | 
						|
: superclass ( class -- super )
 | 
						|
    "superclass" word-prop ;
 | 
						|
 | 
						|
: members ( class -- seq ) "members" word-prop ;
 | 
						|
 | 
						|
: class-empty? ( class -- ? ) members dup [ empty? ] when ;
 | 
						|
 | 
						|
: (flatten-union-class) ( class -- )
 | 
						|
    dup members [
 | 
						|
        [ (flatten-union-class) ] each
 | 
						|
    ] [
 | 
						|
        dup set
 | 
						|
    ] ?if ;
 | 
						|
 | 
						|
: flatten-union-class ( class -- assoc )
 | 
						|
    [ (flatten-union-class) ] H{ } make-assoc ;
 | 
						|
 | 
						|
: (flatten-class) ( class -- )
 | 
						|
    {
 | 
						|
        { [ dup tuple-class? ] [ dup set ] }
 | 
						|
        { [ dup builtin-class? ] [ dup set ] }
 | 
						|
        { [ dup members ] [ members [ (flatten-class) ] each ] }
 | 
						|
        { [ dup superclass ] [ superclass (flatten-class) ] }
 | 
						|
    } cond ;
 | 
						|
 | 
						|
: flatten-class ( class -- assoc )
 | 
						|
    [ (flatten-class) ] H{ } make-assoc ;
 | 
						|
 | 
						|
: class-hashes ( class -- seq )
 | 
						|
    flatten-class keys [
 | 
						|
        dup builtin-class?
 | 
						|
        [ "type" word-prop ] [ hashcode ] if
 | 
						|
    ] map ;
 | 
						|
 | 
						|
: (flatten-builtin-class) ( class -- )
 | 
						|
    {
 | 
						|
        { [ dup members ] [ members [ (flatten-builtin-class) ] each ] }
 | 
						|
        { [ dup superclass ] [ superclass (flatten-builtin-class) ] }
 | 
						|
        { [ t ] [ dup set ] }
 | 
						|
    } cond ;
 | 
						|
 | 
						|
: flatten-builtin-class ( class -- assoc )
 | 
						|
    [ (flatten-builtin-class) ] H{ } make-assoc ;
 | 
						|
 | 
						|
: types ( class -- seq )
 | 
						|
    flatten-builtin-class keys
 | 
						|
    [ "type" word-prop ] map natural-sort ;
 | 
						|
 | 
						|
: class< ( class1 class2 -- ? ) swap class<map get at key? ;
 | 
						|
 | 
						|
<PRIVATE
 | 
						|
 | 
						|
DEFER: (class<)
 | 
						|
 | 
						|
: superclass< ( cls1 cls2 -- ? )
 | 
						|
    >r superclass r> 2dup and [ (class<) ] [ 2drop f ] if ;
 | 
						|
 | 
						|
: union-class< ( cls1 cls2 -- ? )
 | 
						|
    [ flatten-union-class ] 2apply keys
 | 
						|
    [ nip [ (class<) ] curry* contains? ] curry assoc-all? ;
 | 
						|
 | 
						|
: (class<) ( class1 class2 -- ? )
 | 
						|
    {
 | 
						|
        { [ 2dup eq? ] [ 2drop t ] }
 | 
						|
        { [ over class-empty? ] [ 2drop t ] }
 | 
						|
        { [ 2dup superclass< ] [ 2drop t ] }
 | 
						|
        { [ 2dup [ members not ] both? ] [ 2drop f ] }
 | 
						|
        { [ t ] [ union-class< ] }
 | 
						|
    } cond ;
 | 
						|
 | 
						|
: lookup-union ( classes -- class )
 | 
						|
    typemap get at dup empty? [ drop object ] [ first ] if ;
 | 
						|
 | 
						|
: (class-or) ( class class -- class )
 | 
						|
    [ flatten-builtin-class ] 2apply union lookup-union ;
 | 
						|
 | 
						|
: (class-and) ( class class -- class )
 | 
						|
    [ flatten-builtin-class ] 2apply intersect lookup-union ;
 | 
						|
 | 
						|
: tuple-class-and ( class1 class2 -- class )
 | 
						|
    dupd eq? [ drop null ] unless ;
 | 
						|
 | 
						|
: largest-class ( seq -- n elt )
 | 
						|
    dup [
 | 
						|
        [ 2dup class< >r swap class< not r> and ]
 | 
						|
        curry* subset empty?
 | 
						|
    ] curry find [ "Topological sort failed" throw ] unless* ;
 | 
						|
 | 
						|
: (sort-classes) ( vec -- )
 | 
						|
    dup empty?
 | 
						|
    [ drop ]
 | 
						|
    [ dup largest-class , over delete-nth (sort-classes) ] if ;
 | 
						|
 | 
						|
PRIVATE>
 | 
						|
 | 
						|
: sort-classes ( seq -- newseq )
 | 
						|
    [ >vector (sort-classes) ] { } make ;
 | 
						|
 | 
						|
: class-or ( class1 class2 -- class )
 | 
						|
    {
 | 
						|
        { [ 2dup class< ] [ nip ] }
 | 
						|
        { [ 2dup swap class< ] [ drop ] }
 | 
						|
        { [ t ] [ (class-or) ] }
 | 
						|
    } cond ;
 | 
						|
 | 
						|
: class-and ( class1 class2 -- class )
 | 
						|
    {
 | 
						|
        { [ 2dup class< ] [ drop ] }
 | 
						|
        { [ 2dup swap class< ] [ nip ] }
 | 
						|
        { [ 2dup [ tuple-class? ] both? ] [ tuple-class-and ] }
 | 
						|
        { [ t ] [ (class-and) ] }
 | 
						|
    } cond ;
 | 
						|
 | 
						|
: classes-intersect? ( class1 class2 -- ? )
 | 
						|
    class-and class-empty? not ;
 | 
						|
 | 
						|
: min-class ( class seq -- class/f )
 | 
						|
    [ dupd classes-intersect? ] subset dup empty? [
 | 
						|
        2drop f
 | 
						|
    ] [
 | 
						|
        tuck [ class< ] curry* all? [ peek ] [ drop f ] if
 | 
						|
    ] if ;
 | 
						|
 | 
						|
GENERIC: reset-class ( class -- )
 | 
						|
 | 
						|
M: word reset-class drop ;
 | 
						|
 | 
						|
<PRIVATE
 | 
						|
 | 
						|
! class<map
 | 
						|
: bigger-classes ( class -- seq )
 | 
						|
    classes [ (class<) ] curry* subset ;
 | 
						|
 | 
						|
: bigger-classes+ ( class -- )
 | 
						|
    [ bigger-classes [ dup ] H{ } map>assoc ] keep
 | 
						|
    class<map get set-at ;
 | 
						|
 | 
						|
: bigger-classes- ( class -- )
 | 
						|
    class<map get delete-at ;
 | 
						|
 | 
						|
: smaller-classes ( class -- seq )
 | 
						|
    classes swap [ (class<) ] curry subset ;
 | 
						|
 | 
						|
: smaller-classes+ ( class -- )
 | 
						|
    dup smaller-classes class<map get add-vertex ;
 | 
						|
 | 
						|
: smaller-classes- ( class -- )
 | 
						|
    dup smaller-classes class<map get remove-vertex ;
 | 
						|
 | 
						|
: class<map+ ( class -- )
 | 
						|
    H{ } clone over class<map get set-at
 | 
						|
    dup smaller-classes+ bigger-classes+ ;
 | 
						|
 | 
						|
: class<map- ( class -- )
 | 
						|
    dup smaller-classes- bigger-classes- ;
 | 
						|
 | 
						|
! update-map
 | 
						|
: class-uses ( class -- seq )
 | 
						|
    [ dup members % superclass [ , ] when* ] { } make ;
 | 
						|
 | 
						|
: class-usages ( class -- assoc )
 | 
						|
    [ update-map get at ] closure ;
 | 
						|
 | 
						|
: update-map+ ( class -- )
 | 
						|
    dup class-uses update-map get add-vertex ;
 | 
						|
 | 
						|
: update-map- ( class -- )
 | 
						|
    dup class-uses update-map get remove-vertex ;
 | 
						|
 | 
						|
! typemap
 | 
						|
: push-at ( value key assoc -- )
 | 
						|
    2dup at* [
 | 
						|
        2nip push
 | 
						|
    ] [
 | 
						|
        drop >r >r 1vector r> r> set-at
 | 
						|
    ] if ;
 | 
						|
 | 
						|
: typemap+ ( class -- )
 | 
						|
    dup flatten-builtin-class typemap get push-at ;
 | 
						|
 | 
						|
: pop-at ( value key assoc -- )
 | 
						|
    at* [ delete ] [ 2drop ] if ;
 | 
						|
 | 
						|
: typemap- ( class -- )
 | 
						|
    dup flatten-builtin-class typemap get pop-at ;
 | 
						|
 | 
						|
! Class definition
 | 
						|
: cache-class ( class -- )
 | 
						|
    dup typemap+ dup class<map+ update-map+ ;
 | 
						|
 | 
						|
: cache-classes ( assoc -- )
 | 
						|
    [ drop cache-class ] assoc-each ;
 | 
						|
 | 
						|
GENERIC: uncache-class ( class -- )
 | 
						|
 | 
						|
M: class uncache-class
 | 
						|
    dup update-map- dup class<map- typemap- ;
 | 
						|
 | 
						|
M: word uncache-class drop ;
 | 
						|
 | 
						|
: uncache-classes ( assoc -- )
 | 
						|
    [ drop uncache-class ] assoc-each ;
 | 
						|
 | 
						|
GENERIC: update-methods ( class -- )
 | 
						|
 | 
						|
PRIVATE>
 | 
						|
 | 
						|
: define-class-props ( members superclass metaclass -- assoc )
 | 
						|
    [
 | 
						|
        "metaclass" set
 | 
						|
        dup [ bootstrap-word ] when "superclass" set
 | 
						|
        [ bootstrap-word ] map "members" set
 | 
						|
    ] H{ } make-assoc ;
 | 
						|
 | 
						|
: (define-class) ( word props -- )
 | 
						|
    over reset-class
 | 
						|
    >r dup word-props r> union over set-word-props
 | 
						|
    dup intern-symbol
 | 
						|
    t "class" set-word-prop ;
 | 
						|
 | 
						|
: define-class ( word members superclass metaclass -- )
 | 
						|
    #! If it was already a class, update methods after.
 | 
						|
    define-class-props
 | 
						|
    over class? >r
 | 
						|
    over class-usages [
 | 
						|
        uncache-classes
 | 
						|
        dupd (define-class)
 | 
						|
    ] keep cache-classes
 | 
						|
    r> [ update-methods ] [ drop ] if ;
 | 
						|
 | 
						|
GENERIC: class ( object -- class ) inline
 | 
						|
 | 
						|
M: object class type type>class ;
 | 
						|
 | 
						|
<PRIVATE
 | 
						|
 | 
						|
: class-of-tuple ( obj -- class )
 | 
						|
    2 slot { word } declare ; inline
 | 
						|
 | 
						|
PRIVATE>
 |