185 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Factor
		
	
	
		
		
			
		
	
	
			185 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Factor
		
	
	
| 
								 | 
							
								! Copyright (C) 2005, 2007 Slava Pestov.
							 | 
						||
| 
								 | 
							
								! See http://factorcode.org/license.txt for BSD license.
							 | 
						||
| 
								 | 
							
								USING: arrays assocs kernel kernel.private slots.private math
							 | 
						||
| 
								 | 
							
								namespaces sequences vectors words quotations definitions
							 | 
						||
| 
								 | 
							
								hashtables layouts combinators combinators.private generic
							 | 
						||
| 
								 | 
							
								classes classes.private ;
							 | 
						||
| 
								 | 
							
								IN: generic.standard
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								TUPLE: standard-combination # ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								C: <standard-combination> standard-combination
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								SYMBOL: (dispatch#)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: (picker) ( n -- quot )
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								        { 0 [ [ dup ] ] }
							 | 
						||
| 
								 | 
							
								        { 1 [ [ over ] ] }
							 | 
						||
| 
								 | 
							
								        { 2 [ [ pick ] ] }
							 | 
						||
| 
								 | 
							
								        [ 1- (picker) [ >r ] swap [ r> swap ] 3append ]
							 | 
						||
| 
								 | 
							
								    } case ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: picker ( -- quot ) \ (dispatch#) get (picker) ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: unpickers { [ nip ] [ >r nip r> swap ] [ >r >r nip r> r> -rot ] } ; inline
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: unpicker ( -- quot ) \ (dispatch#) get unpickers nth ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								TUPLE: no-method object generic ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: no-method ( object generic -- * )
							 | 
						||
| 
								 | 
							
								    \ no-method construct-boa throw ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: error-method ( word -- method )
							 | 
						||
| 
								 | 
							
								    picker swap [ no-method ] curry append ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: empty-method ( word -- method )
							 | 
						||
| 
								 | 
							
								    [
							 | 
						||
| 
								 | 
							
								        picker % [ delegate dup ] %
							 | 
						||
| 
								 | 
							
								        unpicker over add ,
							 | 
						||
| 
								 | 
							
								        error-method \ drop add* , \ if ,
							 | 
						||
| 
								 | 
							
								    ] [ ] make ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: class-predicates ( assoc -- assoc )
							 | 
						||
| 
								 | 
							
								    [
							 | 
						||
| 
								 | 
							
								        >r >r picker r> "predicate" word-prop append r>
							 | 
						||
| 
								 | 
							
								    ] assoc-map ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: (simplify-alist) ( class i assoc -- default assoc )
							 | 
						||
| 
								 | 
							
								    2dup length 1- = [
							 | 
						||
| 
								 | 
							
								        nth second { } rot drop
							 | 
						||
| 
								 | 
							
								    ] [
							 | 
						||
| 
								 | 
							
								        3dup >r 1+ r> nth first class< [
							 | 
						||
| 
								 | 
							
								            >r 1+ r> (simplify-alist)
							 | 
						||
| 
								 | 
							
								        ] [
							 | 
						||
| 
								 | 
							
								            [ nth second ] 2keep swap 1+ tail rot drop
							 | 
						||
| 
								 | 
							
								        ] if
							 | 
						||
| 
								 | 
							
								    ] if ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: simplify-alist ( class assoc -- default assoc )
							 | 
						||
| 
								 | 
							
								    dup empty? [
							 | 
						||
| 
								 | 
							
								        2drop [ "Unreachable" throw ] { }
							 | 
						||
| 
								 | 
							
								    ] [
							 | 
						||
| 
								 | 
							
								        0 swap (simplify-alist)
							 | 
						||
| 
								 | 
							
								    ] if ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: default-method ( word -- pair )
							 | 
						||
| 
								 | 
							
								    empty-method object bootstrap-word swap 2array ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: method-alist>quot ( alist base-class -- quot )
							 | 
						||
| 
								 | 
							
								    bootstrap-word swap simplify-alist
							 | 
						||
| 
								 | 
							
								    class-predicates alist>quot ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: small-generic ( methods -- def )
							 | 
						||
| 
								 | 
							
								    object method-alist>quot ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: hash-methods ( methods -- buckets )
							 | 
						||
| 
								 | 
							
								    V{ } clone [
							 | 
						||
| 
								 | 
							
								        tuple bootstrap-word over class< [
							 | 
						||
| 
								 | 
							
								            drop t
							 | 
						||
| 
								 | 
							
								        ] [
							 | 
						||
| 
								 | 
							
								            class-hashes
							 | 
						||
| 
								 | 
							
								        ] if
							 | 
						||
| 
								 | 
							
								    ] distribute-buckets ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: big-generic ( methods -- quot )
							 | 
						||
| 
								 | 
							
								    hash-methods [ small-generic ] map
							 | 
						||
| 
								 | 
							
								    hash-dispatch-quot picker [ class-hash ] rot 3append ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: vtable-class ( n -- class )
							 | 
						||
| 
								 | 
							
								    type>class [ hi-tag bootstrap-word ] unless* ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: group-methods ( assoc -- vtable )
							 | 
						||
| 
								 | 
							
								    #! Input is a predicate -> method association.
							 | 
						||
| 
								 | 
							
								    #! n is vtable size (either num-types or num-tags).
							 | 
						||
| 
								 | 
							
								    num-tags get [
							 | 
						||
| 
								 | 
							
								        vtable-class
							 | 
						||
| 
								 | 
							
								        [ swap first classes-intersect? ] curry subset
							 | 
						||
| 
								 | 
							
								    ] curry* map ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: build-type-vtable ( alist-seq -- alist-seq )
							 | 
						||
| 
								 | 
							
								    dup length [
							 | 
						||
| 
								 | 
							
								        vtable-class swap simplify-alist
							 | 
						||
| 
								 | 
							
								        class-predicates alist>quot
							 | 
						||
| 
								 | 
							
								    ] 2map ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: tag-generic ( methods -- quot )
							 | 
						||
| 
								 | 
							
								    [
							 | 
						||
| 
								 | 
							
								        picker %
							 | 
						||
| 
								 | 
							
								        \ tag ,
							 | 
						||
| 
								 | 
							
								        group-methods build-type-vtable ,
							 | 
						||
| 
								 | 
							
								        \ dispatch ,
							 | 
						||
| 
								 | 
							
								    ] [ ] make ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: flatten-method ( class body -- )
							 | 
						||
| 
								 | 
							
								    over members pick object bootstrap-word eq? not and [
							 | 
						||
| 
								 | 
							
								        >r members r> [ flatten-method ] curry each
							 | 
						||
| 
								 | 
							
								    ] [
							 | 
						||
| 
								 | 
							
								        swap set
							 | 
						||
| 
								 | 
							
								    ] if ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: flatten-methods ( methods -- newmethods )
							 | 
						||
| 
								 | 
							
								    [ [ flatten-method ] assoc-each ] V{ } make-assoc ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: dispatched-types ( methods -- seq )
							 | 
						||
| 
								 | 
							
								    keys object bootstrap-word swap remove prune ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: single-combination ( methods -- quot )
							 | 
						||
| 
								 | 
							
								    dup length 4 <= [
							 | 
						||
| 
								 | 
							
								        small-generic
							 | 
						||
| 
								 | 
							
								    ] [
							 | 
						||
| 
								 | 
							
								        flatten-methods
							 | 
						||
| 
								 | 
							
								        dup dispatched-types [ number class< ] all?
							 | 
						||
| 
								 | 
							
								        [ tag-generic ] [ big-generic ] if
							 | 
						||
| 
								 | 
							
								    ] if ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: standard-methods ( word -- alist )
							 | 
						||
| 
								 | 
							
								    dup methods swap default-method add* ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: standard-combination perform-combination
							 | 
						||
| 
								 | 
							
								    standard-combination-# (dispatch#) [
							 | 
						||
| 
								 | 
							
								        standard-methods single-combination
							 | 
						||
| 
								 | 
							
								    ] with-variable ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: default-hook-method ( word -- pair )
							 | 
						||
| 
								 | 
							
								    error-method object bootstrap-word swap 2array ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: hook-methods ( word -- methods )
							 | 
						||
| 
								 | 
							
								    dup methods [ [ drop ] swap append ] assoc-map
							 | 
						||
| 
								 | 
							
								    swap default-hook-method add* ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								TUPLE: hook-combination var ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								C: <hook-combination> hook-combination
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: hook-combination perform-combination
							 | 
						||
| 
								 | 
							
								    0 (dispatch#) [
							 | 
						||
| 
								 | 
							
								        [
							 | 
						||
| 
								 | 
							
								            hook-combination-var [ get ] curry %
							 | 
						||
| 
								 | 
							
								            hook-methods single-combination %
							 | 
						||
| 
								 | 
							
								        ] [ ] make
							 | 
						||
| 
								 | 
							
								    ] with-variable ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								: define-simple-generic ( word -- )
							 | 
						||
| 
								 | 
							
								    T{ standard-combination f 0 } define-generic ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PREDICATE: generic standard-generic
							 | 
						||
| 
								 | 
							
								    "combination" word-prop standard-combination? ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PREDICATE: standard-generic simple-generic
							 | 
						||
| 
								 | 
							
								    "combination" word-prop standard-combination-# zero? ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								PREDICATE: generic hook-generic
							 | 
						||
| 
								 | 
							
								    "combination" word-prop hook-combination? ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								GENERIC: dispatch# ( word -- n )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: word dispatch# "combination" word-prop dispatch# ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: standard-combination dispatch# standard-combination-# ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: hook-combination dispatch# drop 0 ;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								M: simple-generic definer drop \ GENERIC: f ;
							 |