{-# LANGUAGE CPP #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE Safe #-}
module Kleene.Functor.NonEmpty (
K1,
Greediness (..),
some1,
anyChar,
oneof,
char,
charRange,
dot,
everything1,
string,
isEmpty,
isEverything,
match,
toRE,
toKleene,
toRA,
nullableProof,
) where
import Prelude ()
import Prelude.Compat
import Control.Applicative (Alternative (..), liftA2)
import Data.Foldable (toList)
import Data.Functor.Alt ((<!>))
import Data.Functor.Apply (Apply (..))
import Data.List.NonEmpty (NonEmpty (..))
import Data.RangeSet.Map (RSet)
import qualified Data.Functor.Alt as Alt
import qualified Data.List.NonEmpty as NE
import qualified Data.RangeSet.Map as RSet
import qualified Text.Regex.Applicative as R
import qualified Kleene.Classes as C
import Kleene.Internal.Functor (Greediness (..), K (..))
import Kleene.Internal.Pretty
import Kleene.Internal.Sets
import qualified Kleene.RE as RE
data K1 c a where
K1Empty :: K1 c a
K1Char :: (Ord c, Enum c) => RSet c -> K1 c c
K1Append :: (a -> b -> r) -> K1 c a -> K1 c b -> K1 c r
K1Union :: K1 c a -> K1 c a -> K1 c a
KPlus :: Greediness -> K1 c a -> K1 c (NonEmpty a)
K1Map :: (a -> b) -> K1 c a -> K1 c b
K1String :: Eq c => NonEmpty c -> K1 c (NonEmpty c)
instance Functor (K1 c) where
fmap _ K1Empty = K1Empty
fmap f (K1Map g k) = K1Map (f . g) k
fmap f (K1Append g a b) = K1Append (\x y -> f (g x y)) a b
fmap f k = K1Map f k
instance Apply (K1 c) where
K1Empty <.> _ = K1Empty
_ <.> K1Empty = K1Empty
f <.> x = K1Append ($) f x
liftF2 = K1Append
instance Alt.Alt (K1 c) where
K1Empty <!> k = k
k <!> K1Empty = k
K1Char a <!> K1Char b = K1Char (RSet.union a b)
a <!> b = K1Union a b
some1 :: K1 c a -> K1 c (NonEmpty a)
some1 K1Empty = K1Empty
some1 (KPlus _ k) = K1Map pure (KPlus Greedy k)
some1 k = KPlus Greedy k
few1 :: K1 c a -> K1 c (NonEmpty a)
few1 K1Empty = K1Empty
few1 (KPlus _ k) = K1Map pure (KPlus NonGreedy k)
few1 k = KPlus NonGreedy k
anyChar :: (Ord c, Enum c, Bounded c) => K1 c c
anyChar = K1Char RSet.full
oneof :: (Ord c, Enum c, Foldable f) => f c -> K1 c c
oneof = K1Char . RSet.fromList . toList
char :: (Ord c, Enum c) => c -> K1 c c
char = K1Char . RSet.singleton
charRange :: (Enum c, Ord c) => c -> c -> K1 c c
charRange a b = K1Char (RSet.singletonRange (a, b))
dot :: K1 Char Char
dot = K1Char dotRSet
everything1 :: (Ord c, Enum c, Bounded c) => K1 c (NonEmpty c)
everything1 = some1 anyChar
isEmpty :: (Ord c, Enum c, Bounded c) => K1 c a -> Bool
isEmpty k = C.equivalent (toRE k) C.empty
isEverything :: (Ord c, Enum c, Bounded c) => K1 c a -> Bool
isEverything k = C.equivalent (toRE k) C.everything
string :: String -> K1 Char (NonEmpty Char)
string [] = error "panic! K1.string []"
string (x : xs) = K1String (x :| xs)
match :: K1 c a -> [c] -> Maybe a
match = R.match . toRA
toRE :: (Ord c, Enum c, Bounded c) => K1 c a -> RE.RE c
toRE = toKleene
toKleene :: C.FiniteKleene c k => K1 c a -> k
toKleene (K1Map _ a) = toKleene a
toKleene (K1Union a b) = C.unions [toKleene a, toKleene b]
toKleene (K1Append _ a b) = C.appends [toKleene a, toKleene b]
toKleene (KPlus _ a) = let k = toKleene a in C.appends [k, C.star k]
toKleene (K1String s) = C.appends (map C.char $ NE.toList s)
toKleene K1Empty = C.empty
toKleene (K1Char cs) = C.fromRSet cs
toRA :: K1 c a -> R.RE c a
toRA K1Empty = empty
toRA (K1Char cs) = R.psym (\c -> RSet.member c cs)
toRA (K1Append f a b) = liftA2 f (toRA a) (toRA b)
toRA (K1Union a b) = toRA a <|> toRA b
toRA (KPlus Greedy a) = (:|) <$> toRA a <*> many (toRA a)
toRA (KPlus NonGreedy a) = (:|) <$> toRA a <*> R.few (toRA a)
toRA (K1Map f a) = fmap f (toRA a)
toRA (K1String (x :| xs)) = (:|) <$> R.sym x <*> R.string xs
nullableProof :: K c a -> Either (K1 c a) (a, K1 c a)
nullableProof KEmpty = Left K1Empty
nullableProof (KPure x) = Right (x, K1Empty)
nullableProof (KChar c) = Left (K1Char c)
nullableProof (KAppend f a b) = case (nullableProof a, nullableProof b) of
(Left x, Left y) -> Left (K1Append f x y)
(Left x, Right (y', y)) -> Left ((`f` y') <$> x <!> K1Append f x y)
(Right (x', x), Left y) -> Left (K1Append f x y <!> f x' <$> y)
(Right (x', x), Right (y', y)) -> Right
(f x' y'
, K1Append f x y
<!> flip f y' <$> x
<!> f x' <$> y
)
nullableProof (KUnion a b) = case (nullableProof a, nullableProof b) of
(Left x', Left _) -> Left x'
(Right (x, x'), Left y') -> Right (x, x' <!> y')
(Left x', Right (y, y')) -> Right (y, x' <!> y')
(Right (x, x'), Right (_, y')) -> Right (x, x' <!> y')
nullableProof (KStar g a) = case nullableProof a of
Left x -> Right ([], NE.toList <$> star1 x)
Right (_, x) -> Right ([], NE.toList <$> star1 x)
where
star1 = case g of
Greedy -> some1
NonGreedy -> few1
nullableProof (KMap f a) = case nullableProof a of
Right (x, x') -> Right (f x, fmap f x')
Left x' -> Left (fmap f x')
nullableProof (KString []) = Right ([], K1Empty)
nullableProof (KString (c : cs)) = Left (NE.toList <$> K1String (c :| cs))
instance c ~ Char => Pretty (K1 c a) where
pretty = pretty . toRE