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 ;
 |