{-
   Copyright 2016, Dominic Orchard, Andrew Rice, Mistral Contrastin, Matthew Danish

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
-}

{-|

Format of Camfort precompiled files with information about Fortran
modules. The 'ModuleMap' stores information important to the
renamer. The other data is up to you.

Note that the encoder and decoder work on lists of ModFile so that one
fsmod-file may contain information about multiple Fortran files.

One typical usage might look like:

> let modFile1 = genModFile programFile
> let modFile2 = alterModFileData (const (Just ...)) "mydata" modFile1
> let bytes    = encodeModFile [modFile2]
> ...
> case decodeModFile bytes of
>   Left error -> print error
>   Right modFile3:otherModuleFiles -> ...
>     where
>       moduleMap = combinedModuleMap (modFile3:otherModuleFiles)
>       myData    = lookupModFileData "mydata" modFile3
>       renamedPF = analyseRenamesWithModuleMap moduleMap programFile

-}

module Language.Fortran.Util.ModFile
  (
  -- * Main defitions
    ModFile, ModFiles, emptyModFile, emptyModFiles, modFileSuffix
  , lookupModFileData, getLabelsModFileData, alterModFileData, alterModFileDataF

  -- * Creation
  , genModFile, regenModFile

  -- * En/decoding
  , encodeModFile, decodeModFile, decodeModFiles, decodeModFiles'

  -- * Operations
  , moduleFilename
  , StringMap, extractStringMap, combinedStringMap
  , DeclContext(..), DeclMap, extractDeclMap, combinedDeclMap
  , extractModuleMap, combinedModuleMap, combinedTypeEnv
  , ParamVarMap, extractParamVarMap, combinedParamVarMap
  , genUniqNameToFilenameMap
  , TimestampStatus(..), checkTimestamps
  ) where

import qualified Language.Fortran.AST               as F
import qualified Language.Fortran.Analysis          as FA
import qualified Language.Fortran.Analysis.BBlocks  as FAB
import qualified Language.Fortran.Analysis.DataFlow as FAD
import qualified Language.Fortran.Analysis.Renaming as FAR
import qualified Language.Fortran.Analysis.Types    as FAT
import qualified Language.Fortran.Util.Position     as P
import           Language.Fortran.Util.Files ( getDirContents )

import Control.Monad.State
import Data.Binary (Binary, encode, decodeOrFail)
import qualified Data.ByteString.Lazy.Char8 as LB
import Data.Data
import Data.Generics.Uniplate.Operations
import qualified Data.Map.Strict as M
import Data.Maybe
import GHC.Generics (Generic)
import System.Directory ( doesFileExist, getModificationTime )
import qualified System.FilePath
import System.FilePath ( (-<.>), (</>) )
import System.IO ( hPutStrLn, stderr )

--------------------------------------------------

-- | Standard ending of fortran-src-format "mod files"
modFileSuffix :: String
modFileSuffix :: String
modFileSuffix = String
".fsmod"

-- | Returns 'true' for filepaths with an extension that identifies them as a
--   mod file.
isModFile :: FilePath -> Bool
isModFile :: String -> Bool
isModFile = String -> String -> Bool
System.FilePath.isExtensionOf String
modFileSuffix

