]> gitweb.factorcode.org Git - factor.git/blobdiff - basis/regexp/regexp.factor
regexp: don't use execute so the generated code is easier to read
[factor.git] / basis / regexp / regexp.factor
index bbfe44096749edda70412c5235c722e3997da19a..42138d5c66e7792b109f2b1651837fa6e02e496f 100644 (file)
@@ -1,9 +1,10 @@
 ! Copyright (C) 2008, 2009 Doug Coleman, Daniel Ehrenberg.
 ! See http://factorcode.org/license.txt for BSD license.
-USING: accessors combinators kernel kernel.private math sequences
-sequences.private strings sets assocs make lexer namespaces parser
-arrays fry locals regexp.parser splitting sorting regexp.ast
-regexp.negation regexp.compiler compiler.units words math.ranges ;
+USING: accessors arrays classes compiler.units kernel
+kernel.private lexer make math ranges namespaces quotations
+regexp.ast regexp.compiler regexp.negation regexp.parser
+sequences sequences.private splitting strings vocabs.loader
+words ;
 IN: regexp
 
 TUPLE: regexp
@@ -16,20 +17,18 @@ TUPLE: reverse-regexp < regexp ;
 
 <PRIVATE
 
-M: lookahead question>quot ! Returns ( index string -- ? )
-    term>> ast>dfa dfa>shortest-word '[ f _ execute ] ;
+M: lookahead question>quot
+    ! Returns ( index string -- ? )
+    term>> ast>dfa dfa>shortest-word 1quotation [ f ] prepose ;
 
 : <reversed-option> ( ast -- reversed )
     "r" string>options <with-options> ;
 
-M: lookbehind question>quot ! Returns ( index string -- ? )
+M: lookbehind question>quot
+    ! Returns ( index string -- ? )
     term>> <reversed-option>
     ast>dfa dfa>reverse-shortest-word
-    '[ [ 1 - ] dip f _ execute ] ;
-
-: check-string ( string -- string )
-    ! Make this configurable
-    dup string? [ "String required" throw ] unless ;
+    1quotation [ [ 1 - ] dip f ] prepose ;
 
 : match-index-from ( i string regexp -- index/f )
     ! This word is unsafe. It assumes that i is a fixnum
@@ -43,40 +42,56 @@ M: reverse-regexp end/start drop length 1 - -1 swap ;
 PRIVATE>
 
 : matches? ( string regexp -- ? )
-    [ check-string ] dip
+    [ string check-instance ] dip
     [ end/start ] 2keep
     match-index-from
     [ = ] [ drop f ] if* ;
 
 <PRIVATE
 
-:: (next-match) ( i string regexp quot: ( i string regexp -- j ) reverse? -- i start end ? )
-    i string regexp quot call dup [| j |
-        j i j
-        reverse? [ swap [ 1 + ] bi@ ] when
-        string
-    ] [ drop f f f f ] if ; inline
-
 : search-range ( i string reverse? -- seq )
-    [ drop dup 1 + -1 ] [ length 1 ] if range boa ; inline
+    [ drop -1 ] [ length ] if [a..b] ; inline
+
+:: (next-match) ( i string regexp quot: ( i string regexp -- j ) reverse? -- start end ? )
+    i string regexp quot call dup
+    [| j | reverse? [ j i ] [ i j ] if string ] [ drop f f f ] if ; inline
 
-:: next-match ( i string regexp quot: ( i string regexp -- j ) reverse? -- start end ? )
-    f f f f
+:: next-match ( i string regexp quot: ( i string regexp -- j ) reverse? -- start end ? )
+    f f f
     i string reverse? search-range
-    [ [ 2drop 2drop ] dip string regexp quot reverse? (next-match) dup ] find 2drop ; inline
+    [ 3nip string regexp quot reverse? (next-match) dup ] find 2drop ; inline
 
-: do-next-match ( i string regexp -- start end ? )
+: do-next-match ( i string regexp -- start end ? )
     dup next-match>>
