module Futhark.Profile.SourceRange (SourceRange (..), startLineCol, endLineCol, filter123, overlapsWith, mergeSemigroup, parse, fileName) where

import Control.Arrow ((&&&))
import Control.Monad (void, when)
import Data.Bifunctor (first)
import Data.Loc (Pos (Pos), posCol, posFile, posLine)
import Data.Text qualified as T
import Data.Void (Void)
import Text.Megaparsec qualified as P
import Text.Megaparsec.Char.Lexer qualified as L

-- | I chose this representation over `Loc` from `srcLoc` because it guarantees the presence of a range.
-- Loc is essentially a 'Maybe (Pos, Pos)', because of the 'NoLoc' constructor.
-- I cannot even imagine dealing with cross-file ranges anyway.

-- The end of the range is exclusive
data SourceRange = SourceRange
  { SourceRange -> Pos
startPos :: !Pos,
    -- | invariant: at least a big as start.line
    SourceRange -> Int
endLine :: !Int,
    -- | invariant: at least as big as start.col, unless the range spans multiple lines
    SourceRange -> Int
endColumn :: !Int
  }
  deriving (Int -> SourceRange -> ShowS
[SourceRange] -> ShowS
SourceRange -> String
(Int -> SourceRange -> ShowS)
-> (SourceRange -> String)
-> ([SourceRange] -> ShowS)
-> Show SourceRange
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SourceRange -> ShowS
showsPrec :: Int -> SourceRange -> ShowS
$cshow :: SourceRange -> String
show :: SourceRange -> String
$cshowList :: [SourceRange] -> ShowS
showList :: [SourceRange] -> ShowS
Show, SourceRange -> SourceRange -> Bool
(SourceRange -> SourceRange -> Bool)
-> (SourceRange -> SourceRange -> Bool) -> Eq SourceRange
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: SourceRange -> SourceRange -> Bool
== :: SourceRange -> SourceRange -> Bool
$c/= :: SourceRange -> SourceRange -> Bool
/= :: SourceRange -> SourceRange -> Bool
Eq, Eq SourceRange
Eq SourceRange =>
(SourceRange -> SourceRange -> Ordering)
-> (SourceRange -> SourceRange -> Bool)
-> (SourceRange -> SourceRange -> Bool)
-> (SourceRange -> SourceRange -> Bool)
-> (SourceRange -> SourceRange -> Bool)
-> (SourceRange -> SourceRange -> SourceRange)
-> (SourceRange -> SourceRange -> SourceRange)
-> Ord SourceRange
SourceRange -> SourceRange -> Bool
SourceRange -> SourceRange -> Ordering
SourceRange -> SourceRange -> SourceRange
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: SourceRange -> SourceRange -> Ordering
compare :: SourceRange -> SourceRange -> Ordering
$c< :: SourceRange -> SourceRange -> Bool
< :: SourceRange -> SourceRange -> Bool
$c<= :: SourceRange -> SourceRange -> Bool
<= :: SourceRange -> SourceRange -> Bool
$c> :: SourceRange -> SourceRange -> Bool
> :: SourceRange -> SourceRange -> Bool
$c>= :: SourceRange -> SourceRange -> Bool
>= :: SourceRange -> SourceRange -> Bool
$cmax :: SourceRange -> SourceRange -> SourceRange
max :: SourceRange -> SourceRange -> SourceRange
$cmin :: SourceRange -> SourceRange -> SourceRange
min :: SourceRange -> SourceRange -> SourceRange
Ord)

fileName :: SourceRange -> FilePath
fileName :: SourceRange -> String
fileName = Pos -> String
posFile (Pos -> String) -> (SourceRange -> Pos) -> SourceRange -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SourceRange -> Pos
startPos

-- | Extract start line and column
startLineCol :: SourceRange -> (Int, Int)
startLineCol :: SourceRange -> (Int, Int)
startLineCol (SourceRange Pos
pos Int
_ Int
_) = (Pos -> Int
posLine Pos
pos, Pos -> Int
posCol Pos
pos)

-- | Extract end line and column
endLineCol :: SourceRange -> (Int, Int)
endLineCol :: SourceRange -> (Int, Int)
endLineCol (SourceRange Pos
_ Int
line Int
col) = (Int
line, Int
col)

overlapsWith :: SourceRange -> SourceRange -> Bool
overlapsWith :: SourceRange -> SourceRange -> Bool
overlapsWith SourceRange
a SourceRange
b =
  -- since the end is exclusive, I need to use a different operator
  let rangeOverlaps :: (a, a) -> (a, a) -> Bool