-- | Context of a declaration: the ProgramUnit where it was declared.
data DeclContext = DCMain | DCBlockData | DCModule F.ProgramUnitName
                 | DCFunction (F.ProgramUnitName, F.ProgramUnitName)    -- ^ (uniqName, srcName)
                 | DCSubroutine (F.ProgramUnitName, F.ProgramUnitName)  -- ^ (uniqName, srcName)
  deriving (Eq DeclContext
DeclContext -> DeclContext -> Bool
DeclContext -> DeclContext -> Ordering
DeclContext -> DeclContext -> DeclContext
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: DeclContext -> DeclContext -> DeclContext
$cmin :: DeclContext -> DeclContext -> DeclContext
max :: DeclContext -> DeclContext -> DeclContext
$cmax :: DeclContext -> DeclContext -> DeclContext
>= :: DeclContext -> DeclContext -> Bool
$c>= :: DeclContext -> DeclContext -> Bool
> :: DeclContext -> DeclContext -> Bool
$c> :: DeclContext -> DeclContext -> Bool
<= :: DeclContext -> DeclContext -> Bool
$c<= :: DeclContext -> DeclContext -> Bool
< :: DeclContext -> DeclContext -> Bool
$c< :: DeclContext -> DeclContext -> Bool
compare :: DeclContext -> DeclContext -> Ordering
$ccompare :: DeclContext -> DeclContext -> Ordering
Ord, DeclContext -> DeclContext -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DeclContext -> DeclContext -> Bool
$c/= :: DeclContext -> DeclContext -> Bool
== :: DeclContext -> DeclContext -> Bool
$c== :: DeclContext -> DeclContext -> Bool
Eq, Int -> DeclContext -> ShowS
[DeclContext] -> ShowS
DeclContext -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DeclContext] -> ShowS
$cshowList :: [DeclContext] -> ShowS
show :: DeclContext -> String
$cshow :: DeclContext -> String
showsPrec :: Int -> DeclContext -> ShowS
$cshowsPrec :: Int -> DeclContext -> ShowS
Show, Typeable DeclContext
DeclContext -> DataType
DeclContext -> Constr
(forall b. Data b => b -> b) -> DeclContext -> DeclContext
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> DeclContext -> u
forall u. (forall d. Data d => d -> u) -> DeclContext -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> DeclContext -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> DeclContext -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> DeclContext -> m DeclContext
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> DeclContext -> m DeclContext
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c DeclContext
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> DeclContext -> c DeclContext
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c DeclContext)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c DeclContext)
gmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> DeclContext -> m DeclContext
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> DeclContext -> m DeclContext
gmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> DeclContext -> m DeclContext
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> DeclContext -> m DeclContext
gmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> DeclContext -> m DeclContext
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> DeclContext -> m DeclContext
gmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> DeclContext -> u
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> DeclContext -> u
gmapQ :: forall u. (forall d. Data d => d -> u) -> DeclContext -> [u]
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> DeclContext -> [u]
gmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> DeclContext -> r
$cgmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> DeclContext -> r
gmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> DeclContext -> r
$cgmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> DeclContext -> r
gmapT :: (forall b. Data b => b -> b) -> DeclContext -> DeclContext
$cgmapT :: (forall b. Data b => b -> b) -> DeclContext -> DeclContext
dataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c DeclContext)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c DeclContext)
dataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c DeclContext)
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c DeclContext)
dataTypeOf :: DeclContext -> DataType
$cdataTypeOf :: DeclContext -> DataType
toConstr :: DeclContext -> Constr
$ctoConstr :: DeclContext -> Constr
gunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c DeclContext
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c DeclContext
gfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> DeclContext -> c DeclContext
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> DeclContext -> c DeclContext
Data, Typeable, forall x. Rep DeclContext x -> DeclContext
forall x. DeclContext -> Rep DeclContext x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep DeclContext x -> DeclContext
$cfrom :: forall x. DeclContext -> Rep DeclContext x
Generic)

instance Binary DeclContext

-- | Map of unique variable name to the unique name of the program
-- unit where it was defined, and the corresponding SrcSpan.
type DeclMap = M.Map F.Name (DeclContext, P.SrcSpan)

-- | A map of aliases => strings, in order to save space and share
-- structure for repeated strings.
type StringMap = M.Map String String

-- | A map of variables => their constant expression if known
type ParamVarMap = FAD.ParameterVarMap

-- | The data stored in the "mod files"
data ModFile = ModFile { ModFile -> String
mfFilename    :: String
                       , ModFile -> StringMap
mfStringMap   :: StringMap
                       , ModFile -> ModuleMap
mfModuleMap   :: FAR.ModuleMap
                       , ModFile -> DeclMap
mfDeclMap     :: DeclMap
                       , ModFile -> TypeEnv
mfTypeEnv     :: FAT.TypeEnv
                       , ModFile -> ParamVarMap
mfParamVarMap :: ParamVarMap
                       , ModFile -> Map String ByteString
mfOtherData   :: M.Map String LB.ByteString }
  deriving (ModFile -> ModFile -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ModFile -> ModFile -> Bool
$c/= :: ModFile -> ModFile -> Bool
== :: ModFile -> ModFile -> Bool
$c== :: ModFile -> ModFile -> Bool
Eq, Int -> ModFile -> ShowS
[ModFile] -> ShowS
ModFile -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ModFile] -> ShowS
$cshowList :: [ModFile] -> ShowS
show :: ModFile -> String
$cshow :: ModFile -> String
showsPrec :: Int -> ModFile -> ShowS
$cshowsPrec :: Int -> ModFile -> ShowS
Show, Typeable ModFile
ModFile -> DataType
ModFile -> Constr
(forall b. Data b => b -> b) -> ModFile -> ModFile
forall a.
Typeable a
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> ModFile -> u
forall u. (forall d. Data d => d -> u) -> ModFile -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> ModFile -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> ModFile -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> ModFile -> m ModFile
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ModFile -> m ModFile
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c ModFile
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ModFile -> c ModFile
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c ModFile)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c ModFile)
gmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ModFile -> m ModFile
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ModFile -> m ModFile
gmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ModFile -> m ModFile
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ModFile -> m ModFile
gmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> ModFile -> m ModFile
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> ModFile -> m ModFile
gmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> ModFile -> u
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> ModFile -> u
gmapQ :: forall u. (forall d. Data d => d -> u) -> ModFile -> [u]
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> ModFile -> [u]
gmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> ModFile -> r
$cgmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> ModFile -> r
gmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> ModFile -> r
$cgmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> ModFile -> r
gmapT :: (forall b. Data b => b -> b) -> ModFile -> ModFile
$cgmapT :: (forall b. Data b => b -> b) -> ModFile -> ModFile
dataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c ModFile)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c ModFile)
dataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c ModFile)
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c ModFile)
dataTypeOf :: ModFile -> DataType
$cdataTypeOf :: ModFile -> DataType
toConstr :: ModFile -> Constr
$ctoConstr :: ModFile -> Constr
gunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c ModFile
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c ModFile
gfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ModFile -> c ModFile
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ModFile -> c ModFile
Data, Typeable, forall x. Rep ModFile x -> ModFile
forall x. ModFile -> Rep ModFile x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep ModFile x -> ModFile
$cfrom :: forall x. ModFile -> Rep ModFile x
Generic)

