1 ! Copyright (C) 2004, 2006 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays errors generic hashtables kernel
4 math math-internals namespaces parser prettyprint sequences
5 strings vectors words ;
8 : consume-values ( seq node -- )
11 over 0 rot node-inputs
12 meta-d get [ length swap - ] keep set-length ;
14 : produce-values ( seq node -- )
15 >r [ drop <computed> ] map dup r> set-node-out-d
16 meta-d get swap nappend ;
18 : recursing? ( word -- label/f )
19 recursive-state get <reversed> assoc ;
21 : if-inline ( word true false -- )
22 >r >r dup "inline" word-prop r> r> if ; inline
24 : make-call-node ( word -- node )
25 [ dup recursing? [ #call-label ] [ #call ] ?if ]
29 : consume/produce ( effect word -- )
31 swap make-call-node dup node,
32 over effect-in over consume-values
33 over effect-out over produce-values
34 r> over #call-label? [ swap set-node-in-d ] [ 2drop ] if
35 effect-terminated? [ terminate ] when ;
37 TUPLE: no-effect word ;
39 : no-effect ( word -- * )
40 <no-effect> inference-warning ;
42 : nest-node ( -- ) #entry node, ;
44 : unnest-node ( new-node -- new-node )
45 dup node-param #return node,
46 dataflow-graph get 1array over set-node-children ;
48 : add-recursive-state ( word label -- )
49 2array recursive-state [ swap add ] change ;
51 : block-label ( word -- newword )
52 word-name " - inlined" append f <word> ;
54 : inline-block ( word -- node-block data )
56 copy-inference nest-node
57 dup block-label 2dup add-recursive-state
58 #label >r word-def infer-quot r>
62 : apply-infer ( hash -- )
63 { meta-d meta-r d-in }
64 [ [ swap hash ] keep set ] each-with ;
66 GENERIC: collect-recursion* ( label node -- )
68 M: node collect-recursion* 2drop ;
70 M: #call-label collect-recursion*
71 tuck node-param eq? [ node-in-d , ] [ drop ] if ;
73 : collect-recursion ( #label -- seq )
75 [ [ collect-recursion* ] each-node-with ] { } make ;
77 : join-values ( node -- )
78 collect-recursion meta-d get add unify-lengths unify-stacks
79 meta-d [ length tail* >vector ] change ;
81 : splice-node ( node -- )
83 dup node, penultimate-node f over set-node-successor
87 : inline-closure ( word -- )
88 dup inline-block over recursive-label? [
90 drop join-values inline-block apply-infer
91 r> over 2dup set-node-out-d set-node-in-d node,
93 apply-infer node-child node-successor splice-node drop
96 : infer-compound ( word -- hash )
98 recursive-state get init-inference inline-block nip
101 GENERIC: infer-word ( word -- effect data )
103 M: word infer-word no-effect ;
105 TUPLE: effect-error word effect ;
107 : effect-error ( word effect -- * )
108 <effect-error> inference-error ;
110 : check-effect ( word effect -- )
111 over "infer" word-prop [
112 over recorded get push
113 over "declared-effect" word-prop 2dup
114 [ swap effect<= [ effect-error ] unless ] [ 2drop ] if
117 : save-inferred-data ( word effect vars -- )
119 dup vars-trivial? [ drop f ] when
120 "inferred-vars" set-word-prop
121 "inferred-effect" set-word-prop ;
123 : finish-word ( word -- effect vars )
124 current-effect inferred-vars get
128 >r 2dup check-effect r>
129 [ save-inferred-data ] 2keep
132 M: compound infer-word
133 [ dup infer-compound [ finish-word ] bind ]
134 [ swap t "no-effect" set-word-prop rethrow ] recover ;
136 : custom-infer ( word -- )
137 #! Customized inference behavior
138 dup "inferred-vars" word-prop apply-vars
139 dup "inferred-effect" word-prop effect-in ensure-values
140 "infer" word-prop call ;
142 : apply-effect/vars ( word effect vars -- )
143 apply-vars consume/produce ;
145 : cached-infer ( word -- )
146 dup "inferred-effect" word-prop
147 over "inferred-vars" word-prop
150 : default-apply-word ( word -- )
152 { [ dup "no-effect" word-prop ] [ no-effect ] }
153 { [ dup "infer" word-prop ] [ custom-infer ] }
154 { [ dup "inferred-effect" word-prop ] [ cached-infer ] }
155 { [ t ] [ dup infer-word apply-effect/vars ] }
158 M: word apply-word default-apply-word ;
160 M: symbol apply-word apply-literal ;
162 TUPLE: recursive-declare-error word ;
164 : declared-infer ( word -- )
168 <recursive-declare-error> inference-error
171 : apply-inline ( word -- )
172 dup recursive-state get peek first eq?
173 [ declared-infer ] [ inline-closure ] if ;
175 : apply-compound ( word -- )
177 [ declared-infer ] [ default-apply-word ] if ;
179 : custom-infer-vars ( word -- )
180 dup "infer-vars" word-prop dup [
181 swap "inferred-effect" word-prop effect-in ensure-values
187 M: compound apply-word
188 dup custom-infer-vars
189 [ apply-inline ] [ apply-compound ] if-inline ;