rangeOverlaps (a
sa, a
ea) (a
sb, a
eb) = a
sa a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
eb Bool -> Bool -> Bool
&& a
sb a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< a
ea
      startA :: (Int, Int)
startA = SourceRange -> (Int, Int)
startLineCol SourceRange
a
      endA :: (Int, Int)
endA = SourceRange -> (Int, Int)
endLineCol SourceRange
a
      startB :: (Int, Int)
startB = SourceRange -> (Int, Int)
startLineCol SourceRange
b
      endB :: (Int, Int)
endB = SourceRange -> (Int, Int)
endLineCol SourceRange
b
   in ((Int, Int), (Int, Int)) -> ((Int, Int), (Int, Int)) -> Bool
forall {a} {a}. (Ord a, Ord a) => (a, a) -> (a, a) -> Bool
rangeOverlaps ((Int, Int)
startA, (Int, Int)
endA) ((Int, Int)
startB, (Int, Int)
endB)

-- >>> isEmpty $ SourceRange {sourceRangeStartPos = Pos "Futhark.fut" 4 40 (-1), sourceRangeEndLine = 4, sourceRangeEndColumn = 40}
-- True

isEmpty :: SourceRange -> Bool
isEmpty :: SourceRange -> Bool
isEmpty (SourceRange (Pos String
_ Int
startLine Int
startCol Int
_) Int
endLine Int
endCol) =
  Int
startLine Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
endLine Bool -> Bool -> Bool
&& Int
startCol Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
endCol

-- | Parse a source range, respect the invariants noted in the definition
-- and print the MegaParsec errorbundle into a Text.
--
-- >>> parse "example.fut:1:1-5"
-- Right (SourceRange {start = Pos "example.fut" 1 1 (-1), endLine = 1, endColumn = 5})
--
-- >>> parse "directory/example.fut:15:12-17:1"
-- Right (SourceRange {start = Pos "directory/example.fut" 15 12 (-1), endLine = 17, endColumn = 1})
parse :: T.Text -> Either T.Text SourceRange
parse :: Text -> Either Text SourceRange
parse Text
text = (ParseErrorBundle Text Void -> Text)
-> Either (ParseErrorBundle Text Void) SourceRange
-> Either Text SourceRange
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first ParseErrorBundle Text Void -> Text
textErrorBundle (Either (ParseErrorBundle Text Void) SourceRange
 -> Either Text SourceRange)
-> Either (ParseErrorBundle Text Void) SourceRange
-> Either Text SourceRange
forall a b. (a -> b) -> a -> b
$ Parsec Void Text SourceRange
-> String
-> Text
-> Either (ParseErrorBundle Text Void) SourceRange
forall e s a.
Parsec e s a -> String -> s -> Either (ParseErrorBundle s e) a
P.parse Parsec Void Text SourceRange
pSourceRange String
fname Text
text
  where
    fname :: String
fname = String
""
    textErrorBundle :: ParseErrorBundle Text Void -> Text
textErrorBundle = String -> Text
T.pack (String -> Text)
-> (ParseErrorBundle Text Void -> String)
-> ParseErrorBundle Text Void
-> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParseErrorBundle Text Void -> String
forall s e.
(VisualStream s, TraversableStream s, ShowErrorComponent e) =>
ParseErrorBundle s e -> String
P.errorBundlePretty

    lineRangeInvariantMessage :: String
lineRangeInvariantMessage =
      String
"End of Line Range is not bigger than or equal to Start of Line Range."
    columnRangeInvariantMessage :: String
columnRangeInvariantMessage =
      String
"End of Column Range is not bigger than or equal to Start of Column Range"

    pSourceRange :: P.Parsec Void T.Text SourceRange
    pSourceRange :: Parsec Void Text SourceRange
pSourceRange = do
      filePath <- ParsecT Void Text Identity Char
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m Char
L.charLiteral ParsecT Void Text Identity Char
-> ParsecT Void Text Identity (Token Text)
-> ParsecT Void Text Identity String
forall (m :: * -> *) a end. MonadPlus m => m a -> m end -> m [a]
`P.manyTill` Token Text -> ParsecT Void Text Identity (Token Text)
forall e s (m :: * -> *).
MonadParsec e s m =>
Token s -> m (Token s)
P.single Char
Token Text
':' -- separator
      startLine <- L.decimal
      void $ P.single ':' -- separator
      startCol <- L.decimal

      void $ P.single '-' -- range begin
      rangeEnd1 <- L.decimal
      -- we can't know yet whether this is going to be a line or column position

      (lineRangeEnd, columnRangeEnd) <-
        P.choice
          [ do
              endCol <- P.single ':' *> L.decimal
              pure (rangeEnd1, endCol),
            pure (startLine, rangeEnd1)
          ]

      let lineRangeInvalid = Int