instance Binary ModFile

-- | A set of decoded mod files.
type ModFiles = [ModFile]

-- | Empty set of mod files. (future proof: may not always be a list)
emptyModFiles :: ModFiles
emptyModFiles :: [ModFile]
emptyModFiles = []

-- | Starting point.
emptyModFile :: ModFile
emptyModFile :: ModFile
emptyModFile = String
-> StringMap
-> ModuleMap
-> DeclMap
-> TypeEnv
-> ParamVarMap
-> Map String ByteString
-> ModFile
ModFile String
"" forall k a. Map k a
M.empty forall k a. Map k a
M.empty forall k a. Map k a
M.empty forall k a. Map k a
M.empty forall k a. Map k a
M.empty forall k a. Map k a
M.empty

-- | Extracts the module map, declaration map and type analysis from
-- an analysed and renamed ProgramFile, then inserts it into the
-- ModFile.
regenModFile :: forall a. Data a => F.ProgramFile (FA.Analysis a) -> ModFile -> ModFile
regenModFile :: forall a. Data a => ProgramFile (Analysis a) -> ModFile -> ModFile
regenModFile ProgramFile (Analysis a)
pf ModFile
mf = ModFile
mf { mfModuleMap :: ModuleMap
mfModuleMap   = forall a. Data a => ProgramFile (Analysis a) -> ModuleMap
extractModuleMap ProgramFile (Analysis a)
pf
                        , mfDeclMap :: DeclMap
mfDeclMap     = forall a. Data a => ProgramFile (Analysis a) -> DeclMap
extractDeclMap ProgramFile (Analysis a)
pf
                        , mfTypeEnv :: TypeEnv
mfTypeEnv     = forall a. Data a => ProgramFile (Analysis a) -> TypeEnv
FAT.extractTypeEnv ProgramFile (Analysis a)
pf
                        , mfParamVarMap :: ParamVarMap
mfParamVarMap = forall a. Data a => ProgramFile (Analysis a) -> ParamVarMap
extractParamVarMap ProgramFile (Analysis a)
pf
                        , mfFilename :: String
mfFilename    = forall a. ProgramFile a -> String
F.pfGetFilename ProgramFile (Analysis a)
pf }

-- | Generate a fresh ModFile from the module map, declaration map and
-- type analysis of a given analysed and renamed ProgramFile.
genModFile :: forall a. Data a => F.ProgramFile (FA.Analysis a) -> ModFile
genModFile :: forall a. Data a => ProgramFile (Analysis a) -> ModFile
genModFile = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a. Data a => ProgramFile (Analysis a) -> ModFile -> ModFile
regenModFile ModFile
emptyModFile

-- | Looks up the raw "other data" that may be stored in a ModFile by
-- applications that make use of fortran-src.
lookupModFileData :: String -> ModFile -> Maybe LB.ByteString
lookupModFileData :: String -> ModFile -> Maybe ByteString
lookupModFileData String
k = forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup String
k forall b c a. (b -> c) -> (a -> b) -> a -> c
. ModFile -> Map String ByteString
mfOtherData

-- | Get a list of the labels present in the "other data" of a
-- ModFile. More of a meta-programming / debugging feature.
getLabelsModFileData :: ModFile -> [String]
getLabelsModFileData :: ModFile -> [String]
getLabelsModFileData = forall k a. Map k a -> [k]
M.keys forall b c a. (b -> c) -> (a -> b) -> a -> c
. ModFile -> Map String ByteString
mfOtherData

-- | Allows modification/insertion/deletion of "other data" that may
-- be stored in a ModFile by applications that make use of
-- fortran-src. See 'Data.Map.Strict.alter' for more information about
-- the interface of this function.
alterModFileData :: (Maybe LB.ByteString -> Maybe LB.ByteString) -> String -> ModFile -> ModFile
alterModFileData :: (Maybe ByteString -> Maybe ByteString)
-> String -> ModFile -> ModFile
alterModFileData Maybe ByteString -> Maybe ByteString
f String
k ModFile
mf = ModFile
mf { mfOtherData :: Map String ByteString
mfOtherData = forall k a.
Ord k =>
(Maybe a -> Maybe a) -> k -> Map k a -> Map k a
M.alter Maybe ByteString -> Maybe ByteString
f String
k forall b c a. (b -> c) -> (a -> b) -> a -> c
. ModFile -> Map String ByteString
mfOtherData forall a b. (a -> b) -> a -> b
$ ModFile
mf }

