content: module Kempe.Check.TopLevel ( topLevelCheck
                              , Warning
                              ) where
  
  import           Control.Applicative ((<|>))
  import           Data.Foldable       (toList)
  import           Data.Foldable.Ext
  import           Data.List           (group, sort)
  import           Data.Maybe          (mapMaybe)
  import           Kempe.AST
  import           Kempe.Error.Warning
  import           Kempe.Name
  
  topLevelCheck :: Declarations a c a -> Maybe (Warning a)
  topLevelCheck ds =
          checkNames (collectNames ds)
      <|> checkNames (collectCons ds)
  
  -- | Just checks function names and type names. Doesn't check constructors.
  collectNames :: Declarations a c a -> [Name a]
  collectNames = mapMaybe collectDeclNames where
      collectDeclNames (FunDecl _ n _ _ _)   = Just n
      collectDeclNames (ExtFnDecl _ n _ _ _) = Just n
      collectDeclNames Export{}              = Nothing
      collectDeclNames (TyDecl _ tn _ _)     = Just tn
  
  collectCons :: Declarations a c b-> [Name b]
  collectCons = concatMap collectDeclNames where
      collectDeclNames (TyDecl _ _ _ ls) = toList (fst <$> ls)
      collectDeclNames _                 = []
  
  checkNames :: [Name a] -> Maybe (Warning a)
  checkNames ns = foldMapAlternative announce (group $ sort ns) -- maybe could be better idk
      where announce (_:y:_) = Just $ NameClash (loc y) y
            announce _       = Nothing
  