]> gitweb.factorcode.org Git - factor.git/blob - basis/regexp/compiler/compiler.factor
Merge branch 'master' of git://factorcode.org/git/factor into regexp
[factor.git] / basis / regexp / compiler / compiler.factor
1 ! Copyright (C) 2009 Daniel Ehrenberg.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: regexp.classes kernel sequences regexp.negation
4 quotations regexp.minimize assocs fry math locals combinators
5 accessors words compiler.units kernel.private strings
6 sequences.private arrays regexp.matchers call namespaces
7 regexp.transition-tables combinators.short-circuit ;
8 IN: regexp.compiler
9
10 GENERIC: question>quot ( question -- quot )
11
12 <PRIVATE
13
14 SYMBOL: shortest?
15 SYMBOL: backwards?
16
17 M: t question>quot drop [ 2drop t ] ;
18
19 M: beginning-of-input question>quot
20     drop [ drop zero? ] ;
21
22 M: end-of-input question>quot
23     drop [ length = ] ;
24
25 M: end-of-file question>quot
26     drop [
27         {
28             [ length swap - 2 <= ]
29             [ swap tail { "\n" "\r\n" "\r" "" } member? ]
30         } 2&&
31     ] ;
32
33 M: $ question>quot
34     drop [ { [ length = ] [ ?nth "\r\n" member? ] } 2|| ] ;
35
36 M: ^ question>quot
37     drop [ { [ drop zero? ] [ [ 1- ] dip ?nth "\r\n" member? ] } 2|| ] ;
38
39 ! Maybe the condition>quot things can be combined, given a suitable method
40 ! for question>quot on classes, but maybe that'd make stack shuffling annoying
41
42 : execution-quot ( next-state -- quot )
43     ! The conditions here are for lookaround and anchors, etc
44     dup condition? [
45         [ question>> question>quot ] [ yes>> ] [ no>> ] tri
46         [ execution-quot ] bi@
47         '[ 2dup @ _ _ if ]
48     ] [
49         ! There shouldn't be a condition like this!
50         dup sequence?
51         [ [ [ 2drop ] ] [ first '[ _ execute ] ] if-empty ]
52         [ '[ _ execute ] ] if
53     ] if ;
54
55 TUPLE: box contents ;
56 C: <box> box
57
58 : condition>quot ( condition -- quot )
59     ! Conditions here are for different classes
60     dup condition? [
61         [ question>> ] [ yes>> ] [ no>> ] tri
62         [ condition>quot ] bi@
63         '[ dup _ class-member? _ _ if ]
64     ] [
65         contents>>
66         [ [ 3drop ] ] [ execution-quot '[ drop @ ] ] if-empty
67     ] if ;
68
69 : non-literals>dispatch ( non-literal-transitions -- quot )
70     [ swap ] assoc-map ! we want state => predicate, and get the opposite as input
71     table>condition [ <box> ] condition-map condition>quot ;
72
73 : literals>cases ( literal-transitions -- case-body )
74     [ execution-quot ] assoc-map ;
75
76 : expand-one-or ( or-class transition -- alist )
77     [ seq>> ] dip '[ _ 2array ] map ;
78
79 : expand-or ( alist -- new-alist )
80     [
81         first2 over or-class?
82         [ expand-one-or ] [ 2array 1array ] if
83     ] map concat ;
84
85 : split-literals ( transitions -- case default )
86     >alist expand-or [ first integer? ] partition
87     [ literals>cases ] [ non-literals>dispatch ] bi* ;
88
89 :: step ( last-match index str quot final? direction -- last-index/f )
90     final? index last-match ?
91     index str bounds-check? [
92         index direction + str
93         index str nth-unsafe
94         quot call
95     ] when ; inline
96
97 : direction ( -- n )
98     backwards? get -1 1 ? ;
99
100 : transitions>quot ( transitions final-state? -- quot )
101     dup shortest? get and [ 2drop [ drop nip ] ] [
102         [ split-literals swap case>quot ] dip direction
103         '[ { array-capacity string } declare _ _ _ step ]
104     ] if ;
105
106 : word>quot ( word dfa -- quot )
107     [ transitions>> at ]
108     [ final-states>> key? ] 2bi
109     transitions>quot ;
110
111 : states>code ( words dfa -- )
112     '[
113         [
114             dup _ word>quot
115             (( last-match index string -- ? ))
116             define-declared
117         ] each
118     ] with-compilation-unit ;
119
120 : states>words ( dfa -- words dfa )
121     dup transitions>> keys [ gensym ] H{ } map>assoc
122     [ transitions-at ]
123     [ values ]
124     bi swap ; 
125
126 : dfa>word ( dfa -- word )
127     states>words [ states>code ] keep start-state>> ;
128
129 : check-string ( string -- string )
130     ! Make this configurable
131     dup string? [ "String required" throw ] unless ;
132
133 : setup-regexp ( start-index string -- f start-index string )
134     [ f ] [ >fixnum ] [ check-string ] tri* ; inline
135
136 PRIVATE>
137
138 ! The quotation returned is ( start-index string -- i/f )
139
140 : dfa>quotation ( dfa -- quot )
141     dfa>word execution-quot '[ setup-regexp @ ] ;
142
143 : dfa>shortest-quotation ( dfa -- quot )
144     t shortest? [ dfa>quotation ] with-variable ;
145
146 : dfa>reverse-quotation ( dfa -- quot )
147     t backwards? [ dfa>quotation ] with-variable ;
148
149 : dfa>reverse-shortest-quotation ( dfa -- quot )
150     t backwards? [ dfa>shortest-quotation ] with-variable ;
151
152 TUPLE: quot-matcher quot ;
153 C: <quot-matcher> quot-matcher
154
155 M: quot-matcher match-index-from
156     quot>> call( index string -- i/f ) ;