startLine Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
lineRangeEnd
      when lineRangeInvalid $ fail lineRangeInvariantMessage

      let columnRangeInvalid =
            Int
startLine Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
lineRangeEnd Bool -> Bool -> Bool
&& Int
startCol Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
columnRangeEnd
      when columnRangeInvalid $ fail columnRangeInvariantMessage

      pure $
        SourceRange
          { startPos = Pos filePath startLine startCol (-1),
            endLine = lineRangeEnd,
            endColumn = columnRangeEnd
          }

-- | Assumes that the ranges overlap
mergeSemigroup ::
  (Semigroup s) =>
  (SourceRange, s) ->
  (SourceRange, s) ->
  OneTwoThree (SourceRange, s)
mergeSemigroup :: forall s.
Semigroup s =>
(SourceRange, s)
-> (SourceRange, s) -> OneTwoThree (SourceRange, s)
mergeSemigroup a :: (SourceRange, s)
a@(SourceRange
rangeA, s
auxA) b :: (SourceRange, s)
b@(SourceRange
rangeB, s
auxB) =
  let orderedBy :: (b -> a) -> b -> b -> (b, b)
orderedBy b -> a
f b
x b
y = if b -> a
f b
x a -> a -> Bool
forall a. Ord a => a -> a -> Bool
< b -> a
f b
y then (b
x, b
y) else (b
y, b
x)
      ((SourceRange, s)
startsEarlier, (SourceRange, s)
startsLater) = ((SourceRange, s) -> (Int, Int))
-> (SourceRange, s)
-> (SourceRange, s)
-> ((SourceRange, s), (SourceRange, s))
forall {a} {b}. Ord a => (b -> a) -> b -> b -> (b, b)
orderedBy (SourceRange -> (Int, Int)
startLineCol (SourceRange -> (Int, Int))
-> ((SourceRange, s) -> SourceRange)
-> (SourceRange, s)
-> (Int, Int)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SourceRange, s) -> SourceRange
forall a b. (a, b) -> a
fst) (SourceRange, s)
a (SourceRange, s)
b

      startsLaterStart :: (Int, Int)
startsLaterStart = SourceRange -> (Int, Int)
startLineCol (SourceRange -> (Int, Int))
-> ((SourceRange, s) -> SourceRange)
-> (SourceRange, s)
-> (Int, Int)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SourceRange, s) -> SourceRange
forall a b. (a, b) -> a
fst ((SourceRange, s) -> (Int, Int)) -> (SourceRange, s) -> (Int, Int)
forall a b. (a -> b) -> a -> b
$ (SourceRange, s)
startsLater
      fname :: String
fname = Pos -> String
posFile (Pos -> String) -> (SourceRange -> Pos) -> SourceRange -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SourceRange -> Pos
startPos (SourceRange -> String) -> SourceRange -> String
forall a b. (a -> b) -> a -> b
$ SourceRange
rangeA

      ((SourceRange, s)
endsEarlier, (SourceRange, s)
endsLater) =
        ((SourceRange, s) -> (Int, Int))
-> (SourceRange, s)
-> (SourceRange, s)
-> ((SourceRange, s), (SourceRange, s))
forall {a} {b}. Ord a => (b -> a) -> b -> b -> (b, b)
orderedBy
          ((SourceRange -> Int
endLine (SourceRange -> Int)
-> (SourceRange -> Int) -> SourceRange -> (Int, Int)
forall b c c'. (b -> c) -> (b -> c') -> b -> (c, c')
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& SourceRange -> Int
endColumn) (SourceRange -> (Int, Int))
-> ((SourceRange, s) -> SourceRange)
-> (SourceRange, s)
-> (Int, Int)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SourceRange, s) -> SourceRange
forall a b. (a, b) -> a
fst)
          (SourceRange, s)
a
          (SourceRange, s)
b

      firstRange :: SourceRange
