78 lines
2.4 KiB
Haskell
78 lines
2.4 KiB
Haskell
{-# LANGUAGE NamedFieldPuns #-}
|
|
{-# LANGUAGE ConstraintKinds #-}
|
|
{-# LANGUAGE FlexibleContexts #-}
|
|
module Module (
|
|
Environment
|
|
, Log
|
|
, Module(..)
|
|
, Modules(..)
|
|
, emptyEnvironment
|
|
, parse
|
|
, register
|
|
) where
|
|
|
|
import Context (CodePath(..), Context(..), Contextual, Path(..))
|
|
import Control.Monad.Except (MonadError(..))
|
|
import Control.Monad.IO.Class (MonadIO(..))
|
|
import Control.Monad.RWS (MonadState, MonadWriter, asks, modify)
|
|
import Data.Attoparsec.Text (parseOnly)
|
|
import Data.Map (Map)
|
|
import qualified Data.Map as Map (empty, insert)
|
|
import Data.Set (Set)
|
|
import qualified Data.Set as Set (empty, insert)
|
|
import qualified Data.Text as Text (pack)
|
|
import Dependencies (Failable)
|
|
import Module.File (File(..))
|
|
import qualified Module.File (parser)
|
|
import Module.Imports (Reference(..), recurse)
|
|
import Prelude hiding (takeWhile)
|
|
import System.Directory (doesFileExist)
|
|
import System.FilePath ((</>), (<.>))
|
|
import Text.Printf (printf)
|
|
|
|
data Module = Module {
|
|
file :: Module.File.File
|
|
, dependencies :: Set Path
|
|
}
|
|
|
|
newtype Modules = Modules {
|
|
modules :: Map Path Module
|
|
}
|
|
|
|
emptyEnvironment :: Modules
|
|
emptyEnvironment = Modules {
|
|
modules = Map.empty
|
|
}
|
|
|
|
type Environment = MonadState Modules
|
|
type Log = MonadWriter [String]
|
|
|
|
register :: Environment m => Path -> Module -> m ()
|
|
register path module_ = modify $
|
|
\(Modules modules) -> Modules $ Map.insert path module_ modules
|
|
|
|
build :: File -> Module
|
|
build file = Module {file, dependencies}
|
|
where
|
|
dependencies = recurse pushDependency Set.empty $ imports file
|
|
pushDependency set _ ref = Set.insert (modulePath ref) set
|
|
|
|
parse :: (Contextual m, MonadIO m, Failable m) => Bool -> Path -> m Module
|
|
parse isMain path = do
|
|
searchPath <- asks codePaths
|
|
filePath <- find (CodePath [], searchPath) path
|
|
source <- Text.pack <$> liftIO (readFile filePath)
|
|
either throwError (return . build) $
|
|
parseOnly (Module.File.parser isMain) source
|
|
|
|
find :: (Failable m, MonadIO m) => (CodePath, CodePath) -> Path -> m FilePath
|
|
find (stack, CodePath []) path = throwError $
|
|
printf "Module %s not found in paths : %s" (show path) (show $ stack)
|
|
find (CodePath stackedDirs, CodePath (dir:otherDirs)) path@(Path components) = do
|
|
fileExists <- liftIO $ doesFileExist filePath
|
|
if fileExists
|
|
then return filePath
|
|
else find (CodePath (dir:stackedDirs), CodePath otherDirs) path
|
|
where
|
|
filePath = foldl (</>) dir components <.> "js"
|