alterModFileDataF
    :: Functor f
    => (Maybe LB.ByteString -> f (Maybe LB.ByteString)) -> String -> ModFile
    -> f ModFile
alterModFileDataF :: forall (f :: * -> *).
Functor f =>
(Maybe ByteString -> f (Maybe ByteString))
-> String -> ModFile -> f ModFile
alterModFileDataF Maybe ByteString -> f (Maybe ByteString)
f String
k ModFile
mf =
    (\Map String ByteString
od -> ModFile
mf { mfOtherData :: Map String ByteString
mfOtherData = Map String ByteString
od }) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (f :: * -> *) k a.
(Functor f, Ord k) =>
(Maybe a -> f (Maybe a)) -> k -> Map k a -> f (Map k a)
M.alterF Maybe ByteString -> f (Maybe ByteString)
f String
k (ModFile -> Map String ByteString
mfOtherData ModFile
mf)

-- | Convert ModFiles to a strict ByteString for writing to file.
encodeModFile :: [ModFile] -> LB.ByteString
encodeModFile :: [ModFile] -> ByteString
encodeModFile = forall a. Binary a => a -> ByteString
encode forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map ModFile -> ModFile
each
  where
    each :: ModFile -> ModFile
each ModFile
mf = ModFile
mf' { mfStringMap :: StringMap
mfStringMap = StringMap
sm }
      where
        (ModFile
mf', StringMap
sm) = forall a. Data a => a -> (a, StringMap)
extractStringMap (ModFile
mf { mfStringMap :: StringMap
mfStringMap = forall k a. Map k a
M.empty })

-- | Convert a strict ByteString to ModFiles, if possible. Revert the
-- String aliases according to the StringMap.
decodeModFile :: LB.ByteString -> Either String [ModFile]
decodeModFile :: ByteString -> Either String [ModFile]
decodeModFile ByteString
bs = case forall a.
Binary a =>
ByteString
-> Either
     (ByteString, ByteOffset, String) (ByteString, ByteOffset, a)
decodeOrFail ByteString
bs of
  Left (ByteString
_, ByteOffset
_, String
s)    -> forall a b. a -> Either a b
Left String
s
  Right (ByteString
_, ByteOffset
_, [ModFile]
mfs) -> forall a b. b -> Either a b
Right (forall a b. (a -> b) -> [a] -> [b]
map ModFile -> ModFile
each [ModFile]
mfs)
    where
      each :: ModFile -> ModFile
each ModFile
mf = (forall a. Data a => StringMap -> a -> a
revertStringMap StringMap
sm ModFile
mf { mfStringMap :: StringMap
mfStringMap = forall k a. Map k a
M.empty }) { mfStringMap :: StringMap
mfStringMap = StringMap
sm }
        where sm :: StringMap
sm = ModFile -> StringMap
mfStringMap ModFile
mf