firstRange =
        ((SourceRange, s) -> SourceRange
forall a b. (a, b) -> a
fst (SourceRange, s)
startsEarlier)
          { endLine = fst startsLaterStart,
            endColumn = snd startsLaterStart
          }
      secondRange :: SourceRange
secondRange =
        ((SourceRange, s) -> SourceRange
forall a b. (a, b) -> a
fst (SourceRange, s)
startsLater)
          { endLine = endLine . fst $ endsEarlier,
            endColumn = endColumn . fst $ endsEarlier
          }

      thirdRange :: SourceRange
thirdRange =
        let startLine :: Int
startLine = SourceRange -> Int
endLine SourceRange
secondRange
            startCol :: Int
startCol = SourceRange -> Int
endColumn SourceRange
secondRange
         in ((SourceRange, s) -> SourceRange
forall a b. (a, b) -> a
fst (SourceRange, s)
endsLater)
              { startPos = Pos fname startLine startCol (-1)
              }

      rawRanges :: OneTwoThree (SourceRange, s)
rawRanges =
        (SourceRange, s)
-> (SourceRange, s)
-> (SourceRange, s)
-> OneTwoThree (SourceRange, s)
forall a. a -> a -> a -> OneTwoThree a
Three
          (SourceRange
firstRange, (SourceRange, s) -> s
forall a b. (a, b) -> b
snd (SourceRange, s)
startsEarlier)
          (SourceRange
secondRange, s
auxA s -> s -> s
forall a. Semigroup a => a -> a -> a
<> s
auxB)
          (SourceRange
thirdRange, (SourceRange, s) -> s
forall a b. (a, b) -> b
snd (SourceRange, s)
endsLater)
   in case ((SourceRange, s) -> Bool)
-> OneTwoThree (SourceRange, s)
-> Maybe (OneTwoThree (SourceRange, s))
forall a. (a -> Bool) -> OneTwoThree a -> Maybe (OneTwoThree a)
filter123 (Bool -> Bool
not (Bool -> Bool)
-> ((SourceRange, s) -> Bool) -> (SourceRange, s) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SourceRange -> Bool
isEmpty (SourceRange -> Bool)
-> ((SourceRange, s) -> SourceRange) -> (SourceRange, s) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SourceRange, s) -> SourceRange
forall a b. (a, b) -> a
fst) OneTwoThree (SourceRange, s)
rawRanges of
        Maybe (OneTwoThree (SourceRange, s))
Nothing ->
          String -> OneTwoThree (SourceRange, s)
forall a. HasCallStack => String -> a
error (String -> OneTwoThree (SourceRange, s))
-> ([String] -> String) -> [String] -> OneTwoThree (SourceRange, s)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> String
unwords ([String] -> OneTwoThree (SourceRange, s))
-> [String] -> OneTwoThree (SourceRange, s)
forall a b. (a -> b) -> a -> b
$
            [ String
"Impossible! `mergeRanges` produced no range at all, input ranges:",
              SourceRange -> String
forall a. Show a => a -> String
show SourceRange
rangeA,
              SourceRange -> String
forall a. Show a => a -> String
show SourceRange
rangeB
            ]
        Just OneTwoThree (SourceRange, s)
merged -> OneTwoThree (SourceRange, s)
merged

