1 ! Copyright (C) 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
4 USING: kernel namespaces make xmode.rules xmode.tokens
5 xmode.marker.state xmode.marker.context xmode.utilities
6 xmode.catalog sequences math assocs combinators strings
7 regexp splitting ascii regexp.backend unicode.case
8 ascii combinators.short-circuit accessors ;
9 ! regexp.backend is for the regexp class
11 ! Next two words copied from parser-combinators
12 ! Just like head?, but they optionally ignore case
14 : string= ( str1 str2 ignore-case -- ? )
15 [ [ >upper ] bi@ ] when sequence= ;
17 : string-head? ( str1 str2 ignore-case -- ? )
22 [ length head-slice ] 2bi
26 ! Based on org.gjt.sp.jedit.syntax.TokenMarker
28 : current-keyword ( -- string )
29 last-offset get position get line get subseq ;
31 : keyword-number? ( keyword -- ? )
33 [ current-rule-set highlight-digits?>> ]
34 [ dup [ digit? ] any? ]
37 current-rule-set digit-re>>
38 dup [ dupd matches? ] [ drop f ] if
43 : mark-number ( keyword -- id )
44 keyword-number? DIGIT and ;
46 : mark-keyword ( keyword -- id )
47 current-rule-set keywords>> at ;
49 : add-remaining-token ( -- )
50 current-rule-set default>> prev-token, ;
54 dup mark-number [ ] [ mark-keyword ] ?if
55 [ prev-token, ] when* ;
57 : current-char ( -- char )
58 position get line get nth ;
60 GENERIC: match-position ( rule -- n )
62 M: mark-previous-rule match-position drop last-offset get ;
64 M: rule match-position drop position get ;
66 : can-match-here? ( matcher rule -- ? )
69 [ over at-line-start?>> over zero? implies ]
70 [ over at-whitespace-end?>> over whitespace-end get = implies ]
71 [ over at-word-start?>> over last-offset get = implies ]
74 : rest-of-line ( -- str )
75 line get position get tail-slice ;
77 GENERIC: text-matches? ( string text -- match-count/f )
82 M: string-matcher text-matches?
84 [ string>> ] [ ignore-case?>> ] bi string-head?
85 ] keep string>> length and ;
87 M: regexp text-matches?
88 [ >string ] dip match-head ;
90 : rule-start-matches? ( rule -- match-count/f )
91 dup start>> tuck swap can-match-here? [
92 rest-of-line swap text>> text-matches?
97 : rule-end-matches? ( rule -- match-count/f )
98 dup mark-following-rule? [
99 dup start>> swap can-match-here? 0 and
101 dup end>> tuck swap can-match-here? [
103 swap text>> context get end>> or
112 : get-always-rules ( vector/f ruleset -- vector/f )
113 f swap rules>> at ?push-all ;
115 : get-char-rules ( vector/f char ruleset -- vector/f )
116 [ ch>upper ] dip rules>> at ?push-all ;
118 : get-rules ( char ruleset -- seq )
119 [ f ] 2dip [ get-char-rules ] keep get-always-rules ;
121 GENERIC: handle-rule-start ( match-count rule -- )
123 GENERIC: handle-rule-end ( match-count rule -- )
125 : find-escape-rule ( -- rule )
127 in-rule-set>> escape-rule>> [ ] [
128 parent>> in-rule-set>>
129 dup [ escape-rule>> ] when
132 : check-escape-rule ( rule -- ? )
134 find-escape-rule dup [
135 dup rule-start-matches? dup [
136 swap handle-rule-start
137 delegate-end-escaped? [ not ] change
145 : check-every-rule ( -- ? )
146 current-char current-rule-set get-rules
147 [ rule-start-matches? ] map-find
148 dup [ handle-rule-start t ] [ 2drop f ] if ;
152 dup rule-end-matches?
153 dup [ swap handle-rule-end ] [ 2drop ] if
156 : rule-match-token* ( rule -- id )
158 { f [ dup body-token>> ] }
159 { t [ current-rule-set default>> ] }
163 M: escape-rule handle-rule-start
166 process-escape? get [
167 escaped? [ not ] change
168 position [ + ] change
171 M: seq-rule handle-rule-start
175 tuck body-token>> next-token,
176 delegate>> [ push-context ] when* ;
178 UNION: abstract-span-rule span-rule eol-span-rule ;
180 M: abstract-span-rule handle-rule-start
184 tuck rule-match-token* next-token,
186 dup context get (>>in-rule)
187 delegate>> push-context ;
189 M: span-rule handle-rule-end
192 M: mark-following-rule handle-rule-start
194 mark-token add-remaining-token
195 tuck rule-match-token* next-token,
196 f context get (>>end)
197 context get (>>in-rule) ;
199 M: mark-following-rule handle-rule-end
200 nip rule-match-token* prev-token,
201 f context get (>>in-rule) ;
203 M: mark-previous-rule handle-rule-start
206 dup body-token>> prev-token,
207 rule-match-token* next-token, ;
215 : check-end-delegate ( -- ? )
216 context get parent>> [
218 dup rule-end-matches? dup [
224 ] keep context get parent>> in-rule>>
225 rule-match-token* next-token,
227 seen-whitespace-end? on t
228 ] [ drop check-escape-rule ] if
232 : handle-no-word-break ( -- )
233 context get parent>> [
235 dup no-word-break?>> [
236 rule-match-token* prev-token,
246 add-remaining-token ;
248 : (check-word-break) ( -- )
251 1 current-rule-set default>> next-token, ;
253 : rule-set-empty? ( ruleset -- ? )
254 [ rules>> ] [ keywords>> ] bi
255 [ assoc-empty? ] bi@ and ;
257 : check-word-break ( -- ? )
258 current-char dup blank? [
261 seen-whitespace-end? get [
262 position get 1+ whitespace-end set
268 ! Micro-optimization with incorrect semantics; we keep
269 ! it here because jEdit mode files depend on it now...
270 current-rule-set rule-set-empty? [
276 current-rule-set rule-set-no-word-sep* member? [
282 seen-whitespace-end? on
285 delegate-end-escaped? off t ;
288 : mark-token-loop ( -- )
289 position get line get length < [
291 [ check-end-delegate ]
300 : mark-remaining ( -- )
301 line get length position set
304 : unwind-no-line-break ( -- )
305 context get parent>> [
314 : tokenize-line ( line-context line rules -- line-context' seq )