{-# LANGUAGE FlexibleContexts #-}

module Saturn.Unstable.Type.Range where

import qualified Control.Monad as Monad
import qualified Data.Coerce as Coerce
import qualified Data.Set as Set
import qualified Data.Text.Lazy.Builder as Builder
import qualified Data.Word as Word
import qualified Saturn.Unstable.Extra.Tuple as Tuple
import qualified Saturn.Unstable.Type.Number as Number
import qualified Text.Parsec as Parsec

newtype Range
  = Range (Number.Number, Number.Number)
  deriving (Range -> Range -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Range -> Range -> Bool
$c/= :: Range -> Range -> Bool
== :: Range -> Range -> Bool
$c== :: Range -> Range -> Bool
Eq, Int -> Range -> ShowS
[Range] -> ShowS
Range -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Range] -> ShowS
$cshowList :: [Range] -> ShowS
show :: Range -> String
$cshow :: Range -> String
showsPrec :: Int -> Range -> ShowS
$cshowsPrec :: Int -> Range -> ShowS
Show)

fromTuple :: (Number.Number, Number.Number) -> Maybe Range
fromTuple :: (Number, Number) -> Maybe Range
fromTuple (Number
lo, Number
hi) =
  if Number -> Word8
Number.toWord8 Number
lo forall a. Ord a => a -> a -> Bool
> Number -> Word8
Number.toWord8 Number
hi
    then forall a. Maybe a
Nothing
    else forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ (Number, Number) -> Range
Range (Number
lo, Number
hi)

toTuple :: Range -> (Number.Number, Number.Number)
toTuple :: Range -> (Number, Number)
toTuple = coerce :: forall a b. Coercible a b => a -> b
Coerce.coerce

parsec :: (Parsec.Stream s m Char) => Parsec.ParsecT s u m Range
parsec :: forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Range
parsec = do
  Number
lo <- forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Number
Number.parsec
  forall (f :: * -> *) a. Functor f => f a -> f ()
Monad.void forall a b. (a -> b) -> a -> b
$ forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
Parsec.char Char
'-'
  Number
hi <- forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Number
Number.parsec
  forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"invalid Range") forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ (Number, Number) -> Maybe Range
fromTuple (Number
lo, Number
hi)

toBuilder :: Range -> Builder.Builder
toBuilder :: Range -> Builder
toBuilder Range
range =
  let (Number
lo, Number
hi) = Range -> (Number, Number)
toTuple Range
range
   in Number -> Builder
Number.toBuilder Number
lo forall a. Semigroup a => a -> a -> a
<> Char -> Builder
Builder.singleton Char
'-' forall a. Semigroup a => a -> a -> a
<> Number -> Builder
Number.toBuilder Number
hi

isValid :: (Word.Word8, Word.Word8) -> Range -> Bool
isValid :: (Word8, Word8) -> Range -> Bool
isValid (Word8, Word8)
tuple = forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry Bool -> Bool -> Bool
(&&) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> (a, a) -> (b, b)
Tuple.mapBoth ((Word8, Word8) -> Number -> Bool
Number.isValid (Word8, Word8)
tuple) forall b c a. (b -> c) -> (a -> b) -> a -> c
. Range -> (Number, Number)
toTuple

expand :: Range -> Set.Set Word.Word8
expand :: Range -> Set Word8
expand =
  forall a. Ord a => [a] -> Set a
Set.fromList
    forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Enum a => (a, a) -> [a]
Tuple.toSequence
    forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> (a, a) -> (b, b)
Tuple.mapBoth Number -> Word8
Number.toWord8
    forall b c a. (b -> c) -> (a -> b) -> a -> c
. Range -> (Number, Number)
toTuple