-    execute( i string regexp -- i start end ? ) ; inline
-
-:: (each-match) ( ... i string regexp quot: ( ... start end string -- ... ) -- ... )
-    i string regexp do-next-match [| i' start end |
-        start end string quot call
-        i' string regexp quot (each-match)
-    ] [ 3drop ] if ; inline recursive
+    execute( i string regexp -- start end ? ) ; inline
+
+:: (each-match-forward) ( ... i string regexp quot: ( ... start end string -- ... ) -- ... )
+    i string length <= [
+        i string regexp do-next-match [| start end |
+            start end string quot call
+            start end eq? [ end 1 +  ] [ end ] if
+            string regexp quot (each-match-forward)
+        ] [ 2drop ] if
+    ] when ; inline recursive
+
+:: (each-match-backward) ( ... i string regexp quot: ( ... start end string -- ... ) -- ... )
+    i -1 >= [
+        i string regexp do-next-match [| start end |
+            start 1 + end 1 + string quot call
+            start end eq? [ start 1 - ] [ start ] if
+            string regexp quot (each-match-backward)
+        ] [ 2drop ] if
+    ] when ; inline recursive
+
+: (each-match) ( ... i string regexp quot: ( ... start end string -- ... ) -- ... )
+    over reverse-regexp? [ (each-match-backward) ] [ (each-match-forward) ] if ; inline
+
+GENERIC: match-iterator-start ( string regexp -- start )
+M: regexp match-iterator-start 2drop 0 ;
+M: reverse-regexp match-iterator-start drop length ;
 
 : prepare-match-iterator ( string regexp -- i string regexp )
-    [ check-string ] dip [ end/start nip ] 2keep ; inline
+    [ string check-instance ] dip [ match-iterator-start ] 2keep ; inline
 
 PRIVATE>
 
@@ -87,7 +102,7 @@ PRIVATE>
     collector [ each-match ] dip >array ; inline
 
 : all-matching-slices ( string regexp -- seq )
-    [ slice boa ] map-matches ;
+    [ <slice-unsafe> ] map-matches ;
 
 : all-matching-subseqs ( string regexp -- seq )
     [ subseq ] map-matches ;
@@ -97,7 +112,7 @@ PRIVATE>
 
 <PRIVATE
 
-:: (re-split) ( string regexp quot -- new-slices )
+:: (re-split) ( string regexp quot: ( from to seq -- slice ) -- new-slices )
     0 string regexp [| end start end' string |
         end' ! leave it on the stack for the next iteration
         end start string quot call
@@ -107,19 +122,29 @@ PRIVATE>
 
 PRIVATE>
 
-: first-match ( string regexp -- slice/f )
-    [ prepare-match-iterator do-next-match ] [ drop ] 2bi
-    '[ _ slice boa nip ] [ 3drop f ] if ;
+:: first-match ( string regexp -- slice/f )
+    string regexp prepare-match-iterator do-next-match [
+        regexp reverse-regexp? [ [ 1 + ] bi@ ] when
+        string <slice-unsafe>
+    ] [ 2drop f ] if ;
 
 : re-contains? ( string regexp -- ? )
-    prepare-match-iterator do-next-match [ 3drop ] dip >boolean ;
+    prepare-match-iterator do-next-match 2nip >boolean ;
 
 : re-split ( string regexp -- seq )
-    [ slice boa ] (re-split) ;
+    [ <slice-unsafe> ] (re-split) ;
 
 : re-replace ( string regexp replacement -- result )
     [ [ subseq ] (re-split) ] dip join ;
 
+:: re-replace-with ( string regexp quot: ( slice -- replacement ) -- result )
+    [
+        0 string regexp [
+            drop [ [ string <slice-unsafe> , ] keep ] dip
+            [ string <slice-unsafe> quot call( x -- x ) , ] keep
+        ] each-match string [ length ] [ <slice-unsafe> ] bi ,
+    ] { } make concat ;
+
 <PRIVATE
 
 : get-ast ( regexp -- ast )
@@ -130,18 +155,18 @@ GENERIC: compile-regexp ( regex -- regexp )
 : regexp-initial-word ( i string regexp -- i/f )
     [ compile-regexp ] with-compilation-unit match-index-from ;
 
-M: regexp compile-regexp ( regexp -- regexp )
+M: regexp compile-regexp
     dup '[
         dup \ regexp-initial-word =
         [ drop _ get-ast ast>dfa dfa>word ] when
     ] change-dfa ;
 
