{-
   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.
-}

{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveDataTypeable #-}

{-|

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
  ( modFileSuffix, ModFile, ModFiles, emptyModFile, emptyModFiles
  , lookupModFileData, getLabelsModFileData, alterModFileData -- , alterModFileDataF
  , genModFile, regenModFile, encodeModFile, decodeModFile
  , StringMap, DeclMap, ParamVarMap, DeclContext(..), extractModuleMap, extractDeclMap
  , moduleFilename, combinedStringMap, combinedDeclMap, combinedModuleMap, combinedTypeEnv, combinedParamVarMap
  , genUniqNameToFilenameMap
  , TimestampStatus(..), checkTimestamps )
where

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 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 System.Directory
import System.FilePath

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

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

-- | 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
Eq DeclContext
-> (DeclContext -> DeclContext -> Ordering)
-> (DeclContext -> DeclContext -> Bool)
-> (DeclContext -> DeclContext -> Bool)
-> (DeclContext -> DeclContext -> Bool)
-> (DeclContext -> DeclContext -> Bool)
-> (DeclContext -> DeclContext -> DeclContext)
-> (DeclContext -> DeclContext -> DeclContext)
-> Ord 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
$cp1Ord :: Eq DeclContext
Ord, DeclContext -> DeclContext -> Bool
(DeclContext -> DeclContext -> Bool)
-> (DeclContext -> DeclContext -> Bool) -> Eq DeclContext
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
(Int -> DeclContext -> ShowS)
-> (DeclContext -> String)
-> ([DeclContext] -> ShowS)
-> Show DeclContext
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
DataType
Constr
Typeable DeclContext
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> DeclContext -> c DeclContext)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c DeclContext)
-> (DeclContext -> Constr)
-> (DeclContext -> DataType)
-> (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))
-> ((forall b. Data b => b -> b) -> DeclContext -> DeclContext)
-> (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 u. (forall d. Data d => d -> u) -> DeclContext -> [u])
-> (forall u.
    Int -> (forall d. Data d => d -> u) -> DeclContext -> u)
