1 ! Copyright (C) 2016 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors assocs kernel math sequences sequences.deep
4 sequences.extras strings unicode ;
7 : >strings ( seq -- str )
8 [ dup slice? [ >string ] when ] deep-map ;
10 : matching-delimiter ( ch -- ch' )
19 : matching-delimiter-string ( string -- string' )
20 [ matching-delimiter ] map ;
22 : matching-section-delimiter ( string -- string' )
24 rest but-last ";" ">" surround
29 ERROR: unexpected-end n string ;
30 : nth-check-eof ( n string -- nth )
31 2dup ?nth [ 2nip ] [ unexpected-end ] if* ;
33 : peek1-from ( n/f string -- ch )
34 over [ ?nth ] [ 2drop f ] if ;
36 : peek-from ( n/f string m -- string )
37 over [ [ swap tail-slice ] dip head-slice ] [ 3drop f ] if ;
39 : previous-from ( n/f string -- ch )
40 over [ [ 1 - ] dip ?nth ] [ 2drop f ] if ;
43 : next-char-from ( n/f string -- n'/f string ch/f )
45 2dup ?nth [ [ 1 + ] 2dip ] [ f ] if*
47 [ 2drop f ] [ nip ] 2bi f
50 : prev-char-from-slice-end ( slice -- ch/f )
51 [ to>> 2 - ] [ seq>> ] bi ?nth ;
53 : prev-char-from-slice ( slice -- ch/f )
54 [ from>> 1 - ] [ seq>> ] bi ?nth ;
56 : next-char-from-slice ( slice -- ch/f )
57 [ to>> ] [ seq>> ] bi ?nth ;
59 : char-before-slice ( slice -- ch/f )
60 [ from>> 1 - ] [ seq>> ] bi ?nth ;
62 : char-after-slice ( slice -- ch/f )
63 [ to>> ] [ seq>> ] bi ?nth ;
65 : find-from* ( ... n seq quot: ( ... elt -- ... ? ) -- ... i elt ? )
67 pick [ drop t ] [ length -rot nip f ] if ; inline
69 : skip-blank-from ( n string -- n' string )
71 [ [ blank? not ] find-from* 2drop ] keep
74 : skip-til-eol-from ( n string -- n' string )
75 [ [ "\r\n" member? ] find-from* 2drop ] keep ; inline
77 ERROR: take-slice-error n string count ;
78 :: take-slice ( n string count -- n'/f string slice )
79 n [ n string count take-slice-error ] unless
85 ERROR: expected-sequence-error expected actual ;
86 : check-sequence ( expected actual -- actual/* )
87 2dup sequence= [ nip ] [ expected-sequence-error ] if ;
89 : expect-and-span ( n string slice expected-string -- n' string slice' )
90 dup length '[ _ take-slice ] 2dip
91 rot check-sequence span-slices ;
93 :: split-slice-back ( slice n -- slice1 slice2 )
94 slice [ from>> ] [ to>> ] [ seq>> ] tri :> ( from to seq )
95 from to n - seq <slice>
96 to n - to seq <slice> ;
98 ! Don't include the whitespace in the slice
99 :: slice-til-whitespace ( n string -- n' string slice/f ch/f )
101 n string [ "\s\r\n" member? ] find-from :> ( n' ch )
109 :: (slice-until) ( n string quot -- n' string slice/f ch/f )
110 n string quot find-from :> ( n' ch )
115 : slice-until ( n string quot -- n' string slice/f )
116 (slice-until) drop ; inline
118 :: slice-til-not-whitespace ( n string -- n' string slice/f ch/f )
120 n string [ "\s\r\n\t" member? not ] find-from :> ( n' ch )
128 : skip-whitespace ( n/f string -- n'/f string )
129 slice-til-not-whitespace 2drop ;
131 : empty-slice-end ( seq -- slice )
132 [ length dup ] [ ] bi <slice> ; inline
134 : empty-slice-from ( n seq -- slice )
135 dupd <slice> ; inline
137 :: slice-til-eol ( n string -- n' string slice/f ch/f )
139 n string '[ "\r\n" member? ] find-from :> ( n' ch )
144 n string string empty-slice-end f
147 :: merge-slice-til-eol-slash'' ( n string -- n' string slice/f ch/f )
149 n string '[ "\r\n\\" member? ] find-from :> ( n' ch )
154 n string string empty-slice-end f
157 : merge-slice-til-whitespace ( n string slice -- n' string slice' )
159 [ slice-til-whitespace drop ] dip merge-slices
162 : merge-slice-til-eol ( n string slice -- n' string slice' )
163 [ slice-til-eol drop ] dip merge-slices ;
165 : slice-between ( slice1 slice2 -- slice )
166 ! ensure-same-underlying
169 [ [ from>> 2dup < [ swap ] unless ] [ seq>> ] bi ] bi* <slice> ;
171 : slice-before ( slice -- slice' )
172 [ drop 0 ] [ from>> ] [ seq>> ] tri <slice> ;
174 : (?nth) ( n/f string/f -- obj/f )
175 over [ (?nth) ] [ 2drop f ] if ;
177 :: merge-slice-til-eol-slash' ( n string slice -- n' string slice/f ch/f )
178 n string merge-slice-til-eol-slash'' :> ( n' string' slice' ch' )
180 n' 1 + string' (?nth) "\r\n" member? [
181 n' 2 + string' slice slice' span-slices merge-slice-til-eol-slash'
186 n' string' slice slice' span-slices ch'
189 ! Supports \ at eol (with no space after it)
190 : slice-til-eol-slash ( n string -- n' string slice/f ch/f )
191 2dup empty-slice-from merge-slice-til-eol-slash' ;
193 :: slice-til-separator-inclusive ( n string tokens -- n' string slice/f ch/f )
194 n string '[ tokens member? ] find-from [ dup [ 1 + ] when ] dip :> ( n' ch )
199 : slice-til-separator-exclusive ( n string tokens -- n' string slice/f ch/f )
200 slice-til-separator-inclusive dup [
201 [ [ 1 - ] change-to ] dip
204 ! Takes at least one character if not whitespace
205 :: slice-til-either ( n string tokens -- n'/f string slice/f ch/f )
207 n string '[ tokens member? ] find-from
208 dup "\s\r\n" member? [
214 [ dup [ 1 + ] when ] dip :> ( n' ch )
223 ERROR: subseq-expected-but-got-eof n string expected ;
225 :: slice-til-string ( n string search -- n' string payload end-string )
226 search string n subseq-start-from :> n'
227 n' [ n string search subseq-expected-but-got-eof ] unless
228 n' search length + string
230 n' dup search length + string ?<slice> ;
232 : modify-from ( slice n -- slice' )
233 '[ from>> _ + ] [ to>> ] [ seq>> ] tri <slice> ;
235 : modify-to ( slice n -- slice' )
236 [ [ from>> ] [ to>> ] [ seq>> ] tri ] dip
237 swap [ + ] dip <slice> ;
239 ! { CHAR: \] [ read-closing ] }
240 ! { CHAR: \} [ read-closing ] }
241 ! { CHAR: \) [ read-closing ] }
242 : read-closing ( n string tok -- n string tok )
244 -1 modify-to [ 1 - ] 2dip
247 : rewind-slice ( n string slice -- n' string )
249 length swap [ - ] dip
251 [ nip ] dip [ [ length ] bi@ - ] keepd