-M: reverse-regexp compile-regexp ( regexp -- regexp )
+M: reverse-regexp compile-regexp
     t backwards? [ call-next-method ] with-variable ;
 
 DEFER: compile-next-match
 
-: next-initial-word ( i string regexp -- start end string )
+: next-initial-word ( i string regexp -- start end string )
     [ compile-next-match ] with-compilation-unit do-next-match ;
 
 : compile-next-match ( regexp -- regexp )
@@ -149,7 +174,7 @@ DEFER: compile-next-match
         dup \ next-initial-word = [
             drop _ [ compile-regexp dfa>> def>> ] [ reverse-regexp? ] bi
             '[ { array-capacity string regexp } declare _ _ next-match ]
-            (( i string regexp -- i start end string )) define-temp
+            ( i string regexp -- start end string ) define-temp
         ] when
     ] change-next-match ;
 
@@ -171,51 +196,27 @@ PRIVATE>
 
 <PRIVATE
 
-! The following two should do some caching
-
-: find-regexp-syntax ( string -- prefix suffix )
-    {
-        { "R/ "  "/"  }
-        { "R! "  "!"  }
-        { "R\" " "\"" }
-        { "R# "  "#"  }
-        { "R' "  "'"  }
-        { "R( "  ")"  }
-        { "R@ "  "@"  }
-        { "R[ "  "]"  }
-        { "R` "  "`"  }
-        { "R{ "  "}"  }
-        { "R| "  "|"  }
-    } swap [ subseq? not nip ] curry assoc-find drop ;
-
-: take-until ( end lexer -- string )
+: take-until ( lexer -- string )
     dup skip-blank [
-        [ index-from ] 2keep
-        [ swapd subseq ]
-        [ 2drop 1 + ] 3bi
+        dupd [
+            [ [ "\\/" member? ] find-from ] keep swap [
+                CHAR: \ = [ [ 2 + ] dip t ] [ f ] if
+            ] [
+                "Unterminated regexp" throw
+            ] if*
+        ] loop over [ subseq ] dip 1 +
     ] change-lexer-column ;
 
 : parse-noblank-token ( lexer -- str/f )
-    dup still-parsing-line? [ (parse-token) ] [ drop f ] if ;
+    dup still-parsing-line? [ (parse-raw) ] [ drop f ] if ;
 
-: parsing-regexp ( accum end -- accum )
-    lexer get [ take-until ] [ parse-noblank-token ] bi
+: parse-regexp ( accum -- accum )
+    lexer get [ take-until "\\/" "/" replace ] [ parse-noblank-token ] bi
     <optioned-regexp> compile-next-match suffix! ;
 
 PRIVATE>
 
-SYNTAX: R! CHAR: ! parsing-regexp ;
-SYNTAX: R" CHAR: " parsing-regexp ;
-SYNTAX: R# CHAR: # parsing-regexp ;
-SYNTAX: R' CHAR: ' parsing-regexp ;
-SYNTAX: R( CHAR: ) parsing-regexp ;
-SYNTAX: R/ CHAR: / parsing-regexp ;
-SYNTAX: R@ CHAR: @ parsing-regexp ;
-SYNTAX: R[ CHAR: ] parsing-regexp ;
-SYNTAX: R` CHAR: ` parsing-regexp ;
-SYNTAX: R{ CHAR: } parsing-regexp ;
-SYNTAX: R| CHAR: | parsing-regexp ;
-
-USE: vocabs.loader
+SYNTAX: R/ parse-regexp ;
+
 
 { "prettyprint" "regexp" } "regexp.prettyprint" require-when