-> (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 (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> DeclContext -> m DeclContext)
-> Data DeclContext
DeclContext -> DataType
DeclContext -> Constr
(forall b. Data b => b -> b) -> DeclContext -> DeclContext
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> DeclContext -> c DeclContext
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c 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)
$cDCSubroutine :: Constr
$cDCFunction :: Constr
$cDCModule :: Constr
$cDCBlockData :: Constr
$cDCMain :: Constr
$tDeclContext :: DataType
gmapMo :: (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 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 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 :: Int -> (forall d. Data d => d -> u) -> DeclContext -> u
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> DeclContext -> u
gmapQ :: (forall d. Data d => d -> u) -> DeclContext -> [u]
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> DeclContext -> [u]
gmapQr :: (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 :: (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 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 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 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 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
$cp1Data :: Typeable DeclContext
Data, Typeable, (forall x. DeclContext -> Rep DeclContext x)
-> (forall x. Rep DeclContext x -> DeclContext)
-> Generic DeclContext
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
(ModFile -> ModFile -> Bool)
-> (ModFile -> ModFile -> Bool) -> Eq ModFile
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, Eq ModFile
Eq ModFile
-> (ModFile -> ModFile -> Ordering)
-> (ModFile -> ModFile -> Bool)
-> (ModFile -> ModFile -> Bool)
-> (ModFile -> ModFile -> Bool)
-> (ModFile -> ModFile -> Bool)
-> (ModFile -> ModFile -> ModFile)
-> (ModFile -> ModFile -> ModFile)
-> Ord ModFile
ModFile -> ModFile -> Bool
ModFile -> ModFile -> Ordering
ModFile -> ModFile -> ModFile
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 :: ModFile -> ModFile -> ModFile
$cmin :: ModFile -> ModFile -> ModFile
max :: ModFile -> ModFile -> ModFile
$cmax :: ModFile -> ModFile -> ModFile
>= :: ModFile -> ModFile -> Bool
$c>= :: ModFile -> ModFile -> Bool
> :: ModFile -> ModFile -> Bool
$c> :: ModFile -> ModFile -> Bool
<= :: ModFile -> ModFile -> Bool
$c<= :: ModFile -> ModFile -> Bool
< :: ModFile -> ModFile -> Bool
$c< :: ModFile -> ModFile -> Bool
compare :: ModFile -> ModFile -> Ordering
$ccompare :: ModFile -> ModFile -> Ordering
$cp1Ord :: Eq ModFile
Ord, Int -> ModFile -> ShowS
[ModFile] -> ShowS
ModFile -> String
(Int -> ModFile -> ShowS)
-> (ModFile -> String) -> ([ModFile] -> ShowS) -> Show ModFile
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
DataType
Constr
Typeable ModFile
-> (forall (c :: * -> *).
    (forall d b. Data d => c (d -> b) -> d -> c b)
    -> (forall g. g -> c g) -> ModFile -> c ModFile)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c ModFile)
-> (ModFile -> Constr)
-> (ModFile -> DataType)
-> (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))
-> ((forall b. Data b => b -> b) -> ModFile -> ModFile)
-> (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 u. (forall d. Data d => d -> u) -> ModFile -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> ModFile -> u)
-> (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 (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> ModFile -> m ModFile)
-> Data ModFile
ModFile -> DataType
ModFile -> Constr
(forall b. Data b => b -> b) -> ModFile -> ModFile
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ModFile -> c ModFile
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c 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)
$cModFile :: Constr
$tModFile :: DataType
gmapMo :: (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 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 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 :: Int -> (forall d. Data d => d -> u) -> ModFile -> u
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> ModFile -> u
gmapQ :: (forall d. Data d => d -> u) -> ModFile -> [u]
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> ModFile -> [u]
gmapQr :: (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 :: (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 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 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 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 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
$cp1Data :: Typeable ModFile
Data, Typeable, (forall x. ModFile -> Rep ModFile x)
-> (forall x. Rep ModFile x -> ModFile) -> Generic ModFile
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
"" StringMap
forall k a. Map k a
M.empty ModuleMap
forall k a. Map k a
M.empty DeclMap
forall k a. Map k a
M.empty TypeEnv
forall k a. Map k a
M.empty ParamVarMap
forall k a. Map k a
M.empty Map String ByteString
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 :: ProgramFile (Analysis a) -> ModFile -> ModFile
regenModFile ProgramFile (Analysis a)
pf ModFile
mf = ModFile
mf { mfModuleMap :: ModuleMap
mfModuleMap   = ProgramFile (Analysis a) -> ModuleMap
forall a. Data a => ProgramFile (Analysis a) -> ModuleMap
extractModuleMap ProgramFile (Analysis a)
pf
                        , mfDeclMap :: DeclMap
mfDeclMap     = ProgramFile (Analysis a) -> DeclMap
forall a. Data a => ProgramFile (Analysis a) -> DeclMap
extractDeclMap ProgramFile (Analysis a)
pf
                        , mfTypeEnv :: TypeEnv
mfTypeEnv     = ProgramFile (Analysis a) -> TypeEnv
forall a. Data a => ProgramFile (Analysis a) -> TypeEnv
FAT.extractTypeEnv ProgramFile (Analysis a)
pf
                        , mfParamVarMap :: ParamVarMap
mfParamVarMap = ProgramFile (Analysis a) -> ParamVarMap
forall a. Data a => ProgramFile (Analysis a) -> ParamVarMap
extractParamVarMap ProgramFile (Analysis a)
pf
                        , mfFilename :: String
mfFilename    = ProgramFile (Analysis a) -> String
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 :: ProgramFile (Analysis a) -> ModFile
genModFile = (ProgramFile (Analysis a) -> ModFile -> ModFile)
-> ModFile -> ProgramFile (Analysis a) -> ModFile
forall a b c. (a -> b -> c) -> b -> a -> c
flip ProgramFile (Analysis a) -> ModFile -> ModFile
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 = String -> Map String ByteString -> Maybe ByteString
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup String
k (Map String ByteString -> Maybe ByteString)
-> (ModFile -> Map String ByteString)
-> ModFile
-> Maybe ByteString
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 = Map String ByteString -> [String]
forall k a. Map k a -> [k]
M.keys (Map String ByteString -> [String])
-> (ModFile -> Map String ByteString) -> ModFile -> [String]
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 = (Maybe ByteString -> Maybe ByteString)
-> String -> Map String ByteString -> Map String ByteString
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 (Map String ByteString -> Map String ByteString)
-> (ModFile -> Map String ByteString)
-> ModFile
-> Map String ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ModFile -> Map String ByteString
mfOtherData (ModFile -> Map String ByteString)
-> ModFile -> Map String ByteString
forall a b. (a -> b) -> a -> b
$ ModFile
mf }

-- For when stackage gets containers-0.5.8.1:
-- alterModFileDataF :: Functor f => (Maybe B.ByteString -> f (Maybe B.ByteString)) -> String -> ModFile -> f ModFile
-- alterModFileDataF f k mf = (\ od -> mf { mfOtherData = od }) <$> M.alterF f k (mfOtherData mf)

-- | Convert ModFiles to a strict ByteString for writing to file.
encodeModFile :: [ModFile] -> LB.ByteString
encodeModFile :: [ModFile] -> ByteString
encodeModFile = [ModFile] -> ByteString
forall a. Binary a => a -> ByteString
encode ([ModFile] -> ByteString)
-> ([ModFile] -> [ModFile]) -> [ModFile] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ModFile -> ModFile) -> [ModFile] -> [ModFile]
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) = ModFile -> (ModFile, StringMap)
forall a. Data a => a -> (a, StringMap)
extractStringMap (ModFile
mf { mfStringMap :: StringMap
mfStringMap = StringMap
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 ByteString
-> Either
     (ByteString, ByteOffset, String)
     (ByteString, ByteOffset, [ModFile])
forall a.
Binary a =>
ByteString
-> Either
     (ByteString, ByteOffset, String) (ByteString, ByteOffset, a)
decodeOrFail ByteString
bs of
  Left (ByteString
_, ByteOffset
_, String
s)    -> String -> Either String [ModFile]
forall a b. a -> Either a b
Left String
s
  Right (ByteString
_, ByteOffset
_, [ModFile]
mfs) -> [ModFile] -> Either String [ModFile]
forall a b. b -> Either a b
Right ((ModFile -> ModFile) -> [ModFile] -> [ModFile]
forall a b. (a -> b) -> [a] -> [b]
map ModFile -> ModFile
each [ModFile]
mfs)
    where
      each :: ModFile -> ModFile
each ModFile
mf = (StringMap -> ModFile -> ModFile
forall a. Data a => StringMap -> a -> a
revertStringMap StringMap
sm ModFile
mf { mfStringMap :: StringMap
mfStringMap = StringMap
forall k a. Map k a
M.empty }) { mfStringMap :: StringMap
mfStringMap = StringMap
sm }
        where sm :: StringMap
sm = ModFile -> StringMap
mfStringMap ModFile
mf

-- | 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 = [ModuleMap] -> ModuleMap
forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
M.unions ([ModuleMap] -> ModuleMap)
-> ([ModFile] -> [ModuleMap]) -> [ModFile] -> ModuleMap
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ModFile -> ModuleMap) -> [ModFile] -> [ModuleMap]
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 = [TypeEnv] -> TypeEnv
forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
M.unions ([TypeEnv] -> TypeEnv)
-> ([ModFile] -> [TypeEnv]) -> [ModFile] -> TypeEnv
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ModFile -> TypeEnv) -> [ModFile] -> [TypeEnv]
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 = [DeclMap] -> DeclMap
forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
M.unions ([DeclMap] -> DeclMap)
-> ([ModFile] -> [DeclMap]) -> [ModFile] -> DeclMap
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ModFile -> DeclMap) -> [ModFile] -> [DeclMap]
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 = [StringMap] -> StringMap
forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
M.unions ([StringMap] -> StringMap)
-> ([ModFile] -> [StringMap]) -> [ModFile] -> StringMap
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ModFile -> StringMap) -> [ModFile] -> [StringMap]
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 = [ParamVarMap] -> ParamVarMap
forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
M.unions ([ParamVarMap] -> ParamVarMap)
-> ([ModFile] -> [ParamVarMap]) -> [ModFile] -> ParamVarMap
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ModFile -> ParamVarMap) -> [ModFile] -> [ParamVarMap]
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 = [StringMap] -> StringMap
forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
M.unions ([StringMap] -> StringMap)
-> ([ModFile] -> [StringMap]) -> [ModFile] -> StringMap
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ModFile -> StringMap) -> [ModFile] -> [StringMap]
forall a b. (a -> b) -> [a] -> [b]
map ModFile -> StringMap
perMF
  where
    perMF :: ModFile -> StringMap