data OneTwoThree a = One a | Two a a | Three a a a
  deriving (Int -> OneTwoThree a -> ShowS
[OneTwoThree a] -> ShowS
OneTwoThree a -> String
(Int -> OneTwoThree a -> ShowS)
-> (OneTwoThree a -> String)
-> ([OneTwoThree a] -> ShowS)
-> Show (OneTwoThree a)
forall a. Show a => Int -> OneTwoThree a -> ShowS
forall a. Show a => [OneTwoThree a] -> ShowS
forall a. Show a => OneTwoThree a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Show a => Int -> OneTwoThree a -> ShowS
showsPrec :: Int -> OneTwoThree a -> ShowS
$cshow :: forall a. Show a => OneTwoThree a -> String
show :: OneTwoThree a -> String
$cshowList :: forall a. Show a => [OneTwoThree a] -> ShowS
showList :: [OneTwoThree a] -> ShowS
Show, (forall a b. (a -> b) -> OneTwoThree a -> OneTwoThree b)
-> (forall a b. a -> OneTwoThree b -> OneTwoThree a)
-> Functor OneTwoThree
forall a b. a -> OneTwoThree b -> OneTwoThree a
forall a b. (a -> b) -> OneTwoThree a -> OneTwoThree b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
$cfmap :: forall a b. (a -> b) -> OneTwoThree a -> OneTwoThree b
fmap :: forall a b. (a -> b) -> OneTwoThree a -> OneTwoThree b
$c<$ :: forall a b. a -> OneTwoThree b -> OneTwoThree a
<$ :: forall a b. a -> OneTwoThree b -> OneTwoThree a
Functor, (forall m. Monoid m => OneTwoThree m -> m)
-> (forall m a. Monoid m => (a -> m) -> OneTwoThree a -> m)
-> (forall m a. Monoid m => (a -> m) -> OneTwoThree a -> m)
-> (forall a b. (a -> b -> b) -> b -> OneTwoThree a -> b)
-> (forall a b. (a -> b -> b) -> b -> OneTwoThree a -> b)
-> (forall b a. (b -> a -> b) -> b -> OneTwoThree a -> b)
-> (forall b a. (b -> a -> b) -> b -> OneTwoThree a -> b)
-> (forall a. (a -> a -> a) -> OneTwoThree a -> a)
-> (forall a. (a -> a -> a) -> OneTwoThree a -> a)
-> (forall a. OneTwoThree a -> [a])
-> (forall a. OneTwoThree a -> Bool)
-> (forall a. OneTwoThree a -> Int)
-> (forall a. Eq a => a -> OneTwoThree a -> Bool)
-> (forall a. Ord a => OneTwoThree a -> a)
-> (forall a. Ord a => OneTwoThree a -> a)
-> (forall a. Num a => OneTwoThree a -> a)
-> (forall a. Num a => OneTwoThree a -> a)
-> Foldable OneTwoThree
forall a. Eq a => a -> OneTwoThree a -> Bool
forall a. Num a => OneTwoThree a -> a
forall a. Ord a => OneTwoThree a -> a
forall m. Monoid m => OneTwoThree m -> m
forall a. OneTwoThree a -> Bool
forall a. OneTwoThree a -> Int
forall a. OneTwoThree a -> [a]
forall a. (a -> a -> a) -> OneTwoThree a -> a
forall m a. Monoid m => (a -> m) -> OneTwoThree a -> m
forall b a. (b -> a -> b) -> b -> OneTwoThree a -> b
forall a b. (a -> b -> b) -> b -> OneTwoThree a -> b
forall (t :: * -> *).
(forall m. Monoid m => t m -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. t a -> [a])
-> (forall a. t a -> Bool)
-> (forall a. t a -> Int)
-> (forall a. Eq a => a -> t a -> Bool)
-> (forall a. Ord a => t a -> a)
-> (forall a. Ord a => t a -> a)
-> (forall a. Num a => t a -> a)
-> (forall a. Num a => t a -> a)
-> Foldable t
$cfold :: forall m. Monoid m => OneTwoThree m -> m
fold :: forall m. Monoid m => OneTwoThree m -> m
$cfoldMap :: forall m a. Monoid m => (a -> m) -> OneTwoThree a -> m
foldMap :: forall m a. Monoid m => (a -> m) -> OneTwoThree a -> m
$cfoldMap' :: forall m a. Monoid m => (a -> m) -> OneTwoThree a -> m
foldMap' :: forall m a. Monoid m => (a -> m) -> OneTwoThree a -> m
$cfoldr :: forall a b. (a -> b -> b) -> b -> OneTwoThree a -> b
foldr :: forall a b. (a -> b -> b) -> b -> OneTwoThree a -> b
$cfoldr' :: forall a b. (a -> b -> b) -> b -> OneTwoThree a -> b
foldr' :: forall a b. (a -> b -> b) -> b -> OneTwoThree a -> b
$cfoldl :: forall b a. (b -> a -> b) -> b -> OneTwoThree a -> b
foldl :: forall b a. (b -> a -> b) -> b -> OneTwoThree a -> b
$cfoldl' :: forall b a. (b -> a -> b) -> b -> OneTwoThree a -> b
foldl' :: forall b a. (b -> a -> b) -> b -> OneTwoThree a -> b
$cfoldr1 :: forall a. (a -> a -> a) -> OneTwoThree a -> a
foldr1 :: forall a. (a -> a -> a) -> OneTwoThree a -> a
$cfoldl1 :: forall a. (a -> a -> a) -> OneTwoThree a -> a
foldl1 :: forall a. (a -> a -> a) -> OneTwoThree a -> a
$ctoList :: forall a. OneTwoThree a -> [a]
toList :: forall a. OneTwoThree a -> [a]
$cnull :: forall a. OneTwoThree a -> Bool
null :: forall a. OneTwoThree a -> Bool
$clength :: forall a. OneTwoThree a -> Int
length :: forall a. OneTwoThree a -> Int
$celem :: forall a. Eq a => a -> OneTwoThree a -> Bool
elem :: forall a. Eq a => a -> OneTwoThree a -> Bool
$cmaximum :: forall a. Ord a => OneTwoThree a -> a
maximum :: forall a. Ord a => OneTwoThree a -> a
$cminimum :: forall a. Ord a => OneTwoThree a -> a
minimum :: forall a. Ord a => OneTwoThree a -> a
$csum :: forall a. Num a => OneTwoThree a -> a
sum :: forall a. Num a => OneTwoThree a -> a
$cproduct :: forall a. Num a => OneTwoThree a -> a
product :: forall a. Num a => OneTwoThree a -> a
Foldable)

