44module Data.String.Regex
55 ( Regex (..)
66 , RegexFlags (..)
7+ , RegexFlagsRec
78 , regex
89 , source
910 , flags
@@ -16,13 +17,15 @@ module Data.String.Regex
1617 , search
1718 , split
1819 , noFlags
20+ , g , i , m , s , u
1921 ) where
2022
2123import Prelude
2224
2325import Data.Either (Either (..))
2426import Data.Maybe (Maybe (..))
2527import Data.String (contains )
28+ import Data.Monoid (class Monoid )
2629
2730-- | Wraps Javascript `RegExp` objects.
2831foreign import data Regex :: *
@@ -32,22 +35,89 @@ foreign import showRegex' :: Regex -> String
3235instance showRegex :: Show Regex where
3336 show = showRegex'
3437
35- -- | Flags that control matching.
36- type RegexFlags =
37- { global :: Boolean
38+ type RegexFlagsRec =
39+ { global :: Boolean
3840 , ignoreCase :: Boolean
39- , multiline :: Boolean
40- , sticky :: Boolean
41- , unicode :: Boolean
41+ , multiline :: Boolean
42+ , sticky :: Boolean
43+ , unicode :: Boolean
4244 }
4345
46+ -- | Flags that control matching.
47+ data RegexFlags = RegexFlags RegexFlagsRec
48+
4449-- | All flags set to false.
4550noFlags :: RegexFlags
46- noFlags = { global : false
47- , ignoreCase : false
48- , multiline : false
49- , sticky : false
50- , unicode : false }
51+ noFlags = RegexFlags
52+ { global : false
53+ , ignoreCase : false
54+ , multiline : false
55+ , sticky : false
56+ , unicode : false
57+ }
58+
59+ -- | Only global flag set to true
60+ g :: RegexFlags
61+ g = RegexFlags
62+ { global : true
63+ , ignoreCase : false
64+ , multiline : false
65+ , sticky : false
66+ , unicode : false
67+ }
68+
69+ -- | Only ignoreCase flag set to true
70+ i :: RegexFlags
71+ i = RegexFlags
72+ { global : false
73+ , ignoreCase : true
74+ , multiline : false
75+ , sticky : false
76+ , unicode : false
77+ }
78+
79+ -- | Only multiline flag set to true
80+ m :: RegexFlags
81+ m = RegexFlags
82+ { global : false
83+ , ignoreCase : false
84+ , multiline : true
85+ , sticky : false
86+ , unicode : false
87+ }
88+
89+ -- | Only sticky flag set to true
90+ s :: RegexFlags
91+ s = RegexFlags
92+ { global : false
93+ , ignoreCase : false
94+ , multiline : false
95+ , sticky : true
96+ , unicode : false
97+ }
98+
99+ -- | Only unicode flag set to true
100+ u :: RegexFlags
101+ u = RegexFlags
102+ { global : false
103+ , ignoreCase : false
104+ , multiline : false
105+ , sticky : false
106+ , unicode : true
107+ }
108+
109+ instance semigroupRegexFlags :: Semigroup RegexFlags where
110+ append (RegexFlags x) (RegexFlags y) = RegexFlags
111+ { global : x.global || y.global
112+ , ignoreCase : x.ignoreCase || y.ignoreCase
113+ , multiline : x.multiline || y.multiline
114+ , sticky : x.sticky || y.sticky
115+ , unicode : x.unicode || y.unicode
116+ }
117+
118+ instance monoidRegexFlags :: Monoid RegexFlags where
119+ mempty = noFlags
120+
51121
52122foreign import regex' :: (String -> Either String Regex )
53123 -> (Regex -> Either String Regex )
@@ -58,31 +128,37 @@ foreign import regex' :: (String -> Either String Regex)
58128-- | Constructs a `Regex` from a pattern string and flags. Fails with
59129-- | `Left error` if the pattern contains a syntax error.
60130regex :: String -> RegexFlags -> Either String Regex
61- regex s f = regex' Left Right s $ renderFlags f
131+ regex str f = regex' Left Right str $ renderFlags f
62132
63133-- | Returns the pattern string used to construct the given `Regex`.
64134foreign import source :: Regex -> String
65135
66136-- | Returns the `RegexFlags` used to construct the given `Regex`.
67- foreign import flags :: Regex -> RegexFlags
137+ flags :: Regex -> RegexFlags
138+ flags = RegexFlags <<< flags'
139+
140+ -- | Returns the `RegexFlags` inner record used to construct the given `Regex`.
141+ foreign import flags' :: Regex -> RegexFlagsRec
142+
143+
68144
69145-- | Returns the string representation of the given `RegexFlags`.
70146renderFlags :: RegexFlags -> String
71- renderFlags f =
72- (if f.global then " g" else " " ) <>
147+ renderFlags ( RegexFlags f) =
148+ (if f.global then " g" else " " ) <>
73149 (if f.ignoreCase then " i" else " " ) <>
74- (if f.multiline then " m" else " " ) <>
75- (if f.sticky then " y" else " " ) <>
76- (if f.unicode then " u" else " " )
150+ (if f.multiline then " m" else " " ) <>
151+ (if f.sticky then " y" else " " ) <>
152+ (if f.unicode then " u" else " " )
77153
78154-- | Parses the string representation of `RegexFlags`.
79155parseFlags :: String -> RegexFlags
80- parseFlags s =
81- { global: contains " g" s
82- , ignoreCase: contains " i" s
83- , multiline: contains " m" s
84- , sticky: contains " y" s
85- , unicode: contains " u" s
156+ parseFlags str = RegexFlags
157+ { global : contains " g" str
158+ , ignoreCase : contains " i" str
159+ , multiline : contains " m" str
160+ , sticky : contains " y" str
161+ , unicode : contains " u" str
86162 }
87163
88164-- | Returns `true` if the `Regex` matches the string. In contrast to
0 commit comments