perMF ModFile
mf = [(String, String)] -> StringMap
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [ (String
n, String
fname) | ModEnv
modEnv <- ModuleMap -> [ModEnv]
forall k a. Map k a -> [a]
M.elems (ModFile -> ModuleMap
mfModuleMap ModFile
mf)
                                       , (String
n, NameType
_) <- ModEnv -> [(String, NameType)]
forall k a. Map k a -> [a]
M.elems ModEnv
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 :: ProgramFile (Analysis a) -> ModuleMap
extractModuleMap ProgramFile (Analysis a)
pf
  -- in case there are no modules, store global program unit names under the name 'NamelessMain'
  | [(ProgramUnitName, ModEnv)] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(ProgramUnitName, ModEnv)]
mmap = ProgramUnitName -> ModEnv -> ModuleMap
forall k a. k -> a -> Map k a
M.singleton ProgramUnitName
F.NamelessMain (ModEnv -> ModuleMap) -> ModEnv -> ModuleMap
forall a b. (a -> b) -> a -> b
$ [ModEnv] -> ModEnv
forall (f :: * -> *) k a.
(Foldable f, Ord k) =>
f (Map k a) -> Map k a
M.unions [ModEnv]
combinedEnv
  | Bool
otherwise = [(ProgramUnitName, ModEnv)] -> ModuleMap
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [(ProgramUnitName, ModEnv)]
mmap
  where
    mmap :: [(ProgramUnitName, ModEnv)]
