{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module HSE.Scope(
    Scope, scopeCreate, scopeImports
    ) where

import Data.Semigroup
import HSE.Type
import HSE.Util
import Data.List
import Data.Maybe
import Prelude

{-
the hint file can do:

import Prelude (filter)
import Data.List (filter)
import List (filter)

then filter on it's own will get expanded to all of them

import Data.List
import List as Data.List


if Data.List.head x ==> x, then that might match List too
-}


-- | Data type representing the modules in scope within a module.
--   Created with 'scopeCreate' and queried with 'scopeMatch' and 'scopeMove'.
--   Note that the 'mempty' 'Scope' is not equivalent to 'scopeCreate' on an empty module,
--   due to the implicit import of 'Prelude'.
newtype Scope = Scope [ImportDecl S]
             deriving (Int -> Scope -> ShowS
[Scope] -> ShowS
Scope -> String
(Int -> Scope -> ShowS)
-> (Scope -> String) -> ([Scope] -> ShowS) -> Show Scope
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Scope] -> ShowS
$cshowList :: [Scope] -> ShowS
show :: Scope -> String
$cshow :: Scope -> String
showsPrec :: Int -> Scope -> ShowS
$cshowsPrec :: Int -> Scope -> ShowS
Show, Semigroup Scope
Scope
Semigroup Scope =>
Scope
-> (Scope -> Scope -> Scope) -> ([Scope] -> Scope) -> Monoid Scope
[Scope] -> Scope
Scope -> Scope -> Scope
forall a.
Semigroup a =>
a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
mconcat :: [Scope] -> Scope
$cmconcat :: [Scope] -> Scope
mappend :: Scope -> Scope -> Scope
$cmappend :: Scope -> Scope -> Scope
mempty :: Scope
$cmempty :: Scope
$cp1Monoid :: Semigroup Scope
Monoid, b -> Scope -> Scope
NonEmpty Scope -> Scope
Scope -> Scope -> Scope
(Scope -> Scope -> Scope)
-> (NonEmpty Scope -> Scope)
-> (forall b. Integral b => b -> Scope -> Scope)
-> Semigroup Scope
forall b. Integral b => b -> Scope -> Scope
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
stimes :: b -> Scope -> Scope
$cstimes :: forall b. Integral b => b -> Scope -> Scope
sconcat :: NonEmpty Scope -> Scope
$csconcat :: NonEmpty Scope -> Scope
<> :: Scope -> Scope -> Scope
$c<> :: Scope -> Scope -> Scope
Semigroup)

-- | Create a 'Scope' value from a module, based on the modules imports.
scopeCreate :: Module SrcSpanInfo -> Scope
scopeCreate :: Module SrcSpanInfo -> Scope
scopeCreate xs :: Module SrcSpanInfo
xs = [ImportDecl SrcSpanInfo] -> Scope
Scope ([ImportDecl SrcSpanInfo] -> Scope)
-> [ImportDecl SrcSpanInfo] -> Scope
forall a b. (a -> b) -> a -> b
$ [ImportDecl SrcSpanInfo
prelude | Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ (ImportDecl SrcSpanInfo -> Bool)
-> [ImportDecl SrcSpanInfo] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ImportDecl SrcSpanInfo -> Bool
isPrelude [ImportDecl SrcSpanInfo]
res] [ImportDecl SrcSpanInfo]
-> [ImportDecl SrcSpanInfo] -> [ImportDecl SrcSpanInfo]
forall a. [a] -> [a] -> [a]
++ [ImportDecl SrcSpanInfo]
res
    where
        res :: [ImportDecl SrcSpanInfo]
res = [ImportDecl SrcSpanInfo
x | ImportDecl SrcSpanInfo
x <- Module SrcSpanInfo -> [ImportDecl SrcSpanInfo]
moduleImports Module SrcSpanInfo
xs, ImportDecl SrcSpanInfo -> Maybe String
forall l. ImportDecl l -> Maybe String
importPkg ImportDecl SrcSpanInfo
x Maybe String -> Maybe String -> Bool
forall a. Eq a => a -> a -> Bool
/= String -> Maybe String
forall a. a -> Maybe a
Just "hint"]
        prelude :: ImportDecl SrcSpanInfo
prelude = SrcSpanInfo
-> ModuleName SrcSpanInfo
-> Bool
-> Bool
-> Bool
-> Maybe String
-> Maybe (ModuleName SrcSpanInfo)
-> Maybe (ImportSpecList SrcSpanInfo)
-> ImportDecl SrcSpanInfo
forall l.
l
-> ModuleName l
-> Bool
-> Bool
-> Bool
-> Maybe String
-> Maybe (ModuleName l)
-> Maybe (ImportSpecList l)
-> ImportDecl l
ImportDecl SrcSpanInfo
an (SrcSpanInfo -> String -> ModuleName SrcSpanInfo
forall l. l -> String -> ModuleName l
ModuleName SrcSpanInfo
an "Prelude") Bool
False Bool
False Bool
False Maybe String
forall a. Maybe a
Nothing Maybe (ModuleName SrcSpanInfo)
forall a. Maybe a
Nothing Maybe (ImportSpecList SrcSpanInfo)
forall a. Maybe a
Nothing
        isPrelude :: ImportDecl SrcSpanInfo -> Bool
isPrelude x :: ImportDecl SrcSpanInfo
x = ModuleName SrcSpanInfo -> String
fromModuleName (ImportDecl SrcSpanInfo -> ModuleName SrcSpanInfo
forall l. ImportDecl l -> ModuleName l
importModule ImportDecl SrcSpanInfo
x) String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== "Prelude"


scopeImports :: Scope -> [ImportDecl S]
scopeImports :: Scope -> [ImportDecl SrcSpanInfo]
scopeImports (Scope x :: [ImportDecl SrcSpanInfo]
x) = [ImportDecl SrcSpanInfo]
x