decodeModFiles :: [FilePath] -> IO [(FilePath, ModFile)]
decodeModFiles :: [String] -> IO [(String, ModFile)]
decodeModFiles = forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM (\ [(String, ModFile)]
modFiles String
d -> do
      -- Figure out the camfort mod files and parse them.
      [String]
modFileNames <- forall a. (a -> Bool) -> [a] -> [a]
filter String -> Bool
isModFile forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` String -> IO [String]
getDirContents String
d
      [(String, ModFile)]
addedModFiles <- forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [String]
modFileNames forall a b. (a -> b) -> a -> b
$ \ String
modFileName -> do
        ByteString
contents <- String -> IO ByteString
LB.readFile (String
d String -> ShowS
</> String
modFileName)
        case ByteString -> Either String [ModFile]
decodeModFile ByteString
contents of
          Left String
msg -> do
            Handle -> String -> IO ()
hPutStrLn Handle
stderr forall a b. (a -> b) -> a -> b
$ String
modFileName forall a. [a] -> [a] -> [a]
++ String
": Error: " forall a. [a] -> [a] -> [a]
++ String
msg
            forall (m :: * -> *) a. Monad m => a -> m a
return [(String
modFileName, ModFile
emptyModFile)]
          Right [ModFile]
mods -> do
            Handle -> String -> IO ()
hPutStrLn Handle
stderr forall a b. (a -> b) -> a -> b
$ String
modFileName forall a. [a] -> [a] -> [a]
++ String
": successfully parsed precompiled file."
            forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map (String
modFileName,) [ModFile]
mods
      forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ [(String, ModFile)]
addedModFiles forall a. [a] -> [a] -> [a]
++ [(String, ModFile)]
modFiles
    ) [] -- can't use emptyModFiles

decodeModFiles' :: [FilePath] -> IO ModFiles
decodeModFiles' :: [String] -> IO [ModFile]
decodeModFiles' = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a b. (a -> b) -> [a] -> [b]
map forall a b. (a, b) -> b
snd) forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> IO [(String, ModFile)]
decodeModFiles

-- | Extract the combined module map from a set of ModFiles. Useful
-- for parsing a Fortran file in a large context of other modules.
combinedModuleMap :: ModFiles -> FAR.ModuleMap
combinedModuleMap :: [ModFile] -> ModuleMap
combinedModuleMap = forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
M.unions forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map ModFile -> ModuleMap
mfModuleMap

-- | Extract the combined module map from a set of ModFiles. Useful
-- for parsing a Fortran file in a large context of other modules.
combinedTypeEnv :: ModFiles -> FAT.TypeEnv
combinedTypeEnv :: [ModFile] -> TypeEnv
combinedTypeEnv = forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
M.unions forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map ModFile -> TypeEnv
mfTypeEnv

-- | Extract the combined declaration map from a set of
-- ModFiles. Useful for parsing a Fortran file in a large context of
-- other modules.
combinedDeclMap :: ModFiles -> DeclMap
combinedDeclMap :: [ModFile] -> DeclMap
combinedDeclMap = forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
M.unions forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map ModFile -> DeclMap
mfDeclMap

-- | Extract the combined string map of ModFiles. Mainly internal use.
combinedStringMap :: ModFiles -> StringMap
combinedStringMap :: [ModFile] -> StringMap
combinedStringMap = forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
M.unions forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map ModFile -> StringMap
mfStringMap

-- | Extract the combined string map of ModFiles. Mainly internal use.
combinedParamVarMap :: ModFiles -> ParamVarMap
combinedParamVarMap :: [ModFile] -> ParamVarMap
combinedParamVarMap = forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
M.unions forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map ModFile -> ParamVarMap
mfParamVarMap

-- | Get the associated Fortran filename that was used to compile the
-- ModFile.
moduleFilename :: ModFile -> String
moduleFilename :: ModFile -> String
moduleFilename = ModFile -> String
mfFilename

--------------------------------------------------

-- | Create a map that links all unique variable/function names in the
-- ModFiles to their corresponding filename.
genUniqNameToFilenameMap :: ModFiles -> M.Map F.Name String
genUniqNameToFilenameMap :: [ModFile] -> StringMap
genUniqNameToFilenameMap = forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
M.unions forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map ModFile -> StringMap
perMF
  where
    perMF :: ModFile -> StringMap
perMF ModFile
mf = forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [ (String
n, String
fname) | Map String (String, NameType)
modEnv <- forall k a. Map k a -> [a]
M.elems (ModFile -> ModuleMap
mfModuleMap ModFile
mf)
                                       , (String
n, NameType
_) <- forall k a. Map k a -> [a]
M.elems Map String (String, NameType)
modEnv ]
      where
        fname :: String
fname = ModFile -> String
mfFilename ModFile
mf

--------------------------------------------------

-- | Extract all module maps (name -> environment) by collecting all
-- of the stored module maps within the PUModule annotation.
extractModuleMap :: forall a. Data a => F.ProgramFile (FA.Analysis a) -> FAR.ModuleMap
extractModuleMap :: forall a. Data a => ProgramFile (Analysis a) -> ModuleMap
extractModuleMap ProgramFile (Analysis a)
pf
  -- in case there are no modules, store global program unit names under the name 'NamelessMain'
  | forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(ProgramUnitName, Map String (String, NameType))]
mmap = forall k a. k -> a -> Map k a
M.singleton ProgramUnitName
F.NamelessMain forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
M.unions [Map String (String, NameType)]
combinedEnv
  | Bool
otherwise = forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [(ProgramUnitName, Map String (String, NameType))]
mmap
  where
    mmap :: [(ProgramUnitName, Map String (String, NameType))]
mmap = [ (ProgramUnitName
n, Map String (String, NameType)
env) | pu :: ProgramUnit (Analysis a)
pu@F.PUModule{} <- forall from to. Biplate from to => from -> [to]
childrenBi ProgramFile (Analysis a)
pf :: [F.ProgramUnit (FA.Analysis a)]
                      , let a :: Analysis a
a = forall (f :: * -> *) a. Annotated f => f a -> a
F.getAnnotation ProgramUnit (Analysis a)
pu
                      , let n :: ProgramUnitName
n = forall a. Named a => a -> ProgramUnitName
F.getName ProgramUnit (Analysis a)
pu
                      , Map String (String, NameType)
env <- forall a. Maybe a -> [a]
maybeToList (forall a. Analysis a -> Maybe (Map String (String, NameType))
FA.moduleEnv Analysis a
a) ]
    combinedEnv :: [Map String (String, NameType)]
combinedEnv = [ Map String (String, NameType)
env | ProgramUnit (Analysis a)
pu <- forall from to. Biplate from to => from -> [to]
childrenBi ProgramFile (Analysis a)
pf :: [F.ProgramUnit (FA.Analysis a)]
                        , let a :: Analysis a
a = forall (f :: * -> *) a. Annotated f => f a -> a
F.getAnnotation ProgramUnit (Analysis a)
pu
                        , Map String (String, NameType)
env <- forall a. Maybe a -> [a]
maybeToList (forall a. Analysis a -> Maybe (Map String (String, NameType))
FA.moduleEnv Analysis a
a) ]

-- | Extract map of declared variables with their associated program
-- unit and source span.
extractDeclMap :: forall a. Data a => F.ProgramFile (FA.Analysis a) -> DeclMap
extractDeclMap :: forall a. Data a => ProgramFile (Analysis a) -> DeclMap
extractDeclMap ProgramFile (Analysis a)
pf = forall k a. Ord k => [(k, a)] -> Map k a
M.fromList forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ((DeclContext, Maybe (String, SrcSpan), [Block (Analysis a)])
-> [(String, (DeclContext, SrcSpan))]
blockDecls forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgramUnit (Analysis a)
-> (DeclContext, Maybe (String, SrcSpan), [Block (Analysis a)])
nameAndBlocks) forall a b. (a -> b) -> a -> b
$ forall from to. Biplate from to => from -> [to]
universeBi ProgramFile (Analysis a)
pf
  where
    -- Extract variable names, source spans from declarations (and
    -- from function return variable if present)
    blockDecls :: (DeclContext, Maybe (F.Name, P.SrcSpan), [F.Block (FA.Analysis a)]) -> [(F.Name, (DeclContext, P.SrcSpan))]
    blockDecls :: (DeclContext, Maybe (String, SrcSpan), [Block (Analysis a)])
-> [(String, (DeclContext, SrcSpan))]
blockDecls (DeclContext
dc, Maybe (String, SrcSpan)
mret, [Block (Analysis a)]
bs)
      | Maybe (String, SrcSpan)
Nothing        <- Maybe (String, SrcSpan)
mret = forall a b. (a -> b) -> [a] -> [b]
map Declarator (Analysis a) -> (String, (DeclContext, SrcSpan))
decls (forall from to. Biplate from to => from -> [to]
universeBi [Block (Analysis a)]
bs)
      | Just (String
ret, SrcSpan
ss) <- Maybe (String, SrcSpan)
mret = (String
ret, (DeclContext
dc, SrcSpan
ss))forall a. a -> [a] -> [a]
:forall a b. (a -> b) -> [a] -> [b]
map Declarator (Analysis a) -> (String, (DeclContext, SrcSpan))
decls (forall from to. Biplate from to => from -> [to]
universeBi [Block (Analysis a)]
bs)
      where
        decls :: Declarator (Analysis a) -> (String, (DeclContext, SrcSpan))
decls Declarator (Analysis a)
d = let (String
v, SrcSpan
ss) = Declarator (Analysis a) -> (String, SrcSpan)
declVarName Declarator (Analysis a)
d in (String
v, (DeclContext
dc, SrcSpan
ss))

    -- Extract variable name and source span from declaration
    declVarName :: F.Declarator (FA.Analysis a) -> (F.Name, P.SrcSpan)
    declVarName :: Declarator (Analysis a) -> (String, SrcSpan)
declVarName (F.Declarator Analysis a
_ SrcSpan
_ Expression (Analysis a)
e DeclaratorType (Analysis a)
_ Maybe (Expression (Analysis a))
_ Maybe (Expression (Analysis a))
_)  = (forall a. Expression (Analysis a) -> String
FA.varName Expression (Analysis a)
e, forall a. Spanned a => a -> SrcSpan
P.getSpan Expression (Analysis a)
e)

    -- Extract context identifier, a function return value (+ source
    -- span) if present, and a list of contained blocks
    nameAndBlocks :: F.ProgramUnit (FA.Analysis a) -> (DeclContext, Maybe (F.Name, P.SrcSpan), [F.Block (FA.Analysis a)])
    nameAndBlocks :: ProgramUnit (Analysis a)
-> (DeclContext, Maybe (String, SrcSpan), [Block (Analysis a)])
nameAndBlocks ProgramUnit (Analysis a)
pu = case ProgramUnit (Analysis a)
pu of
      F.PUMain       Analysis a
_ SrcSpan
_ Maybe String
_ [Block (Analysis a)]
b Maybe [ProgramUnit (Analysis a)]
_            -> (DeclContext
DCMain, forall a. Maybe a
Nothing, [Block (Analysis a)]
b)
      F.PUModule     Analysis a
_ SrcSpan
_ String
_ [Block (Analysis a)]
b Maybe [ProgramUnit (Analysis a)]
_            -> (ProgramUnitName -> DeclContext
DCModule forall a b. (a -> b) -> a -> b
$ forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puName ProgramUnit (Analysis a)
pu, forall a. Maybe a
Nothing, [Block (Analysis a)]
b)
      F.PUSubroutine Analysis a
_ SrcSpan
_ PrefixSuffix (Analysis a)
_ String
_ Maybe (AList Expression (Analysis a))
_ [Block (Analysis a)]
b Maybe [ProgramUnit (Analysis a)]
_        -> ((ProgramUnitName, ProgramUnitName) -> DeclContext
DCSubroutine (forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puName ProgramUnit (Analysis a)
pu, forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puSrcName ProgramUnit (Analysis a)
pu), forall a. Maybe a
Nothing, [Block (Analysis a)]
b)
      F.PUFunction   Analysis a
_ SrcSpan
_ Maybe (TypeSpec (Analysis a))
_ PrefixSuffix (Analysis a)
_ String
_ Maybe (AList Expression (Analysis a))
_ Maybe (Expression (Analysis a))
mret [Block (Analysis a)]
b Maybe [ProgramUnit (Analysis a)]
_
        | Maybe (Expression (Analysis a))
Nothing   <- Maybe (Expression (Analysis a))
mret
        , F.Named String
n <- forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puName ProgramUnit (Analysis a)
pu       -> ((ProgramUnitName, ProgramUnitName) -> DeclContext
DCFunction (forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puName ProgramUnit (Analysis a)
pu, forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puSrcName ProgramUnit (Analysis a)
pu), forall a. a -> Maybe a
Just (String
n, forall a. Spanned a => a -> SrcSpan
P.getSpan ProgramUnit (Analysis a)
pu), [Block (Analysis a)]
b)
        | Just Expression (Analysis a)
ret <- Maybe (Expression (Analysis a))
mret                -> ((ProgramUnitName, ProgramUnitName) -> DeclContext
DCFunction (forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puName ProgramUnit (Analysis a)
pu, forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puSrcName ProgramUnit (Analysis a)
pu), forall a. a -> Maybe a
Just (forall a. Expression (Analysis a) -> String
FA.varName Expression (Analysis a)
ret, forall a. Spanned a => a -> SrcSpan
P.getSpan Expression (Analysis a)
ret), [Block (Analysis a)]
b)
        | Bool
otherwise                       -> forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ String
"nameAndBlocks: un-named function with no return value! " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puName ProgramUnit (Analysis a)
pu) forall a. [a] -> [a] -> [a]
++ String
" at source-span " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (forall a. Spanned a => a -> SrcSpan
P.getSpan ProgramUnit (Analysis a)
pu)
      F.PUBlockData  Analysis a
_ SrcSpan
_ Maybe String
_ [Block (Analysis a)]
b              -> (DeclContext
DCBlockData, forall a. Maybe a
Nothing, [Block (Analysis a)]
b)
      F.PUComment    {}                   -> (DeclContext
DCBlockData, forall a. Maybe a
Nothing, []) -- no decls inside of comments, so ignore it

-- | Extract a string map from the given data, leaving behind aliased
-- values in place of strings in the returned version.
extractStringMap :: Data a => a -> (a, StringMap)
extractStringMap :: forall a. Data a => a -> (a, StringMap)
extractStringMap a
x = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall {a}. Map a String -> Map String a
inv forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b c. (a -> b -> c) -> b -> a -> c
flip forall s a. State s a -> s -> (a, s)
runState (forall k a. Map k a
M.empty, Int
0) forall a b. (a -> b) -> a -> b
$ forall from to (m :: * -> *).
(Biplate from to, Applicative m) =>
(to -> m to) -> from -> m from
descendBiM String -> State (StringMap, Int) String
f a
x
  where
    inv :: Map a String -> Map String a
inv = forall k a. Ord k => [(k, a)] -> Map k a
M.fromList forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map (\ (a
a,String
b) -> (String
b,a
a)) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall k a. Map k a -> [(k, a)]
M.toList
    f :: String -> State (StringMap, Int) String
    f :: String -> State (StringMap, Int) String
f String
s = do
      (StringMap
m, Int
n) <- forall s (m :: * -> *). MonadState s m => m s
get
      case forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup String
s StringMap
m of
        Just String
s' -> forall (m :: * -> *) a. Monad m => a -> m a
return String
s'
        Maybe String
Nothing -> do
          let s' :: String
s' = Char
'@'forall a. a -> [a] -> [a]
:forall a. Show a => a -> String
show Int
n
          forall s (m :: * -> *). MonadState s m => s -> m ()
put (forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert String
s String
s' StringMap
m, Int
n forall a. Num a => a -> a -> a
+ Int
1)
          forall (m :: * -> *) a. Monad m => a -> m a
return String
s'

-- | Rewrite the data with the string map aliases replaced by the
-- actual values (implicitly sharing structure).
revertStringMap :: Data a => StringMap -> a -> a
revertStringMap :: forall a. Data a => StringMap -> a -> a
revertStringMap StringMap
sm = forall from to. Biplate from to => (to -> to) -> from -> from
descendBi (\ String
s -> String
s forall a. a -> Maybe a -> a
`fromMaybe` forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup String
s StringMap
sm)

-- | Extract a map of variables assigned to constant values.
extractParamVarMap :: forall a. Data a => F.ProgramFile (FA.Analysis a) -> ParamVarMap
extractParamVarMap :: forall a. Data a => ProgramFile (Analysis a) -> ParamVarMap
extractParamVarMap ProgramFile (Analysis a)
pf = forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [(String, FValue)]
cvm
  where
    pf' :: ProgramFile (Analysis a)
pf' = forall a.
Data a =>
ProgramFile (Analysis a) -> ProgramFile (Analysis a)
FAD.analyseConstExps forall a b. (a -> b) -> a -> b
$ forall a.
Data a =>
ProgramFile (Analysis a) -> ProgramFile (Analysis a)
FAB.analyseBBlocks ProgramFile (Analysis a)
pf
    cvm :: [(String, FValue)]
cvm = [ (forall a. Expression (Analysis a) -> String
FA.varName Expression (Analysis a)
v, FValue
con)
          | F.PUModule Analysis a
_ SrcSpan
_ String
_ [Block (Analysis a)]
bs Maybe [ProgramUnit (Analysis a)]
_                             <- forall from to. Biplate from to => from -> [to]
universeBi ProgramFile (Analysis a)
pf' :: [F.ProgramUnit (FA.Analysis a)]
          , st :: Statement (Analysis a)
st@(F.StDeclaration Analysis a
_ SrcSpan
_ (F.TypeSpec Analysis a
_ SrcSpan
_ BaseType
_ Maybe (Selector (Analysis a))
_) Maybe (AList Attribute (Analysis a))
_ AList Declarator (Analysis a)
_) <- forall from to. Biplate from to => from -> [to]
universeBi [Block (Analysis a)]
bs  :: [F.Statement (FA.Analysis a)]
          , F.AttrParameter Analysis a
_ SrcSpan
_                               <- forall from to. Biplate from to => from -> [to]
universeBi Statement (Analysis a)
st  :: [F.Attribute (FA.Analysis a)]
          , (F.Declarator Analysis a
_ SrcSpan
_ Expression (Analysis a)
v DeclaratorType (Analysis a)
F.ScalarDecl Maybe (Expression (Analysis a))
_ Maybe (Expression (Analysis a))
_)       <- forall from to. Biplate from to => from -> [to]
universeBi Statement (Analysis a)
st  :: [F.Declarator (FA.Analysis a)]
          , Just FValue
con                                          <- [forall a. Analysis a -> Maybe FValue
FA.constExp (forall (f :: * -> *) a. Annotated f => f a -> a
F.getAnnotation Expression (Analysis a)
v)] ] forall a. [a] -> [a] -> [a]
++
          [ (forall a. Expression (Analysis a) -> String
FA.varName Expression (Analysis a)
v, FValue
con)
          | F.PUModule Analysis a
_ SrcSpan
_ String
_ [Block (Analysis a)]
bs Maybe [ProgramUnit (Analysis a)]
_                             <- forall from to. Biplate from to => from -> [to]
universeBi ProgramFile (Analysis a)
pf' :: [F.ProgramUnit (FA.Analysis a)]
          , st :: Statement (Analysis a)
st@F.StParameter {}                               <- forall from to. Biplate from to => from -> [to]
universeBi [Block (Analysis a)]
bs  :: [F.Statement (FA.Analysis a)]
          , (F.Declarator Analysis a
_ SrcSpan
_ Expression (Analysis a)
v DeclaratorType (Analysis a)
F.ScalarDecl Maybe (Expression (Analysis a))
_ Maybe (Expression (Analysis a))
_)       <- forall from to. Biplate from to => from -> [to]
universeBi Statement (Analysis a)
st  :: [F.Declarator (FA.Analysis a)]
          , Just FValue
con                                          <- [forall a. Analysis a -> Maybe FValue
FA.constExp (forall (f :: * -> *) a. Annotated f => f a -> a
F.getAnnotation Expression (Analysis a)
v)] ]

-- | Status of mod-file compared to Fortran file.
data TimestampStatus = NoSuchFile | CompileFile | ModFileExists FilePath

-- | Compare the source file timestamp to the fsmod file timestamp, if
-- it exists.
checkTimestamps :: FilePath -> IO TimestampStatus
checkTimestamps :: String -> IO TimestampStatus
checkTimestamps String
path = do
  Bool
pathExists <- String -> IO Bool
doesFileExist String
path
  Bool
modExists <- String -> IO Bool
doesFileExist forall a b. (a -> b) -> a -> b
$ String
path String -> ShowS
-<.> String
modFileSuffix
  case (Bool
pathExists, Bool
modExists) of
    (Bool
False, Bool
_)    -> forall (f :: * -> *) a. Applicative f => a -> f a
pure TimestampStatus
NoSuchFile
    (Bool
True, Bool
False) -> forall (f :: * -> *) a. Applicative f => a -> f a
pure TimestampStatus
CompileFile
    (Bool
True, Bool
True)  -> do
      let modPath :: String
modPath = String
path String -> ShowS
-<.> String
modFileSuffix
      UTCTime
pathModTime <- String -> IO UTCTime
getModificationTime String
path
      UTCTime
modModTime  <- String -> IO UTCTime
getModificationTime String
modPath
      if UTCTime
pathModTime forall a. Ord a => a -> a -> Bool
< UTCTime
modModTime
        then forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ String -> TimestampStatus
ModFileExists String
modPath
        else forall (f :: * -> *) a. Applicative f => a -> f a
pure TimestampStatus
CompileFile