mmap = [ (ProgramUnitName
n, ModEnv
env) | pu :: ProgramUnit (Analysis a)
pu@F.PUModule{} <- ProgramFile (Analysis a) -> [ProgramUnit (Analysis a)]
forall from to. Biplate from to => from -> [to]
childrenBi ProgramFile (Analysis a)
pf :: [F.ProgramUnit (FA.Analysis a)]
                      , let a :: Analysis a
a = ProgramUnit (Analysis a) -> Analysis a
forall (f :: * -> *) a. Annotated f => f a -> a
F.getAnnotation ProgramUnit (Analysis a)
pu
                      , let n :: ProgramUnitName
n = ProgramUnit (Analysis a) -> ProgramUnitName
forall a. Named a => a -> ProgramUnitName
F.getName ProgramUnit (Analysis a)
pu
                      , ModEnv
env <- Maybe ModEnv -> [ModEnv]
forall a. Maybe a -> [a]
maybeToList (Analysis a -> Maybe ModEnv
forall a. Analysis a -> Maybe ModEnv
FA.moduleEnv Analysis a
a) ]
    combinedEnv :: [ModEnv]
combinedEnv = [ ModEnv
env | ProgramUnit (Analysis a)
pu <- ProgramFile (Analysis a) -> [ProgramUnit (Analysis a)]
forall from to. Biplate from to => from -> [to]
childrenBi ProgramFile (Analysis a)
pf :: [F.ProgramUnit (FA.Analysis a)]
                        , let a :: Analysis a
a = ProgramUnit (Analysis a) -> Analysis a
forall (f :: * -> *) a. Annotated f => f a -> a
F.getAnnotation ProgramUnit (Analysis a)
pu
                        , ModEnv
env <- Maybe ModEnv -> [ModEnv]
forall a. Maybe a -> [a]
maybeToList (Analysis a -> Maybe ModEnv
forall a. Analysis a -> Maybe ModEnv
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 :: ProgramFile (Analysis a) -> DeclMap
extractDeclMap ProgramFile (Analysis a)
pf = [(String, (DeclContext, SrcSpan))] -> DeclMap
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList ([(String, (DeclContext, SrcSpan))] -> DeclMap)
-> ([ProgramUnit (Analysis a)]
    -> [(String, (DeclContext, SrcSpan))])
-> [ProgramUnit (Analysis a)]
-> DeclMap
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ProgramUnit (Analysis a) -> [(String, (DeclContext, SrcSpan))])
-> [ProgramUnit (Analysis a)] -> [(String, (DeclContext, SrcSpan))]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap ((DeclContext, Maybe (String, SrcSpan), [Block (Analysis a)])
-> [(String, (DeclContext, SrcSpan))]
blockDecls ((DeclContext, Maybe (String, SrcSpan), [Block (Analysis a)])
 -> [(String, (DeclContext, SrcSpan))])
-> (ProgramUnit (Analysis a)
    -> (DeclContext, Maybe (String, SrcSpan), [Block (Analysis a)]))
-> ProgramUnit (Analysis a)
-> [(String, (DeclContext, SrcSpan))]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgramUnit (Analysis a)
-> (DeclContext, Maybe (String, SrcSpan), [Block (Analysis a)])
nameAndBlocks) ([ProgramUnit (Analysis a)] -> DeclMap)
-> [ProgramUnit (Analysis a)] -> DeclMap
forall a b. (a -> b) -> a -> b
$ ProgramFile (Analysis a) -> [ProgramUnit (Analysis a)]
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 = (Declarator (Analysis a) -> (String, (DeclContext, SrcSpan)))
-> [Declarator (Analysis a)] -> [(String, (DeclContext, SrcSpan))]
forall a b. (a -> b) -> [a] -> [b]
map Declarator (Analysis a) -> (String, (DeclContext, SrcSpan))
decls ([Block (Analysis a)] -> [Declarator (Analysis a)]
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))(String, (DeclContext, SrcSpan))
-> [(String, (DeclContext, SrcSpan))]
-> [(String, (DeclContext, SrcSpan))]
forall a. a -> [a] -> [a]
:(Declarator (Analysis a) -> (String, (DeclContext, SrcSpan)))
-> [Declarator (Analysis a)] -> [(String, (DeclContext, SrcSpan))]
forall a b. (a -> b) -> [a] -> [b]
map Declarator (Analysis a) -> (String, (DeclContext, SrcSpan))
decls ([Block (Analysis a)] -> [Declarator (Analysis a)]
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.DeclVariable Analysis a
_ SrcSpan
_ Expression (Analysis a)
e Maybe (Expression (Analysis a))
_ Maybe (Expression (Analysis a))
_) = (Expression (Analysis a) -> String
forall a. Expression (Analysis a) -> String
FA.varName Expression (Analysis a)
e, Expression (Analysis a) -> SrcSpan
forall a. Spanned a => a -> SrcSpan
P.getSpan Expression (Analysis a)
e)
    declVarName (F.DeclArray Analysis a
_ SrcSpan
_ Expression (Analysis a)
e AList DimensionDeclarator (Analysis a)
_ Maybe (Expression (Analysis a))
_ Maybe (Expression (Analysis a))
_)  = (Expression (Analysis a) -> String
forall a. Expression (Analysis a) -> String
FA.varName Expression (Analysis a)
e, Expression (Analysis a) -> SrcSpan
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, Maybe (String, SrcSpan)
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 (ProgramUnitName -> DeclContext) -> ProgramUnitName -> DeclContext
forall a b. (a -> b) -> a -> b
$ ProgramUnit (Analysis a) -> ProgramUnitName
forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puName ProgramUnit (Analysis a)
pu, Maybe (String, SrcSpan)
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 (ProgramUnit (Analysis a) -> ProgramUnitName
forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puName ProgramUnit (Analysis a)
pu, ProgramUnit (Analysis a) -> ProgramUnitName
forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puSrcName ProgramUnit (Analysis a)
pu), Maybe (String, SrcSpan)
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 <- ProgramUnit (Analysis a) -> ProgramUnitName
forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puName ProgramUnit (Analysis a)
pu       -> ((ProgramUnitName, ProgramUnitName) -> DeclContext
DCFunction (ProgramUnit (Analysis a) -> ProgramUnitName
forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puName ProgramUnit (Analysis a)
pu, ProgramUnit (Analysis a) -> ProgramUnitName
forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puSrcName ProgramUnit (Analysis a)
pu), (String, SrcSpan) -> Maybe (String, SrcSpan)
forall a. a -> Maybe a
Just (String
n, ProgramUnit (Analysis a) -> SrcSpan
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 (ProgramUnit (Analysis a) -> ProgramUnitName
forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puName ProgramUnit (Analysis a)
pu, ProgramUnit (Analysis a) -> ProgramUnitName
forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puSrcName ProgramUnit (Analysis a)
pu), (String, SrcSpan) -> Maybe (String, SrcSpan)
forall a. a -> Maybe a
Just (Expression (Analysis a) -> String
forall a. Expression (Analysis a) -> String
FA.varName Expression (Analysis a)
ret, Expression (Analysis a) -> SrcSpan
forall a. Spanned a => a -> SrcSpan
P.getSpan Expression (Analysis a)
ret), [Block (Analysis a)]
b)
        | Bool
otherwise                       -> String
-> (DeclContext, Maybe (String, SrcSpan), [Block (Analysis a)])
forall a. HasCallStack => String -> a
error (String
 -> (DeclContext, Maybe (String, SrcSpan), [Block (Analysis a)]))
-> String
-> (DeclContext, Maybe (String, SrcSpan), [Block (Analysis a)])
forall a b. (a -> b) -> a -> b
$ String
"nameAndBlocks: un-named function with no return value! " String -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgramUnitName -> String
forall a. Show a => a -> String
show (ProgramUnit (Analysis a) -> ProgramUnitName
forall a. ProgramUnit (Analysis a) -> ProgramUnitName
FA.puName ProgramUnit (Analysis a)
pu) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" at source-span " String -> ShowS
forall a. [a] -> [a] -> [a]
++ SrcSpan -> String
forall a. Show a => a -> String
show (ProgramUnit (Analysis a) -> SrcSpan
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, Maybe (String, SrcSpan)
forall a. Maybe a
Nothing, [Block (Analysis a)]
b)
      F.PUComment    {}                   -> (DeclContext
DCBlockData, Maybe (String, SrcSpan)
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 :: a -> (a, StringMap)
extractStringMap a
x = ((StringMap, Int) -> StringMap)
-> (a, (StringMap, Int)) -> (a, StringMap)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (StringMap -> StringMap
forall a. Map a String -> Map String a
inv (StringMap -> StringMap)
-> ((StringMap, Int) -> StringMap) -> (StringMap, Int) -> StringMap
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (StringMap, Int) -> StringMap
forall a b. (a, b) -> a
fst) ((a, (StringMap, Int)) -> (a, StringMap))
-> (State (StringMap, Int) a -> (a, (StringMap, Int)))
-> State (StringMap, Int) a
-> (a, StringMap)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (State (StringMap, Int) a
 -> (StringMap, Int) -> (a, (StringMap, Int)))
-> (StringMap, Int)
-> State (StringMap, Int) a
-> (a, (StringMap, Int))
forall a b c. (a -> b -> c) -> b -> a -> c
flip State (StringMap, Int) a
-> (StringMap, Int) -> (a, (StringMap, Int))
forall s a. State s a -> s -> (a, s)
runState (StringMap
forall k a. Map k a
M.empty, Int
0) (State (StringMap, Int) a -> (a, StringMap))
-> State (StringMap, Int) a -> (a, StringMap)
forall a b. (a -> b) -> a -> b
$ (String -> StateT (StringMap, Int) Identity String)
-> a -> State (StringMap, Int) a
forall from to (m :: * -> *).
(Biplate from to, Applicative m) =>
(to -> m to) -> from -> m from
descendBiM String -> StateT (StringMap, Int) Identity String
f a
x
  where
    inv :: Map a String -> Map String a
inv = [(String, a)] -> Map String a
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList ([(String, a)] -> Map String a)
-> (Map a String -> [(String, a)]) -> Map a String -> Map String a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((a, String) -> (String, a)) -> [(a, String)] -> [(String, a)]
forall a b. (a -> b) -> [a] -> [b]
map (\ (a
a,String
b) -> (String
b,a
a)) ([(a, String)] -> [(String, a)])
-> (Map a String -> [(a, String)]) -> Map a String -> [(String, a)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map a String -> [(a, String)]
forall k a. Map k a -> [(k, a)]
M.toList
    f :: String -> State (StringMap, Int) String
    f :: String -> StateT (StringMap, Int) Identity String
f String
s = do
      (StringMap
m, Int
n) <- StateT (StringMap, Int) Identity (StringMap, Int)
forall s (m :: * -> *). MonadState s m => m s
get
      case String -> StringMap -> Maybe String
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup String
s StringMap
m of
        Just String
s' -> String -> StateT (StringMap, Int) Identity String
forall (m :: * -> *) a. Monad m => a -> m a
return String
s'
        Maybe String
Nothing -> do
          let s' :: String
s' = Char
'@'Char -> ShowS
forall a. a -> [a] -> [a]
:Int -> String
forall a. Show a => a -> String
show Int
n
          (StringMap, Int) -> StateT (StringMap, Int) Identity ()
forall s (m :: * -> *). MonadState s m => s -> m ()
put (String -> String -> StringMap -> StringMap
forall k a. Ord k => k -> a -> Map k a -> Map k a
M.insert String
s String
s' StringMap
m, Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1)
          String -> StateT (StringMap, Int) Identity String
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 :: StringMap -> a -> a
revertStringMap StringMap
sm = ShowS -> a -> a
forall from to. Biplate from to => (to -> to) -> from -> from
descendBi (\ String
s -> String
s String -> Maybe String -> String
forall a. a -> Maybe a -> a
`fromMaybe` String -> StringMap -> Maybe String
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 :: ProgramFile (Analysis a) -> ParamVarMap
extractParamVarMap ProgramFile (Analysis a)
pf = [(String, Constant)] -> ParamVarMap
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList [(String, Constant)]
cvm
  where
    pf' :: ProgramFile (Analysis a)
pf' = ProgramFile (Analysis a) -> ProgramFile (Analysis a)
forall a.
Data a =>
ProgramFile (Analysis a) -> ProgramFile (Analysis a)
FAD.analyseConstExps (ProgramFile (Analysis a) -> ProgramFile (Analysis a))
-> ProgramFile (Analysis a) -> ProgramFile (Analysis a)
forall a b. (a -> b) -> a -> b
$ ProgramFile (Analysis a) -> ProgramFile (Analysis a)
forall a.
Data a =>
ProgramFile (Analysis a) -> ProgramFile (Analysis a)
FAB.analyseBBlocks ProgramFile (Analysis a)
pf
    cvm :: [(String, Constant)]
cvm = [ (Expression (Analysis a) -> String
forall a. Expression (Analysis a) -> String
FA.varName Expression (Analysis a)
v, Constant
con)
          | F.PUModule Analysis a
_ SrcSpan
_ String
_ [Block (Analysis a)]
bs Maybe [ProgramUnit (Analysis a)]
_                             <- ProgramFile (Analysis a) -> [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)
_) <- [Block (Analysis a)] -> [Statement (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
_                               <- Statement (Analysis a) -> [Attribute (Analysis a)]
forall from to. Biplate from to => from -> [to]
universeBi Statement (Analysis a)
st  :: [F.Attribute (FA.Analysis a)]
          , (F.DeclVariable Analysis a
_ SrcSpan
_ Expression (Analysis a)
v Maybe (Expression (Analysis a))
_ Maybe (Expression (Analysis a))
_)                        <- Statement (Analysis a) -> [Declarator (Analysis a)]
forall from to. Biplate from to => from -> [to]
universeBi Statement (Analysis a)
st  :: [F.Declarator (FA.Analysis a)]
          , Just Constant
con                                          <- [Analysis a -> Maybe Constant
forall a. Analysis a -> Maybe Constant
FA.constExp (Expression (Analysis a) -> Analysis a
forall (f :: * -> *) a. Annotated f => f a -> a
F.getAnnotation Expression (Analysis a)
v)] ] [(String, Constant)]
-> [(String, Constant)] -> [(String, Constant)]
forall a. [a] -> [a] -> [a]
++
          [ (Expression (Analysis a) -> String
forall a. Expression (Analysis a) -> String
FA.varName Expression (Analysis a)
v, Constant
con)
          | F.PUModule Analysis a
_ SrcSpan
_ String
_ [Block (Analysis a)]
bs Maybe [ProgramUnit (Analysis a)]
_                             <- ProgramFile (Analysis a) -> [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 {}                               <- [Block (Analysis a)] -> [Statement (Analysis a)]
forall from to. Biplate from to => from -> [to]
universeBi [Block (Analysis a)]
bs  :: [F.Statement (FA.Analysis a)]
          , (F.DeclVariable Analysis a
_ SrcSpan
_ Expression (Analysis a)
v Maybe (Expression (Analysis a))
_ Maybe (Expression (Analysis a))
_)                        <- Statement (Analysis a) -> [Declarator (Analysis a)]
forall from to. Biplate from to => from -> [to]
universeBi Statement (Analysis a)
st  :: [F.Declarator (FA.Analysis a)]
          , Just Constant
con                                          <- [Analysis a -> Maybe Constant
forall a. Analysis a -> Maybe Constant
FA.constExp (Expression (Analysis a) -> Analysis a
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 (String -> IO Bool) -> String -> IO Bool
forall a b. (a -> b) -> a -> b
$ String
path String -> ShowS
-<.> String
modFileSuffix
  case (Bool
pathExists, Bool
modExists) of
    (Bool
False, Bool
_)    -> TimestampStatus -> IO TimestampStatus
forall (f :: * -> *) a. Applicative f => a -> f a
pure TimestampStatus
NoSuchFile
    (Bool
True, Bool
False) -> TimestampStatus -> IO TimestampStatus
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 UTCTime -> UTCTime -> Bool
forall a. Ord a => a -> a -> Bool
< UTCTime
modModTime
        then TimestampStatus -> IO TimestampStatus
forall (f :: * -> *) a. Applicative f => a -> f a
pure (TimestampStatus -> IO TimestampStatus)
-> TimestampStatus -> IO TimestampStatus
forall a b. (a -> b) -> a -> b
$ String -> TimestampStatus
ModFileExists String
modPath
        else TimestampStatus -> IO TimestampStatus
forall (f :: * -> *) a. Applicative f => a -> f a
pure TimestampStatus
CompileFile