Merge branch 'master' of git://factorcode.org/git/factor
[factor/jcg.git] / core / generic / standard / standard.factor
blob9ace1a01f4f63efb02abf938fd43aa106f4f3fda
1 ! Copyright (C) 2005, 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays assocs kernel kernel.private slots.private math
4 namespaces make sequences vectors words quotations definitions
5 hashtables layouts combinators sequences.private generic
6 classes classes.algebra classes.private generic.standard.engines
7 generic.standard.engines.tag generic.standard.engines.predicate
8 generic.standard.engines.tuple accessors ;
9 IN: generic.standard
11 GENERIC: dispatch# ( word -- n )
13 M: generic dispatch#
14     "combination" word-prop dispatch# ;
16 GENERIC: method-declaration ( class generic -- quot )
18 M: generic method-declaration
19     "combination" word-prop method-declaration ;
21 M: quotation engine>quot
22     assumed get generic get method-declaration prepend ;
24 ERROR: no-method object generic ;
26 : error-method ( word -- quot )
27     picker swap [ no-method ] curry append ;
29 : push-method ( method specializer atomic assoc -- )
30     [
31         [ H{ } clone <predicate-dispatch-engine> ] unless*
32         [ methods>> set-at ] keep
33     ] change-at ;
35 : flatten-method ( class method assoc -- )
36     [ [ flatten-class keys ] keep ] 2dip [
37         [ spin ] dip push-method
38     ] 3curry each ;
40 : flatten-methods ( assoc -- assoc' )
41     H{ } clone [
42         [
43             flatten-method
44         ] curry assoc-each
45     ] keep ;
47 : <big-dispatch-engine> ( assoc -- engine )
48     flatten-methods
49     convert-tuple-methods
50     convert-hi-tag-methods
51     <lo-tag-dispatch-engine> ;
53 : find-default ( methods -- quot )
54     #! Side-effects methods.
55     object bootstrap-word swap delete-at* [
56         drop generic get "default-method" word-prop 1quotation
57     ] unless ;
59 : mangle-method ( method generic -- quot )
60     [ 1quotation ] [ extra-values \ drop <repetition> ] bi*
61     prepend [ ] like ;
63 : <standard-engine> ( word -- engine )
64     object bootstrap-word assumed set {
65         [ generic set ]
66         [ "engines" word-prop forget-all ]
67         [ V{ } clone "engines" set-word-prop ]
68         [
69             "methods" word-prop
70             [ generic get mangle-method ] assoc-map
71             [ find-default default set ]
72             [ <big-dispatch-engine> ]
73             bi
74         ]
75     } cleave ;
77 : single-combination ( word -- quot )
78     [ <standard-engine> engine>quot ] with-scope ;
80 ERROR: inconsistent-next-method class generic ;
82 : single-next-method-quot ( class generic -- quot/f )
83     2dup next-method dup [
84         [
85             pick "predicate" word-prop %
86             1quotation ,
87             [ inconsistent-next-method ] 2curry ,
88             \ if ,
89         ] [ ] make
90     ] [ 3drop f ] if ;
92 : single-effective-method ( obj word -- method )
93     [ [ order [ instance? ] with find-last nip ] keep method ]
94     [ "default-method" word-prop ]
95     bi or ;
97 TUPLE: standard-combination # ;
99 C: <standard-combination> standard-combination
101 PREDICATE: standard-generic < generic
102     "combination" word-prop standard-combination? ;
104 PREDICATE: simple-generic < standard-generic
105     "combination" word-prop #>> zero? ;
107 : define-simple-generic ( word -- )
108     T{ standard-combination f 0 } define-generic ;
110 : with-standard ( combination quot -- quot' )
111     [ #>> (dispatch#) ] dip with-variable ; inline
113 M: standard-generic extra-values drop 0 ;
115 M: standard-combination make-default-method
116     [ error-method ] with-standard ;
118 M: standard-combination perform-combination
119     [ drop ] [ [ single-combination ] with-standard ] 2bi define ;
121 M: standard-combination dispatch# #>> ;
123 M: standard-combination method-declaration
124     dispatch# object <array> swap prefix [ declare ] curry [ ] like ;
126 M: standard-combination next-method-quot*
127     [
128         single-next-method-quot
129         dup [ picker prepend ] when
130     ] with-standard ;
132 M: standard-generic effective-method
133     [ dispatch# (picker) call ] keep single-effective-method ;
135 TUPLE: hook-combination var ;
137 C: <hook-combination> hook-combination
139 PREDICATE: hook-generic < generic
140     "combination" word-prop hook-combination? ;
142 : with-hook ( combination quot -- quot' )
143     0 (dispatch#) [
144         [ hook-combination ] dip with-variable
145     ] with-variable ; inline
147 : prepend-hook-var ( quot -- quot' )
148     hook-combination get var>> [ get ] curry prepend ;
150 M: hook-combination dispatch# drop 0 ;
152 M: hook-combination method-declaration 2drop [ ] ;
154 M: hook-generic extra-values drop 1 ;
156 M: hook-generic effective-method
157     [ "combination" word-prop var>> get ] keep
158     single-effective-method ;
160 M: hook-combination make-default-method
161     [ error-method prepend-hook-var ] with-hook ;
163 M: hook-combination perform-combination
164     [ drop ] [
165         [ single-combination prepend-hook-var ] with-hook
166     ] 2bi define ;
168 M: hook-combination next-method-quot*
169     [
170         single-next-method-quot
171         dup [ prepend-hook-var ] when
172     ] with-hook ;
174 M: simple-generic definer drop \ GENERIC: f ;
176 M: standard-generic definer drop \ GENERIC# f ;
178 M: hook-generic definer drop \ HOOK: f ;