module Language.Dickinson.Check.Duplicate ( checkDuplicates
                                          ) where

import           Control.Applicative      ((<|>))
import           Data.Foldable            (toList)
import           Data.Foldable.Ext        (foldMapAlternative)
import           Data.Function            (on)
import           Data.List                (groupBy, sortBy)
import           Data.Maybe               (mapMaybe)
import qualified Data.Text                as T
import           Language.Dickinson.Error
import           Language.Dickinson.Type

-- TODO: duplicate check better? hm
-- FIXME: HashSet or whatever?

checkNames :: [(a, T.Text)] -> Maybe (DickinsonWarning a)
checkNames :: forall a. [(a, Text)] -> Maybe (DickinsonWarning a)
checkNames [(a, Text)]
ns = forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Alternative f) =>
(a -> f b) -> t a -> f b
foldMapAlternative forall a. [(a, Text)] -> Maybe (DickinsonWarning a)
announce (forall a. (a -> a -> Bool) -> [a] -> [[a]]
groupBy (forall a. Eq a => a -> a -> Bool
(==) forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` forall a b. (a, b) -> b
snd) forall a b. (a -> b) -> a -> b
$ forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (forall a. Ord a => a -> a -> Ordering
compare forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` forall a b. (a, b) -> b
snd) [(a, Text)]
ns)
    where announce :: [(a, Text)] -> Maybe (DickinsonWarning a)
announce ((a, Text)
_:(a
l, Text
y):[(a, Text)]
_) = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a. a -> Text -> DickinsonWarning a
DuplicateStr a
l Text
y
          announce [(a, Text)]
_            = forall a. Maybe a
Nothing

-- | Check that there are not duplicates in branches.
checkDuplicates :: [Declaration a] -> Maybe (DickinsonWarning a)
checkDuplicates :: forall a. [Declaration a] -> Maybe (DickinsonWarning a)
checkDuplicates = forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Alternative f) =>
(a -> f b) -> t a -> f b
foldMapAlternative forall a. Declaration a -> Maybe (DickinsonWarning a)
checkDeclDuplicates

checkDeclDuplicates :: Declaration a -> Maybe (DickinsonWarning a)
checkDeclDuplicates :: forall a. Declaration a -> Maybe (DickinsonWarning a)
checkDeclDuplicates (Define a
_ Name a
_ Expression a
e) = forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates Expression a
e
checkDeclDuplicates TyDecl{}       = forall a. Maybe a
Nothing

extrText :: Expression a -> Maybe (a, T.Text)
extrText :: forall a. Expression a -> Maybe (a, Text)
extrText (Literal a
l Text
t) = forall (f :: * -> *) a. Applicative f => a -> f a
pure (a
l, Text
t)
extrText Expression a
_             = forall a. Maybe a
Nothing

collectText :: [(b, Expression a)] -> [(a, T.Text)]
collectText :: forall b a. [(b, Expression a)] -> [(a, Text)]
collectText = forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (forall a. Expression a -> Maybe (a, Text)
extrText forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd)

checkExprDuplicates :: Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates :: forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates Var{}              = forall a. Maybe a
Nothing
checkExprDuplicates Literal{}          = forall a. Maybe a
Nothing
checkExprDuplicates StrChunk{}         = forall a. Maybe a
Nothing
checkExprDuplicates (Interp a
_ [Expression a]
es)      = forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Alternative f) =>
(a -> f b) -> t a -> f b
foldMapAlternative forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates [Expression a]
es
checkExprDuplicates (MultiInterp a
_ [Expression a]
es) = forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Alternative f) =>
(a -> f b) -> t a -> f b
foldMapAlternative forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates [Expression a]
es
checkExprDuplicates (Concat a
_ [Expression a]
es)      = forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Alternative f) =>
(a -> f b) -> t a -> f b
foldMapAlternative forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates [Expression a]
es
checkExprDuplicates (Tuple a
_ NonEmpty (Expression a)
es)       = forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Alternative f) =>
(a -> f b) -> t a -> f b
foldMapAlternative forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates NonEmpty (Expression a)
es
checkExprDuplicates (Apply a
_ Expression a
e Expression a
e')     = forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates Expression a
e forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates Expression a
e'
checkExprDuplicates (Choice a
_ NonEmpty (Double, Expression a)
brs)     = forall a. [(a, Text)] -> Maybe (DickinsonWarning a)
checkNames (forall b a. [(b, Expression a)] -> [(a, Text)]
collectText forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t a -> [a]
toList NonEmpty (Double, Expression a)
brs)
checkExprDuplicates (Let a
_ NonEmpty (Name a, Expression a)
brs Expression a
es)     = forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Alternative f) =>
(a -> f b) -> t a -> f b
foldMapAlternative forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates (forall a b. (a, b) -> b
snd forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty (Name a, Expression a)
brs) forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates Expression a
es
checkExprDuplicates (Bind a
_ NonEmpty (Name a, Expression a)
brs Expression a
es)    = forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Alternative f) =>
(a -> f b) -> t a -> f b
foldMapAlternative forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates (forall a b. (a, b) -> b
snd forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmpty (Name a, Expression a)
brs) forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates Expression a
es
checkExprDuplicates (Lambda a
_ Name a
_ DickinsonTy a
_ Expression a
e)   = forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates Expression a
e
checkExprDuplicates (Match a
_ Expression a
e NonEmpty (Pattern a, Expression a)
brs)    = forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates Expression a
e forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Alternative f) =>
(a -> f b) -> t a -> f b
foldMapAlternative (forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd) NonEmpty (Pattern a, Expression a)
brs
checkExprDuplicates (Flatten a
_ Expression a
e)      = forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates Expression a
e
checkExprDuplicates (Annot a
_ Expression a
e DickinsonTy a
_)      = forall a. Expression a -> Maybe (DickinsonWarning a)
checkExprDuplicates Expression a
e
checkExprDuplicates Constructor{}      = forall a. Maybe a
Nothing
checkExprDuplicates BuiltinFn{}        = forall a. Maybe a
Nothing
checkExprDuplicates Random{}           = forall a. Maybe a
Nothing