module Language.PureScript.Interactive.Module where

import           Prelude

import qualified Language.PureScript as P
import qualified Language.PureScript.CST as CST
import           Language.PureScript.Interactive.Types
import           System.Directory (getCurrentDirectory)
import           System.FilePath (pathSeparator, makeRelative)
import           System.IO.UTF8 (readUTF8FilesT)

-- * Support Module

-- | The name of the PSCI support module
supportModuleName :: P.ModuleName
supportModuleName :: ModuleName
supportModuleName = forall a b. (a, b) -> a
fst (ModuleName, Ident)
initialInteractivePrint

-- | Checks if the Console module is defined
supportModuleIsDefined :: [P.ModuleName] -> Bool
supportModuleIsDefined :: [ModuleName] -> Bool
supportModuleIsDefined = forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem ModuleName
supportModuleName

-- * Module Management

-- | Load all modules.
loadAllModules :: [FilePath] -> IO (Either P.MultipleErrors [(FilePath, P.Module)])
loadAllModules :: [[Char]] -> IO (Either MultipleErrors [([Char], Module)])
loadAllModules [[Char]]
files = do
  [Char]
pwd <- IO [Char]
getCurrentDirectory
  [([Char], Text)]
filesAndContent <- [[Char]] -> IO [([Char], Text)]
readUTF8FilesT [[Char]]
files
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a b. (a, b) -> b
snd) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) k.
MonadError MultipleErrors m =>
(k -> [Char]) -> [(k, Text)] -> m [(k, ([ParserWarning], Module))]
CST.parseFromFiles ([Char] -> [Char] -> [Char]
makeRelative [Char]
pwd) [([Char], Text)]
filesAndContent

-- |
-- Makes a volatile module to execute the current expression.
--
createTemporaryModule :: Bool -> PSCiState -> P.Expr -> P.Module
createTemporaryModule :: Bool -> PSCiState -> Expr -> Module
createTemporaryModule Bool
exec PSCiState
st Expr
val =
  let
    imports :: [ImportedModule]
imports       = PSCiState -> [ImportedModule]
psciImportedModules PSCiState
st
    lets :: [Declaration]
lets          = PSCiState -> [Declaration]
psciLetBindings PSCiState
st
    moduleName :: ModuleName
moduleName    = Text -> ModuleName
P.ModuleName Text
"$PSCI"
    effModuleName :: ModuleName
effModuleName = Text -> ModuleName
P.ModuleName Text
"Effect"
    effImport :: ImportedModule
effImport     = (ModuleName
effModuleName, ImportDeclarationType
P.Implicit, forall a. a -> Maybe a
Just (Text -> ModuleName
P.ModuleName Text
"$Effect"))
    supportImport :: ImportedModule
supportImport = (forall a b. (a, b) -> a
fst (PSCiState -> (ModuleName, Ident)
psciInteractivePrint PSCiState
st), ImportDeclarationType
P.Implicit, forall a. a -> Maybe a
Just (Text -> ModuleName
P.ModuleName Text
"$Support"))
    eval :: Expr
eval          = SourceSpan -> Qualified Ident -> Expr
P.Var SourceSpan
internalSpan (forall a. QualifiedBy -> a -> Qualified a
P.Qualified (ModuleName -> QualifiedBy
P.ByModuleName (Text -> ModuleName
P.ModuleName Text
"$Support")) (forall a b. (a, b) -> b
snd (PSCiState -> (ModuleName, Ident)
psciInteractivePrint PSCiState
st)))
    mainValue :: Expr
mainValue     = Expr -> Expr -> Expr
P.App Expr
eval (SourceSpan -> Qualified Ident -> Expr
P.Var SourceSpan
internalSpan (forall a. QualifiedBy -> a -> Qualified a
P.Qualified QualifiedBy
P.ByNullSourcePos (Text -> Ident
P.Ident Text
"it")))
    itDecl :: Declaration
itDecl        = SourceAnn
-> Ident -> NameKind -> [Binder] -> [GuardedExpr] -> Declaration
P.ValueDecl (SourceSpan
internalSpan, []) (Text -> Ident
P.Ident Text
"it") NameKind
P.Public [] [Expr -> GuardedExpr
P.MkUnguarded Expr
val]
    typeDecl :: Declaration