filter123 :: (a -> Bool) -> OneTwoThree a -> Maybe (OneTwoThree a)
filter123 :: forall a. (a -> Bool) -> OneTwoThree a -> Maybe (OneTwoThree a)
filter123 a -> Bool
p self :: OneTwoThree a
self@(One a
x) = if a -> Bool
p a
x then OneTwoThree a -> Maybe (OneTwoThree a)
forall a. a -> Maybe a
Just OneTwoThree a
self else Maybe (OneTwoThree a)
forall a. Maybe a
Nothing
filter123 a -> Bool
p self :: OneTwoThree a
self@(Two a
x a
y) = case (a -> Bool
p a
x, a -> Bool
p a
y) of
  (Bool
True, Bool
True) -> OneTwoThree a -> Maybe (OneTwoThree a)
forall a. a -> Maybe a
Just OneTwoThree a
self
  (Bool
True, Bool
False) -> OneTwoThree a -> Maybe (OneTwoThree a)
forall a. a -> Maybe a
Just (a -> OneTwoThree a
forall a. a -> OneTwoThree a
One a
x)
  (Bool
False, Bool
True) -> OneTwoThree a -> Maybe (OneTwoThree a)
forall a. a -> Maybe a
Just (a -> OneTwoThree a
forall a. a -> OneTwoThree a
One a
y)
  (Bool
False, Bool
False) -> Maybe (OneTwoThree a)
forall a. Maybe a
Nothing
filter123 a -> Bool
p self :: OneTwoThree a
self@(Three a
x a
y a
z) = case (a -> Bool
p a
x, a -> Bool
p a
y, a -> Bool
p a
z) of
  (Bool
False, Bool
False, Bool
False) -> Maybe (OneTwoThree a)
forall a. Maybe a
Nothing
  (Bool
False, Bool
False, Bool
True) -> OneTwoThree a -> Maybe (OneTwoThree a)
forall a. a -> Maybe a
Just (a -> OneTwoThree a
forall a. a -> OneTwoThree a
One a
z)
  (Bool
False, Bool
True, Bool
False) -> OneTwoThree a -> Maybe (OneTwoThree a)
forall a. a -> Maybe a
Just (a -> OneTwoThree a
forall a. a -> OneTwoThree a
One a
y)
  (Bool
False, Bool
True, Bool
True) -> OneTwoThree a -> Maybe (OneTwoThree a)
forall a. a -> Maybe a
Just (a -> a -> OneTwoThree a
forall a. a -> a -> OneTwoThree a
Two a
y a
z)
  (Bool
True, Bool
False, Bool
False) -> OneTwoThree a -> Maybe (OneTwoThree a)
forall a. a -> Maybe a
Just (a -> OneTwoThree a
forall a. a -> OneTwoThree a
One a
x)
  (Bool
True, Bool
False, Bool
True) -> OneTwoThree a -> Maybe (OneTwoThree a)
forall a. a -> Maybe a
Just (a -> a -> OneTwoThree a
forall a. a -> a -> OneTwoThree a
Two a
x a
z)
  (Bool
True, Bool
True, Bool
False) -> OneTwoThree a -> Maybe (OneTwoThree a)
forall a. a -> Maybe a
Just (a -> a -> OneTwoThree a
forall a. a -> a -> OneTwoThree a
Two a
x a
y)
  (Bool
True, Bool
True, Bool
True) -> OneTwoThree a -> Maybe (OneTwoThree a)
forall a. a -> Maybe a
Just OneTwoThree a
self