@@ -25,7 +25,11 @@ module Text.Grammar.Distributor
2525 , genGrammar
2626 , printGrammar
2727 -- * RegEx
28- , RegEx (.. ), regexString , regexGrammar
28+ , RegEx (.. )
29+ , regexNorm
30+ , regexParse
31+ , regexString
32+ , regexGrammar
2933 ) where
3034
3135import Control.Applicative
@@ -79,6 +83,10 @@ and `IsString` with the property:
7983
8084prop> fromString = tokens
8185
86+ `Grammatical` has defaults for methods
87+ `inClass`, `notInClass`, `inCategory`, `notInCategory`
88+ in terms of `satisfy`;
89+ and `rule` & `ruleRec` in terms of `id` & `fix`.
8290-}
8391class
8492 ( Alternator p
@@ -104,11 +112,11 @@ class
104112 notInCategory cat = satisfy $ \ ch -> cat /= generalCategory ch
105113
106114 {- | A nonterminal rule. -}
107- rule :: String -> p a b -> p a b
115+ rule :: String -> p a a -> p a a
108116 rule _ = id
109117
110118 {- | A recursive, nonterminal rule. -}
111- ruleRec :: String -> (p a b -> p a b ) -> p a b
119+ ruleRec :: String -> (p a a -> p a a ) -> p a a
112120 ruleRec name = rule name . fix
113121
114122instance (Alternative f , Cons s s Char Char )
@@ -137,8 +145,6 @@ data RegEx
137145makeNestedPrisms ''RegEx
138146makeNestedPrisms ''GeneralCategory
139147
140- -- Kleene Star Algebra Operators
141-
142148(-*-) , (|||) :: RegEx -> RegEx -> RegEx
143149
144150Terminal " " -*- rex = rex
@@ -174,7 +180,47 @@ plusK Fail = Fail
174180plusK (Terminal " " ) = Terminal " "
175181plusK rex = KleenePlus rex
176182
177- -- RegEx generator
183+ {- | Normalize a `RegEx`.
184+
185+ >>> regexNorm (Sequence (Terminal "abc") (Terminal "xyz"))
186+ Terminal "abcxyz"
187+ -}
188+ regexNorm :: RegEx -> RegEx
189+ regexNorm = \ case
190+ Sequence rex0 rex1 -> regexNorm rex0 -*- regexNorm rex1
191+ Alternate rex0 rex1 -> regexNorm rex0 ||| regexNorm rex1
192+ KleeneOpt rex -> optK (regexNorm rex)
193+ KleeneStar rex -> starK (regexNorm rex)
194+ KleenePlus rex -> plusK (regexNorm rex)
195+ otherRegEx -> otherRegEx
196+
197+ {- | Parse a `RegEx` from a `String`.
198+
199+ >>> let str = "xy|z+"
200+ >>> regexParse str
201+ Alternate (Terminal "xy") (KleenePlus (Terminal "z"))
202+
203+ `Fail` if the `String` is not a valid regular expression.
204+
205+ >>> let bad = ")("
206+ >>> regexParse bad
207+ Fail
208+ -}
209+ regexParse :: String -> RegEx
210+ regexParse str = case readGrammar regexGrammar str of
211+ [] -> Fail
212+ rex: _ -> regexNorm rex
213+
214+ {- | The `RegEx` `String`.
215+
216+ >>> let rex = Alternate (Terminal "xy") (KleenePlus (Terminal "z"))
217+ >>> putStrLn (regexString rex)
218+ xy|z+
219+ -}
220+ regexString :: RegEx -> String
221+ regexString rex = maybe " \\ q" id (showGrammar regexGrammar rex)
222+
223+ -- RegEx Generator --
178224
179225newtype DiRegEx a b = DiRegEx RegEx
180226instance Functor (DiRegEx a ) where fmap = rmap
@@ -214,7 +260,7 @@ instance Grammatical DiRegEx where
214260 inCategory cat = DiRegEx (InCategory cat)
215261 notInCategory cat = DiRegEx (NotInCategory cat)
216262
217- -- Grammar generator
263+ -- Grammar Generator --
218264
219265data DiGrammar a b = DiGrammar
220266 { grammarStart :: DiRegEx a b
@@ -281,7 +327,7 @@ instance Grammatical DiGrammar where
281327
282328-- Generators --
283329
284- {- | Generate a `ReadS` from a `Grammar`. -}
330+ {- | Generate a `ReadS` parser from a `Grammar`. -}
285331genReadS :: Grammar a -> ReadS a
286332genReadS = runParsor
287333
@@ -293,7 +339,7 @@ readGrammar grammar str =
293339 , remaining == []
294340 ]
295341
296- {- | Generate a `ShowS` from a `Grammar`. -}
342+ {- | Generate `ShowS` printers from a `Grammar`. -}
297343genShowS :: Alternative f => Grammar a -> a -> f ShowS
298344genShowS = runPrintor
299345
@@ -309,7 +355,7 @@ genRegEx :: Grammar a -> RegEx
309355genRegEx (DiRegEx rex) = rex
310356
311357{- | Generate a context free grammar,
312- consisting of a @"start"@ and named `RegEx`es , from a `Grammar`.
358+ consisting of @"start"@ & named `RegEx` rules , from a `Grammar`.
313359-}
314360genGrammar :: Grammar a -> [(String , RegEx )]
315361genGrammar (DiGrammar (DiRegEx start) rules) =
@@ -322,15 +368,6 @@ printGrammar gram = for_ (genGrammar gram) $ \(name_i, rule_i) -> do
322368 putStr " = "
323369 putStrLn (regexString rule_i)
324370
325- {- | The `RegEx` `String`.
326-
327- >>> let rex = Terminal "xy" `Alternate` KleenePlus (Terminal "z")
328- >>> putStrLn (regexString rex)
329- xy|z+
330- -}
331- regexString :: RegEx -> String
332- regexString rex = maybe " \\ q" id (showGrammar regexGrammar rex)
333-
334371-- RegEx Grammar --
335372
336373{- | `regexGrammar` provides an important example of a `Grammar`.
@@ -459,7 +496,7 @@ nonterminalG :: Grammar RegEx
459496nonterminalG = rule " nonterminal" $
460497 _NonTerminal >?< " \\ q{" >* manyP charG *< " }"
461498
462- parenG :: Grammarr RegEx RegEx
499+ parenG :: Grammarr a a
463500parenG rex = rule " parenthesized" $
464501 " (" >* rex *< " )"
465502
0 commit comments