typeDecl      = TypeDeclarationData -> Declaration
P.TypeDeclaration
                      (SourceAnn -> Ident -> SourceType -> TypeDeclarationData
P.TypeDeclarationData (SourceSpan
internalSpan, []) (Text -> Ident
P.Ident Text
"$main")
                        (SourceType -> SourceType -> SourceType
P.srcTypeApp
                          (Qualified (ProperName 'TypeName) -> SourceType
P.srcTypeConstructor
                            (forall a. QualifiedBy -> a -> Qualified a
P.Qualified (ModuleName -> QualifiedBy
P.ByModuleName (Text -> ModuleName
P.ModuleName Text
"$Effect")) (forall (a :: ProperNameType). Text -> ProperName a
P.ProperName Text
"Effect")))
                                  SourceType
P.srcTypeWildcard))
    mainDecl :: Declaration
mainDecl      = SourceAnn
-> Ident -> NameKind -> [Binder] -> [GuardedExpr] -> Declaration
P.ValueDecl (SourceSpan
internalSpan, []) (Text -> Ident
P.Ident Text
"$main") NameKind
P.Public [] [Expr -> GuardedExpr
P.MkUnguarded Expr
mainValue]
    decls :: [Declaration]
decls         = if Bool
exec then [Declaration
itDecl, Declaration
typeDecl, Declaration
mainDecl] else [Declaration
itDecl]
  in
    SourceSpan
-> [Comment]
-> ModuleName
-> [Declaration]
-> Maybe [DeclarationRef]
-> Module
P.Module SourceSpan
internalSpan
             [] ModuleName
moduleName
             ((ImportedModule -> Declaration
importDecl forall a b. (a -> b) -> [a] -> [b]
`map` (ImportedModule
effImport forall a. a -> [a] -> [a]
: ImportedModule
supportImport forall a. a -> [a] -> [a]
: [ImportedModule]
imports)) forall a. [a] -> [a] -> [a]
++ [Declaration]
lets forall a. [a] -> [a] -> [a]
++ [Declaration]
decls)
             forall a. Maybe a
Nothing


-- |
-- Makes a volatile module to hold a non-qualified type synonym for a fully-qualified data type declaration.
--
createTemporaryModuleForKind :: PSCiState -> P.SourceType -> P.Module
createTemporaryModuleForKind :: PSCiState -> SourceType -> Module
createTemporaryModuleForKind PSCiState
st SourceType
typ =
  let
    imports :: [ImportedModule]
imports    = PSCiState -> [ImportedModule]
psciImportedModules PSCiState
st
    lets :: [Declaration]
lets       = PSCiState -> [Declaration]
psciLetBindings PSCiState
st
    moduleName :: ModuleName
moduleName = Text -> ModuleName
P.ModuleName Text
"$PSCI"
    itDecl :: Declaration
itDecl     = SourceAnn
-> ProperName 'TypeName
-> [(Text, Maybe SourceType)]
-> SourceType
-> Declaration
P.TypeSynonymDeclaration (SourceSpan
internalSpan, []) (forall (a :: ProperNameType). Text -> ProperName a
P.ProperName Text
"IT") [] SourceType
typ
  in
    SourceSpan
-> [Comment]
-> ModuleName
-> [Declaration]
-> Maybe [DeclarationRef]
-> Module
P.Module SourceSpan
internalSpan [] ModuleName
moduleName ((ImportedModule -> Declaration
importDecl forall a b. (a -> b) -> [a] -> [b]
`map` [ImportedModule]
imports) forall a. [a] -> [a] -> [a]
++ [Declaration]
lets forall a. [a] -> [a] -> [a]
++ [Declaration
itDecl]) forall a. Maybe a
Nothing

-- |
-- Makes a volatile module to execute the current imports.
--
createTemporaryModuleForImports :: PSCiState -> P.Module
createTemporaryModuleForImports :: PSCiState -> Module
createTemporaryModuleForImports PSCiState
st =
  let
    imports :: [ImportedModule]
imports    = PSCiState -> [ImportedModule]
psciImportedModules PSCiState
st
    moduleName :: ModuleName
moduleName = Text -> ModuleName
P.ModuleName Text
"$PSCI"
  in
    SourceSpan
-> [Comment]
-> ModuleName
-> [Declaration]
-> Maybe [DeclarationRef]
-> Module
P.Module SourceSpan
internalSpan [] ModuleName
moduleName (ImportedModule -> Declaration
importDecl forall a b. (a -> b) -> [a] -> [b]
`map` [ImportedModule]
imports) forall a. Maybe a
Nothing

importDecl :: ImportedModule -> P.Declaration
importDecl :: ImportedModule -> Declaration
importDecl (ModuleName
mn, ImportDeclarationType
declType, Maybe ModuleName
asQ) = SourceAnn
-> ModuleName
-> ImportDeclarationType
-> Maybe ModuleName
-> Declaration
P.ImportDeclaration (SourceSpan
internalSpan, []) ModuleName
mn ImportDeclarationType
declType Maybe ModuleName
asQ

indexFile :: FilePath
indexFile :: [Char]
indexFile = [Char]
".psci_modules" forall a. [a] -> [a] -> [a]
++ Char
pathSeparator forall a. a -> [a] -> [a]
: [Char]
"index.js"

modulesDir :: FilePath
modulesDir :: [Char]
modulesDir = [Char]
".psci_modules"

internalSpan :: P.SourceSpan
internalSpan :: SourceSpan
internalSpan = [Char] -> SourceSpan
P.internalModuleSourceSpan [Char]
"<internal>"