]> gitweb.factorcode.org Git - factor.git/blob - basis/fry/fry.factor
cca4aef3b5fe266c81d6461e67221589606b3082
[factor.git] / basis / fry / fry.factor
1 ! Copyright (C) 2009 Slava Pestov, Eduardo Cavazos, Joe Groff.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors combinators kernel locals.backend math parser
4 quotations sequences sets splitting words ;
5 IN: fry
6
7 : _ ( -- * ) "Only valid inside a fry" throw ;
8 : @ ( -- * ) "Only valid inside a fry" throw ;
9
10 ERROR: >r/r>-in-fry-error ;
11
12 GENERIC: fry ( quot -- quot' )
13
14 <PRIVATE
15
16 : check-fry ( quot -- quot )
17     dup { load-local load-locals get-local drop-locals } intersect
18     [ >r/r>-in-fry-error ] unless-empty ;
19
20 PREDICATE: fry-specifier < word { _ @ } member-eq? ;
21
22 GENERIC: count-inputs ( quot -- n )
23
24 M: callable count-inputs [ count-inputs ] map-sum ;
25 M: fry-specifier count-inputs drop 1 ;
26 M: object count-inputs drop 0 ;
27
28 MIXIN: fried
29 PREDICATE: fried-callable < callable
30     count-inputs 0 > ;
31 INSTANCE: fried-callable fried
32
33 : (ncurry) ( quot n -- quot )
34     {
35         { 0 [ ] }
36         { 1 [ \ curry  suffix! ] }
37         { 2 [ \ 2curry suffix! ] }
38         { 3 [ \ 3curry suffix! ] }
39         [ [ \ 3curry suffix! ] dip 3 - (ncurry) ]
40     } case ;
41
42 : wrap-non-callable ( obj -- quot )
43     dup callable? [ ] [ [ call ] curry ] if ; inline
44
45 : [ncurry] ( n -- quot )
46     [ V{ } clone ] dip (ncurry) >quotation ;
47
48 : [ndip] ( quot n -- quot' )
49     {
50         { 0 [ wrap-non-callable ] }
51         { 1 [ \ dip  [ ] 2sequence ] }
52         { 2 [ \ 2dip [ ] 2sequence ] }
53         { 3 [ \ 3dip [ ] 2sequence ] }
54         [ [ \ 3dip [ ] 2sequence ] dip 3 - [ndip] ]
55     } case ;
56
57 : (make-curry) ( tail quot -- quot' )
58     swap [ncurry] curry [ compose ] compose ;
59
60 : make-compose ( consecutive quot -- consecutive quot' )
61     [
62         [ [ ] ]
63         [ [ncurry] ] if-zero
64     ] [
65         [ [ compose ] ]
66         [ [ compose compose ] curry ] if-empty
67     ] bi* compose
68     0 swap ;
69
70 : make-curry ( consecutive quot -- consecutive' quot' )
71     [ 1 + ] dip
72     [ [ ] ] [ (make-curry) 0 swap ] if-empty ;
73
74 : convert-curry ( consecutive quot -- consecutive' quot' )
75     [ [ ] make-curry ] [
76         dup first \ @ =
77         [ rest >quotation make-compose ]
78         [ >quotation make-curry ] if
79     ] if-empty ;
80
81 : prune-curries ( seq -- seq' )
82     dup [ empty? not ] find
83     [ [ 1 + tail ] dip but-last prefix ]
84     [ 2drop { } ] if* ;
85
86 : convert-curries ( seq -- tail seq' )
87     unclip-slice [ 0 swap [ convert-curry ] map ] dip
88     [ prune-curries ]
89     [ >quotation 1quotation prefix ] if-empty ;
90
91 : mark-composes ( quot -- quot' )
92     [ dup \ @ = [ drop [ _ @ ] ] [ 1quotation ] if ] map concat ; inline
93
94 : shallow-fry ( quot -- quot' )
95     check-fry mark-composes
96     { _ } split convert-curries
97     [ [ [ ] ] [ [ ] (make-curry) but-last ] if-zero ]
98     [ shallow-spread>quot swap [ [ ] (make-curry) compose ] unless-zero ] if-empty ;
99
100 DEFER: dredge-fry
101
102 TUPLE: dredge-fry-state
103     { in-quot read-only }
104     { prequot read-only }
105     { quot read-only } ;
106
107 : <dredge-fry> ( quot -- dredge-fry )
108     V{ } clone V{ } clone dredge-fry-state boa ; inline
109
110 : in-quot-slices ( n i state -- head tail )
111     in-quot>>
112     [ <slice> ]
113     [ [ drop ] 2dip swap 1 + tail-slice ] 3bi ; inline
114
115 : push-head-slice ( head state -- )
116     quot>> [ push-all ] [ \ _ swap push ] bi ; inline
117
118 : push-subquot ( tail elt state -- )
119     [ fry swap >quotation count-inputs [ndip] ] dip prequot>> push-all ; inline
120
121 : (dredge-fry-subquot) ( n state i elt -- )
122     rot {
123         [ nip in-quot-slices ] ! head tail i elt state
124         [ [ 2drop swap ] dip push-head-slice ]
125         [ [ drop ] 2dip push-subquot ]
126         [ [ 1 + ] [ drop ] [ ] tri* dredge-fry ]
127     } 3cleave ; inline recursive
128
129 : (dredge-fry-simple) ( n state -- )
130     [ in-quot>> swap tail-slice ] [ quot>> ] bi push-all ; inline recursive
131
132 : dredge-fry ( n dredge-fry -- )
133     2dup in-quot>> [ fried? ] find-from
134     [ (dredge-fry-subquot) ]
135     [ drop (dredge-fry-simple) ] if* ; inline recursive
136
137 PRIVATE>
138
139 M: callable fry ( quot -- quot' )
140     [ [ [ ] ] ] [
141         0 swap <dredge-fry>
142         [ dredge-fry ] [
143             [ prequot>> >quotation ]
144             [ quot>> >quotation shallow-fry ] bi append
145         ] bi
146     ] if-empty ;
147
148 SYNTAX: '[ parse-quotation fry append! ;